[yt-svn] commit/yt: 2 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Thu Jun 18 07:51:15 PDT 2015


2 new commits in yt:

https://bitbucket.org/yt_analysis/yt/commits/76052ef99b8e/
Changeset:   76052ef99b8e
Branch:      yt
User:        jzuhone
Date:        2015-06-18 13:46:17+00:00
Summary:     Be less restrictive about what fits files to read--this allows the reading of images without any coordinate information
Affected #:  1 file

diff -r 761246ef25f204cbc8fa1ed8f790ecdf09dfeba9 -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -159,7 +159,7 @@
             naxis4 = 1
         for i, fits_file in enumerate(self.dataset._handle._fits_files):
             for j, hdu in enumerate(fits_file):
-                if isinstance(hdu, _astropy.pyfits.BinTableHDU):
+                if isinstance(hdu, _astropy.pyfits.BinTableHDU) or hdu.header["naxis"] == 0:
                     continue
                 if self._ensure_same_dims(hdu):
                     units = self._determine_image_units(hdu.header, known_units)
@@ -386,14 +386,17 @@
                          (self.events_info["y"][1]-self.events_info["y"][0])/self.reblock]
         else:
             self.events_data = False
-            self.first_image = 0
+            # Sometimes the primary hdu doesn't have an image
+            if len(self._handle) > 1 and self._handle[0].header["naxis"] == 0:
+                self.first_image = 1
+            else:
+                self.first_image = 0
             self.primary_header = self._handle[self.first_image].header
             self.naxis = self.primary_header["naxis"]
-            self.axis_names = [self.primary_header["ctype%d" % (i+1)]
+            self.axis_names = [self.primary_header.get("ctype%d" % (i+1),"LINEAR")
                                for i in range(self.naxis)]
             self.dims = [self.primary_header["naxis%d" % (i+1)]
                          for i in range(self.naxis)]
-
             wcs = _astropy.pywcs.WCS(header=self.primary_header)
             if self.naxis == 4:
                 self.wcs = _astropy.pywcs.WCS(naxis=3)
@@ -515,12 +518,20 @@
 
         # Check to see if this data is in some kind of (Lat,Lon,Vel) format
         self.spec_cube = False
+        self.wcs_2d = None
         x = 0
         for p in lon_prefixes+lat_prefixes+list(spec_names.keys()):
             y = np_char.startswith(self.axis_names[:self.dimensionality], p)
             x += np.any(y)
-        if x == self.dimensionality and self.axis_names != ['LINEAR','LINEAR']: 
-            self._setup_spec_cube()
+        if x == self.dimensionality:
+            if self.axis_names == ['LINEAR','LINEAR']:
+                self.wcs_2d = self.wcs
+                self.lat_axis = 1
+                self.lon_axis = 0
+                self.lat_name = "Y"
+                self.lon_name = "X"
+            else:
+                self._setup_spec_cube()
 
     def _setup_spec_cube(self):
 
@@ -587,7 +598,7 @@
                                                      self.spectral_factor*Dz
             self._dz /= self.spectral_factor
             self._p0 = (self._p0-0.5)*self.spectral_factor + 0.5
-            
+
         else:
 
             self.wcs_2d = self.wcs
@@ -620,8 +631,8 @@
                 warnings.filterwarnings('ignore', category=UserWarning, append=True)
                 fileh = _astropy.pyfits.open(args[0])
             valid = fileh[0].header["naxis"] >= 2
-            if len(fileh) > 1 and fileh[1].name == "EVENTS":
-                valid = fileh[1].header["naxis"] >= 2
+            if len(fileh) > 1:
+                valid = fileh[1].header["naxis"] >= 2 or valid
             fileh.close()
             return valid
         except:


https://bitbucket.org/yt_analysis/yt/commits/dc2467c4eae7/
Changeset:   dc2467c4eae7
Branch:      yt
User:        jzuhone
Date:        2015-06-18 13:46:52+00:00
Summary:     Merge
Affected #:  27 files

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 doc/helper_scripts/run_recipes.py
--- a/doc/helper_scripts/run_recipes.py
+++ b/doc/helper_scripts/run_recipes.py
@@ -13,7 +13,7 @@
 from yt.config import ytcfg
 
 FPATTERNS = ['*.png', '*.txt', '*.h5', '*.dat']
-DPATTERNS = ['LC*', 'LR', 'DD0046', 'halo_analysis']
+DPATTERNS = ['LC*', 'LR', 'DD0046']
 BADF = ['cloudy_emissivity.h5', 'apec_emissivity.h5',
         'xray_emissivity.h5', 'AMRGridData_Slice_x_density.png']
 CWD = os.getcwd()

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 doc/source/visualizing/FITSImageBuffer.ipynb
--- a/doc/source/visualizing/FITSImageBuffer.ipynb
+++ /dev/null
@@ -1,205 +0,0 @@
-{
- "metadata": {
-  "name": "",
-  "signature": "sha256:872f7525edd3c1ee09c67f6ecdd8552218df05ebe5ab73bcab55654edf0ac2bb"
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
-  {
-   "cells": [
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "yt has capabilities for writing 2D and 3D uniformly gridded data generated from datasets to FITS files. This is via the `FITSImageBuffer` class, which has subclasses `FITSSlice` and `FITSProjection` to write slices and projections directly to FITS. We'll test this out on an Athena dataset."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "%matplotlib inline\n",
-      "import yt\n",
-      "from yt.utilities.fits_image import FITSImageBuffer, FITSSlice, FITSProjection"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "ds = yt.load(\"MHDSloshing/virgo_low_res.0054.vtk\", parameters={\"length_unit\":(1.0,\"Mpc\"),\n",
-      "                                                               \"mass_unit\":(1.0e14,\"Msun\"),\n",
-      "                                                               \"time_unit\":(1.0,\"Myr\")})"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "To demonstrate a useful example of creating a FITS file, let's first make a `ProjectionPlot`:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "prj = yt.ProjectionPlot(ds, \"z\", [\"temperature\"], weight_field=\"density\", width=(500.,\"kpc\"))\n",
-      "prj.show()"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "Suppose that we wanted to write this projection to a FITS file for analysis and visualization in other programs, such as ds9. We can do that using `FITSProjection`:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "prj_fits = FITSProjection(ds, \"z\", [\"temperature\"], weight_field=\"density\")"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "which took the same parameters as `ProjectionPlot` except the width, because `FITSProjection` and `FITSSlice` always make slices and projections of the width of the domain size, at the finest resolution available in the simulation, in a unit determined to be appropriate for the physical size of the dataset. `prj_fits` is a full-fledged FITS file in memory, specifically an [AstroPy `HDUList`](http://astropy.readthedocs.org/en/latest/io/fits/api/hdulists.html) object. This means that we can use all of the methods inherited from `HDUList`:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "prj_fits.info()"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "`info` shows us the contents of the virtual FITS file. We can also look at the header for the `\"temperature\"` image, like so:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "prj_fits[\"temperature\"].header"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "where we can see that the temperature units are in Kelvin and the cell widths are in kiloparsecs. The projection can be written to disk using the `writeto` method:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "prj_fits.writeto(\"sloshing.fits\", clobber=True)"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "Since yt can read FITS image files, it can be loaded up just like any other dataset:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "ds2 = yt.load(\"sloshing.fits\")"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "and we can make a `SlicePlot` of the 2D image, which shows the same data as the previous image:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "slc2 = yt.SlicePlot(ds2, \"z\", [\"temperature\"], width=(500.,\"kpc\"))\n",
-      "slc2.set_log(\"temperature\", True)\n",
-      "slc2.show()"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "If you want more fine-grained control over what goes into the FITS file, you can call `FITSImageBuffer` directly, with various kinds of inputs. For example, you could use a `FixedResolutionBuffer`, and specify you want the units in parsecs instead:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "slc3 = ds.slice(0, 0.0)\n",
-      "frb = slc3.to_frb((500.,\"kpc\"), 800)\n",
-      "fib = FITSImageBuffer(frb, fields=[\"density\",\"temperature\"], units=\"pc\")"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "Finally, a 3D FITS cube can be created from a covering grid:"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "cvg = ds.covering_grid(ds.index.max_level, [-0.5,-0.5,-0.5], [64, 64, 64], fields=[\"density\",\"temperature\"])\n",
-      "fib = FITSImageBuffer(cvg, fields=[\"density\",\"temperature\"], units=\"Mpc\")"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
-    }
-   ],
-   "metadata": {}
-  }
- ]
-}
\ No newline at end of file

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 doc/source/visualizing/FITSImageData.ipynb
--- /dev/null
+++ b/doc/source/visualizing/FITSImageData.ipynb
@@ -0,0 +1,409 @@
+{
+ "metadata": {
+  "name": "",
+  "signature": "sha256:c7de5ef190feaa2289595aec7eaa05db02fd535e408e0d04aa54088b0bd3ebae"
+ },
+ "nbformat": 3,
+ "nbformat_minor": 0,
+ "worksheets": [
+  {
+   "cells": [
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "yt has capabilities for writing 2D and 3D uniformly gridded data generated from datasets to FITS files. This is via the `FITSImageData` class. We'll test these capabilities out on an Athena dataset."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "import yt\n",
+      "from yt.utilities.fits_image import FITSImageData, FITSProjection"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "ds = yt.load(\"MHDSloshing/virgo_low_res.0054.vtk\", parameters={\"length_unit\":(1.0,\"Mpc\"),\n",
+      "                                                               \"mass_unit\":(1.0e14,\"Msun\"),\n",
+      "                                                               \"time_unit\":(1.0,\"Myr\")})"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "heading",
+     "level": 2,
+     "metadata": {},
+     "source": [
+      "Creating FITS images from Slices and Projections"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "There are several ways to make a `FITSImageData` instance. The most intuitive ways are to use the `FITSSlice`, `FITSProjection`, `FITSOffAxisSlice`, and `FITSOffAxisProjection` classes to write slices and projections directly to FITS. To demonstrate a useful example of creating a FITS file, let's first make a `ProjectionPlot`:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj = yt.ProjectionPlot(ds, \"z\", [\"temperature\"], weight_field=\"density\", width=(500.,\"kpc\"))\n",
+      "prj.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Suppose that we wanted to write this projection to a FITS file for analysis and visualization in other programs, such as ds9. We can do that using `FITSProjection`:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits = FITSProjection(ds, \"z\", [\"temperature\"], weight_field=\"density\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "which took the same parameters as `ProjectionPlot` except the width, because `FITSProjection` and `FITSSlice` always make slices and projections of the width of the domain size, at the finest resolution available in the simulation, in a unit determined to be appropriate for the physical size of the dataset."
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Because `FITSImageData` inherits from the [AstroPy `HDUList`](http://astropy.readthedocs.org/en/latest/io/fits/api/hdulists.html) class, we can call its methods. For example, `info` shows us the contents of the virtual FITS file:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits.info()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "We can also look at the header for a particular field:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits[\"temperature\"].header"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "where we can see that the temperature units are in Kelvin and the cell widths are in kiloparsecs. If we want the raw image data with units, we can call `get_data`:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits.get_data(\"temperature\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "We can use the `set_unit` method to change the units of a particular field:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits.set_unit(\"temperature\",\"R\")\n",
+      "prj_fits.get_data(\"temperature\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "The image can be written to disk using the `writeto` method:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits.writeto(\"sloshing.fits\", clobber=True)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Since yt can read FITS image files, it can be loaded up just like any other dataset:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "ds2 = yt.load(\"sloshing.fits\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "and we can make a `SlicePlot` of the 2D image, which shows the same data as the previous image:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "slc2 = yt.SlicePlot(ds2, \"z\", [\"temperature\"], width=(500.,\"kpc\"))\n",
+      "slc2.set_log(\"temperature\", True)\n",
+      "slc2.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "heading",
+     "level": 2,
+     "metadata": {},
+     "source": [
+      "Using `FITSImageData` directly"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "If you want more fine-grained control over what goes into the FITS file, you can call `FITSImageData` directly, with various kinds of inputs. For example, you could use a `FixedResolutionBuffer`, and specify you want the units in parsecs instead:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "slc3 = ds.slice(0, 0.0)\n",
+      "frb = slc3.to_frb((500.,\"kpc\"), 800)\n",
+      "fid_frb = FITSImageData(frb, fields=[\"density\",\"temperature\"], units=\"pc\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "A 3D FITS cube can also be created from a covering grid:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "cvg = ds.covering_grid(ds.index.max_level, [-0.5,-0.5,-0.5], [64, 64, 64], fields=[\"density\",\"temperature\"])\n",
+      "fid_cvg = FITSImageData(cvg, fields=[\"density\",\"temperature\"], units=\"Mpc\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "heading",
+     "level": 2,
+     "metadata": {},
+     "source": [
+      "Other `FITSImageData` Methods"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "A `FITSImageData` instance can be generated from one previously written to disk using the `from_file` classmethod:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "fid = FITSImageData.from_file(\"sloshing.fits\")\n",
+      "fid.info()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Multiple `FITSImageData` can be combined to create a new one, provided that the coordinate information is the same:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits2 = FITSProjection(ds, \"z\", [\"density\"])\n",
+      "prj_fits3 = FITSImageData.from_images([prj_fits, prj_fits2])\n",
+      "prj_fits3.info()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Alternatively, individual fields can be popped as well:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "dens_fits = prj_fits3.pop(\"density\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "dens_fits.info()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits3.info()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "So far, the FITS images we have shown have linear spatial coordinates. One may want to take a projection of an object and make a crude mock observation out of it, with celestial coordinates. For this, we can use the `create_sky_wcs` method. Specify a center (RA, Dec) coordinate in degrees, as well as a linear scale in terms of angle per distance:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "sky_center = [30.,45.] # in degrees\n",
+      "sky_scale = (2.5, \"arcsec/kpc\") # could also use a YTQuantity\n",
+      "prj_fits.create_sky_wcs(sky_center, sky_scale, ctype=[\"RA---TAN\",\"DEC--TAN\"])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "By the default, a tangent RA/Dec projection is used, but one could also use another projection using the `ctype` keyword. We can now look at the header and see it has the appropriate WCS:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj_fits[\"temperature\"].header"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Finally, we can add header keywords to a single field or for all fields in the FITS image using `update_header`:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "fid_frb.update_header(\"all\", \"time\", 0.1) # Update all the fields\n",
+      "fid_frb.update_header(\"temperature\", \"scale\", \"Rankine\") # Update just one field"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print fid_frb[\"density\"].header[\"time\"]\n",
+      "print fid_frb[\"temperature\"].header[\"scale\"]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    }
+   ],
+   "metadata": {}
+  }
+ ]
+}
\ No newline at end of file

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 doc/source/visualizing/manual_plotting.rst
--- a/doc/source/visualizing/manual_plotting.rst
+++ b/doc/source/visualizing/manual_plotting.rst
@@ -66,6 +66,57 @@
 setting up multiple axes with colorbars easier than it would be using only
 matplotlib can be found in the :ref:`advanced-multi-panel` cookbook recipe.
 
+.. _frb-filters:
+
+Fixed Resolution Buffer Filters
+-------------------------------
+
+The FRB can be modified by using set of predefined filters in order to e.g.
+create realistically looking, mock observation images out of simulation data.
+Applying filter is an irreversible operation, hence the order in which you are
+using them matters.
+
+.. python-script::
+
+   import matplotlib
+   matplotlib.use('Agg')
+   from matplotlib import pyplot as plt
+
+   import yt
+
+   ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+   slc = ds.slice('z', 0.5)
+   frb = slc.to_frb((20, 'kpc'), 512)
+   frb.apply_gauss_beam(nbeam=30, sigma=2.0)
+   frb.apply_white_noise(5e-23)
+   plt.imshow(frb['density'].d)
+   plt.savefig('frb_filters.png')
+
+Currently available filters:
+
+Gaussian Smoothing
+~~~~~~~~~~~~~~~~~~
+
+.. function:: apply_gauss_beam(self, nbeam=30, sigma=2.0)
+
+   (This is a proxy for
+   :class:`~yt.visualization.fixed_resolution_filters.FixedResolutionBufferGaussBeamFilter`.)
+
+    This filter convolves the FRB with 2d Gaussian that is "nbeam" pixel wide
+    and has standard deviation "sigma".
+
+White Noise
+~~~~~~~~~~~
+
+.. function:: apply_white_noise(self, bg_lvl=None)
+
+   (This is a proxy for
+   :class:`~yt.visualization.fixed_resolution_filters.FixedResolutionBufferWhiteNoiseFilter`.)
+
+    This filter adds white noise with the amplitude "bg_lvl" to the FRB.
+    If "bg_lvl" is not present, 10th percentile of the FRB's values is used
+    instead.
+
 .. _manual-line-plots:
 
 Line Plots

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 doc/source/visualizing/writing_fits_images.rst
--- a/doc/source/visualizing/writing_fits_images.rst
+++ b/doc/source/visualizing/writing_fits_images.rst
@@ -3,4 +3,4 @@
 Writing FITS Images
 ==========================
 
-.. notebook:: FITSImageBuffer.ipynb
\ No newline at end of file
+.. notebook:: FITSImageData.ipynb
\ No newline at end of file

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ b/yt/analysis_modules/ppv_cube/ppv_cube.py
@@ -13,8 +13,7 @@
 import numpy as np
 from yt.utilities.on_demand_imports import _astropy
 from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer, sanitize_fits_unit, \
-    create_sky_wcs
+from yt.utilities.fits_image import FITSImageData, sanitize_fits_unit
 from yt.visualization.volume_rendering.camera import off_axis_projection
 from yt.funcs import get_pbar
 from yt.utilities.physical_constants import clight, mh
@@ -89,6 +88,8 @@
         dims : integer, optional
             The spatial resolution of the cube. Implies nx = ny, e.g. the 
             aspect ratio of the PPVCube's spatial dimensions is 1.
+        thermal_broad : boolean, optional
+            Whether or not to broaden the line using the gas temperature. Default: False.
         atomic_weight : float, optional
             Set this value to the atomic weight of the particle that is emitting the line
             if *thermal_broad* is True. Defaults to 56 (Fe).
@@ -152,9 +153,7 @@
                                "methods are supported in PPVCube.")
 
         dd = ds.all_data()
-
         fd = dd._determine_fields(field)[0]
-
         self.field_units = ds._get_field_info(fd).units
 
         self.vbins = ds.arr(np.linspace(velocity_bounds[0],
@@ -172,7 +171,7 @@
         _vlos = create_vlos(normal, self.no_shifting)
         self.ds.add_field(("gas","v_los"), function=_vlos, units="cm/s")
 
-        _intensity = self.create_intensity()
+        _intensity = self._create_intensity()
         self.ds.add_field(("gas","intensity"), function=_intensity, units=self.field_units)
 
         if method == "integrate" and weight_field is None:
@@ -214,16 +213,6 @@
         self.ds.field_info.pop(("gas","intensity"))
         self.ds.field_info.pop(("gas","v_los"))
 
-    def create_intensity(self):
-        def _intensity(field, data):
-            v = self.current_v-data["v_los"].v
-            T = data["temperature"].v
-            w = ppv_utils.compute_weight(self.thermal_broad, self.dv_cgs,
-                                         self.particle_mass, v.flatten(), T.flatten())
-            w[np.isnan(w)] = 0.0
-            return data[self.field]*w.reshape(v.shape)
-        return _intensity
-
     def transform_spectral_axis(self, rest_value, units):
         """
         Change the units of the spectral axis to some equivalent unit, such
@@ -259,17 +248,18 @@
         self.dv = self.vbins[1]-self.vbins[0]
 
     @parallel_root_only
-    def write_fits(self, filename, clobber=True, length_unit=None,
+    def write_fits(self, filename, clobber=False, length_unit=None,
                    sky_scale=None, sky_center=None):
         r""" Write the PPVCube to a FITS file.
 
         Parameters
         ----------
         filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : string
+            The name of the file to write to. 
+        clobber : boolean, optional
+            Whether to overwrite a file with the same name that already 
+            exists. Default False.
+        length_unit : string, optional
             The units to convert the coordinates to in the file.
         sky_scale : tuple, optional
             Conversion between an angle unit and a length unit, if sky
@@ -280,7 +270,8 @@
 
         Examples
         --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, sky_scale=(1.0,"arcsec/kpc"))
+        >>> cube.write_fits("my_cube.fits", clobber=False, 
+        ...                 sky_scale=(1.0,"arcsec/kpc"), sky_center=(30.,45.))
         """
         vunit = fits_info[self.axis_type][0]
         vtype = fits_info[self.axis_type][1]
@@ -303,13 +294,11 @@
         w.wcs.cunit = [units,units,vunit]
         w.wcs.ctype = ["LINEAR","LINEAR",vtype]
 
+        fib = FITSImageData(self.data.transpose(), fields=self.field, wcs=w)
+        fib.update_all_headers("bunit", re.sub('()', '', str(self.proj_units)))
+        fib.update_all_headers("btype", self.field)
         if sky_scale is not None and sky_center is not None:
-            w = create_sky_wcs(w, sky_center, sky_scale)
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = re.sub('()', '', str(self.proj_units))
-        fib[0].header["btype"] = self.field
-
+            fib.create_sky_wcs(sky_center, sky_scale)
         fib.writeto(filename, clobber=clobber)
 
     def __repr__(self):
@@ -320,3 +309,13 @@
 
     def __getitem__(self, item):
         return self.data[item]
+
+    def _create_intensity(self):
+        def _intensity(field, data):
+            v = self.current_v-data["v_los"].in_cgs().v
+            T = (data["temperature"]).in_cgs().v
+            w = ppv_utils.compute_weight(self.thermal_broad, self.dv_cgs,
+                                         self.particle_mass, v.flatten(), T.flatten())
+            w[np.isnan(w)] = 0.0
+            return data[self.field]*w.reshape(v.shape)
+        return _intensity

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/analysis_modules/ppv_cube/tests/test_ppv.py
--- a/yt/analysis_modules/ppv_cube/tests/test_ppv.py
+++ b/yt/analysis_modules/ppv_cube/tests/test_ppv.py
@@ -1,5 +1,5 @@
 """
-Unit test the sunyaev_zeldovich analysis module.
+Unit test the PPVCube analysis module.
 """
 
 #-----------------------------------------------------------------------------

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/analysis_modules/sunyaev_zeldovich/projection.py
--- a/yt/analysis_modules/sunyaev_zeldovich/projection.py
+++ b/yt/analysis_modules/sunyaev_zeldovich/projection.py
@@ -316,7 +316,7 @@
         >>> sky_center = (30., 45., "deg")
         >>> szprj.write_fits("SZbullet.fits", sky_center=sky_center, sky_scale=sky_scale)
         """
-        from yt.utilities.fits_image import FITSImageBuffer, create_sky_wcs
+        from yt.utilities.fits_image import FITSImageData
 
         dx = self.dx.in_units("kpc")
         dy = dx
@@ -328,10 +328,9 @@
         w.wcs.cunit = ["kpc"]*2
         w.wcs.ctype = ["LINEAR"]*2
 
+        fib = FITSImageData(self.data, fields=self.data.keys(), wcs=w)
         if sky_scale is not None and sky_center is not None:
-            w = create_sky_wcs(w, sky_center, sky_scale)
-
-        fib = FITSImageBuffer(self.data, fields=self.data.keys(), wcs=w)
+            fib.create_sky_wcs(sky_center, sky_scale)
         fib.writeto(filename, clobber=clobber)
         
     @parallel_root_only

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -92,7 +92,7 @@
     >>> streamlines = Streamlines(ds, [0.5]*3)
     >>> streamlines.integrate_through_volume()
     >>> stream = streamlines.path(0)
-    >>> matplotlib.pylab.semilogy(stream['t'], stream['Density'], '-x')
+    >>> matplotlib.pylab.semilogy(stream['t'], stream['density'], '-x')
 
     """
     _type_name = "streamline"
@@ -991,12 +991,13 @@
     This will create a data object, find a nice value in the center, and
     output the vertices to "triangles.obj" after rescaling them.
 
+    >>> from yt.units import kpc
     >>> sp = ds.sphere("max", (10, "kpc")
-    >>> surf = ds.surface(sp, "Density", 5e-27)
-    >>> print surf["Temperature"]
+    >>> surf = ds.surface(sp, "density", 5e-27)
+    >>> print surf["temperature"]
     >>> print surf.vertices
-    >>> bounds = [(sp.center[i] - 5.0/ds['kpc'],
-    ...            sp.center[i] + 5.0/ds['kpc']) for i in range(3)]
+    >>> bounds = [(sp.center[i] - 5.0*kpc,
+    ...            sp.center[i] + 5.0*kpc) for i in range(3)]
     >>> surf.export_ply("my_galaxy.ply", bounds = bounds)
     """
     _type_name = "surface"
@@ -1117,9 +1118,9 @@
         calculate the metal flux over it.
 
         >>> sp = ds.sphere("max", (10, "kpc")
-        >>> surf = ds.surface(sp, "Density", 5e-27)
+        >>> surf = ds.surface(sp, "density", 5e-27)
         >>> flux = surf.calculate_flux(
-        ...     "velocity_x", "velocity_y", "velocity_z", "Metal_Density")
+        ...     "velocity_x", "velocity_y", "velocity_z", "metal_density")
         """
         flux = 0.0
         mylog.info("Fluxing %s", fluxing_field)
@@ -1204,18 +1205,18 @@
         >>> sp = ds.sphere("max", (10, "kpc"))
         >>> trans = 1.0
         >>> distf = 3.1e18*1e3 # distances into kpc
-        >>> surf = ds.surface(sp, "Density", 5e-27)
+        >>> surf = ds.surface(sp, "density", 5e-27)
         >>> surf.export_obj("my_galaxy", transparency=trans, dist_fac = distf)
 
         >>> sp = ds.sphere("max", (10, "kpc"))
-        >>> mi, ma = sp.quantities['Extrema']('Temperature')[0]
+        >>> mi, ma = sp.quantities.extrema('temperature')[0]
         >>> rhos = [1e-24, 1e-25]
         >>> trans = [0.5, 1.0]
         >>> distf = 3.1e18*1e3 # distances into kpc
         >>> for i, r in enumerate(rhos):
-        ...     surf = ds.surface(sp,'Density',r)
+        ...     surf = ds.surface(sp,'density',r)
         ...     surf.export_obj("my_galaxy", transparency=trans[i], 
-        ...                      color_field='Temperature', dist_fac = distf, 
+        ...                      color_field='temperature', dist_fac = distf, 
         ...                      plot_index = i, color_field_max = ma, 
         ...                      color_field_min = mi)
 
@@ -1224,12 +1225,12 @@
         >>> trans = [0.5, 1.0]
         >>> distf = 3.1e18*1e3 # distances into kpc
         >>> def _Emissivity(field, data):
-        ...     return (data['Density']*data['Density']*np.sqrt(data['Temperature']))
-        >>> add_field("Emissivity", function=_Emissivity, units=r"\rm{g K}/\rm{cm}^{6}")
+        ...     return (data['density']*data['density']*np.sqrt(data['temperature']))
+        >>> ds.add_field("emissivity", function=_Emissivity, units=r"g*K/cm**6")
         >>> for i, r in enumerate(rhos):
-        ...     surf = ds.surface(sp,'Density',r)
-        ...     surf.export_obj("my_galaxy", transparency=trans[i], 
-        ...                      color_field='Temperature', emit_field = 'Emissivity', 
+        ...     surf = ds.surface(sp,'density',r)
+        ...     surf.export_obj("my_galaxy", transparency=trans[i],
+        ...                      color_field='temperature', emit_field = 'emissivity',
         ...                      dist_fac = distf, plot_index = i)
 
         """
@@ -1459,18 +1460,18 @@
         >>> sp = ds.sphere("max", (10, "kpc"))
         >>> trans = 1.0
         >>> distf = 3.1e18*1e3 # distances into kpc
-        >>> surf = ds.surface(sp, "Density", 5e-27)
+        >>> surf = ds.surface(sp, "density", 5e-27)
         >>> surf.export_obj("my_galaxy", transparency=trans, dist_fac = distf)
 
         >>> sp = ds.sphere("max", (10, "kpc"))
-        >>> mi, ma = sp.quantities['Extrema']('Temperature')[0]
+        >>> mi, ma = sp.quantities.extrema('temperature')[0]
         >>> rhos = [1e-24, 1e-25]
         >>> trans = [0.5, 1.0]
         >>> distf = 3.1e18*1e3 # distances into kpc
         >>> for i, r in enumerate(rhos):
-        ...     surf = ds.surface(sp,'Density',r)
+        ...     surf = ds.surface(sp,'density',r)
         ...     surf.export_obj("my_galaxy", transparency=trans[i],
-        ...                      color_field='Temperature', dist_fac = distf,
+        ...                      color_field='temperature', dist_fac = distf,
         ...                      plot_index = i, color_field_max = ma,
         ...                      color_field_min = mi)
 
@@ -1479,12 +1480,12 @@
         >>> trans = [0.5, 1.0]
         >>> distf = 3.1e18*1e3 # distances into kpc
         >>> def _Emissivity(field, data):
-        ...     return (data['Density']*data['Density']*np.sqrt(data['Temperature']))
-        >>> add_field("Emissivity", function=_Emissivity, units=r"\rm{g K}/\rm{cm}^{6}")
+        ...     return (data['density']*data['density']*np.sqrt(data['temperature']))
+        >>> ds.add_field("emissivity", function=_Emissivity, units="g / cm**6")
         >>> for i, r in enumerate(rhos):
-        ...     surf = ds.surface(sp,'Density',r)
+        ...     surf = ds.surface(sp,'density',r)
         ...     surf.export_obj("my_galaxy", transparency=trans[i],
-        ...                      color_field='Temperature', emit_field = 'Emissivity',
+        ...                      color_field='temperature', emit_field = 'emissivity',
         ...                      dist_fac = distf, plot_index = i)
 
         """
@@ -1581,12 +1582,13 @@
         Examples
         --------
 
+        >>> from yt.units import kpc
         >>> sp = ds.sphere("max", (10, "kpc")
-        >>> surf = ds.surface(sp, "Density", 5e-27)
-        >>> print surf["Temperature"]
+        >>> surf = ds.surface(sp, "density", 5e-27)
+        >>> print surf["temperature"]
         >>> print surf.vertices
-        >>> bounds = [(sp.center[i] - 5.0/ds['kpc'],
-        ...            sp.center[i] + 5.0/ds['kpc']) for i in range(3)]
+        >>> bounds = [(sp.center[i] - 5.0*kpc,
+        ...            sp.center[i] + 5.0*kpc) for i in range(3)]
         >>> surf.export_ply("my_galaxy.ply", bounds = bounds)
         """
         if self.vertices is None:
@@ -1716,18 +1718,17 @@
         Examples
         --------
 
-        >>> from yt.mods import *
-        >>> ds = load("redshift0058")
+        >>> from yt.units import kpc
         >>> dd = ds.sphere("max", (200, "kpc"))
         >>> rho = 5e-27
-        >>> bounds = [(dd.center[i] - 100.0/ds['kpc'],
-        ...            dd.center[i] + 100.0/ds['kpc']) for i in range(3)]
+        >>> bounds = [(dd.center[i] - 100.0*kpc,
+        ...            dd.center[i] + 100.0*kpc) for i in range(3)]
         ...
-        >>> surf = ds.surface(dd, "Density", rho)
+        >>> surf = ds.surface(dd, "density", rho)
         >>> rv = surf.export_sketchfab(
         ...     title = "Testing Upload",
         ...     description = "A simple test of the uploader",
-        ...     color_field = "Temperature",
+        ...     color_field = "temperature",
         ...     color_map = "hot",
         ...     color_log = True,
         ...     bounds = bounds)

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/data_objects/profiles.py
--- a/yt/data_objects/profiles.py
+++ b/yt/data_objects/profiles.py
@@ -937,6 +937,9 @@
     def items(self):
         return [(k,self[k]) for k in self.field_data.keys()]
 
+    def keys(self):
+        return self.field_data.keys()
+
     def __iter__(self):
         return sorted(self.items())
 

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/fields/field_detector.py
--- a/yt/fields/field_detector.py
+++ b/yt/fields/field_detector.py
@@ -136,6 +136,11 @@
                 self[item] = \
                   YTArray(np.ones((self.NumberOfParticles, 3)),
                           finfo.units, registry=self.ds.unit_registry)
+            elif "FourMetalFractions" in (item, item[1]):
+                self[item] = \
+                  YTArray(np.ones((self.NumberOfParticles, 4)),
+                          finfo.units, registry=self.ds.unit_registry)
+
             else:
                 # Not a vector
                 self[item] = \

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/fields/particle_fields.py
--- a/yt/fields/particle_fields.py
+++ b/yt/fields/particle_fields.py
@@ -61,6 +61,10 @@
     'Mg_fraction',
     'Si_fraction',
     'Fe_fraction',
+    'C_density',
+    'O_density',
+    'Si_density',
+    'Fe_density'
 )
 
 

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/frontends/enzo/data_structures.py
--- a/yt/frontends/enzo/data_structures.py
+++ b/yt/frontends/enzo/data_structures.py
@@ -452,9 +452,16 @@
             if "AppendActiveParticleType" in self.dataset.parameters:
                 ap_fields = self._detect_active_particle_fields()
                 field_list = list(set(field_list).union(ap_fields))
+            ptypes = self.dataset.particle_types
+            ptypes_raw = self.dataset.particle_types_raw
         else:
             field_list = None
+            ptypes = None
+            ptypes_raw = None
         self.field_list = list(self.comm.mpi_bcast(field_list))
+        self.dataset.particle_types = list(self.comm.mpi_bcast(ptypes))
+        self.dataset.particle_types_raw = list(self.comm.mpi_bcast(ptypes_raw))
+
 
     def _generate_random_grids(self):
         if self.num_grids > 40:

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -18,7 +18,7 @@
 from yt.funcs import mylog, get_image_suffix
 from yt.visualization._mpl_imports import FigureCanvasAgg
 from yt.units.yt_array import YTQuantity, YTArray
-from yt.utilities.fits_image import FITSImageBuffer
+from yt.utilities.fits_image import FITSImageData
 
 import os
 
@@ -127,7 +127,7 @@
     w = subcube.wcs.copy()
     w.wcs.crpix[-1] = 0.5
     w.wcs.crval[-1] = -0.5*width
-    fid = FITSImageBuffer(slab_data, wcs=w)
+    fid = FITSImageData(slab_data, wcs=w)
     for hdu in fid:
         hdu.header.pop("RESTFREQ", None)
         hdu.header.pop("RESTFRQ", None)

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/frontends/gadget/definitions.py
--- a/yt/frontends/gadget/definitions.py
+++ b/yt/frontends/gadget/definitions.py
@@ -65,5 +65,22 @@
                    ("Electron_Number_Density", "Gas"),
                    ("HI_NumberDensity", "Gas"),
                    ("SmoothingLength", "Gas"),
-    )
+    ),
+    group0000 =  ( "Coordinates",
+                   "Velocities",
+                   "ParticleIDs",
+                   "Mass",
+                   "Potential",
+                   ("Temperature", "Gas"),
+                   ("Density", "Gas"),
+                   ("ElectronNumberDensity", "Gas"),
+                   ("HI_NumberDensity", "Gas"),
+                   ("SmoothingLength", "Gas"),
+                   ("StarFormationRate", "Gas"),
+                   ("DelayTime", "Gas"),
+                   ("FourMetalFractions", ("Gas", "Stars")),
+                   ("MaxTemperature", ("Gas", "Stars")),
+                   ("NStarsSpawned", ("Gas", "Stars")),
+                   ("StellarAge", "Stars")
+    ),
 )

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/frontends/gadget/fields.py
--- a/yt/frontends/gadget/fields.py
+++ b/yt/frontends/gadget/fields.py
@@ -21,13 +21,53 @@
 class GadgetFieldInfo(SPHFieldInfo):
 
     def setup_particle_fields(self, ptype, *args, **kwargs):
+
+        # setup some special fields that only make sense for SPH particles
+
+        if (ptype, "FourMetalFractions") in self.ds.field_list:
+            self._setup_four_metal_fractions(ptype)
+
         super(GadgetFieldInfo, self).setup_particle_fields(
             ptype, *args, **kwargs)
 
-        # setup some special fields that only make sense for SPH particles
         if ptype in ("PartType0", "Gas"):
             self.setup_gas_particle_fields(ptype)
 
+    def _setup_four_metal_fractions(self, ptype):
+        """
+        This function breaks the FourMetalFractions field (if present) 
+        into its four component metal fraction fields and adds 
+        corresponding metal density fields which will later get smoothed
+
+        This gets used with the Gadget group0000 format
+        as defined in the gadget_field_specs in frontends/gadget/definitions.py
+        """
+        metal_names = ['C', 'O', 'Si', 'Fe']
+        for i, metal_name in enumerate(metal_names):
+
+            # add the metal fraction fields
+            def _Fraction_wrap(i):
+                def _Fraction(field, data):
+                    return data[(ptype, 'FourMetalFractions')][:,i]
+                return _Fraction
+
+            self.add_field( (ptype, metal_name+"_fraction"),
+                            function=_Fraction_wrap(i), 
+                            particle_type=True,
+                            units="")
+
+            # add the metal density fields
+            def _Density_wrap(i):
+                def _Metal_density(field, data):
+                    return data[(ptype, 'FourMetalFractions')][:,i] * \
+                           data[(ptype, 'density')]
+                return _Metal_density
+
+            self.add_field( (ptype, metal_name+"_density"),
+                            function=_Density_wrap(i), 
+                            particle_type=True,
+                            units="g/cm**3")
+
     def setup_gas_particle_fields(self, ptype):
         if (ptype, "ElectronAbundance") in self.ds.field_list:
             def _temperature(field, data):

diff -r 76052ef99b8e12b666cffbd8cd4b03a4ea4169a2 -r dc2467c4eae70b9f185adf2cba8f61b95f65fea0 yt/frontends/gadget/io.py
--- a/yt/frontends/gadget/io.py
+++ b/yt/frontends/gadget/io.py
@@ -33,7 +33,10 @@
     
 class IOHandlerGadgetBinary(BaseIOHandler):
     _dataset_type = "gadget_binary"
-    _vector_fields = ("Coordinates", "Velocity", "Velocities")
+    _vector_fields = (("Coordinates", 3),
+                      ("Velocity", 3),
+                      ("Velocities", 3),
+                      ("FourMetalFractions", 4))
 
     # Particle types (Table 3 in GADGET-2 user guide)
     #
@@ -54,6 +57,7 @@
     _var_mass = None
 
     def __init__(self, ds, *args, **kwargs):
+        self._vector_fields = dict(self._vector_fields)
         self._fields = ds._field_spec
         self._ptypes = ds._ptype_spec
         super(IOHandlerGadgetBinary, self).__init__(ds, *args, **kwargs)
@@ -126,10 +130,11 @@
         else:
             dt = "float32"
         if name in self._vector_fields:
-            count *= 3
+            count *= self._vector_fields[name]
         arr = np.fromfile(f, dtype=dt, count = count)
         if name in self._vector_fields:
-            arr = arr.reshape((count/3, 3), order="C")
+            factor = self._vector_fields[name]
+            arr = arr.reshape((count/factor, factor), order="C")
         return arr.astype("float64")
 
     def _initialize_index(self, data_file, regions):
@@ -177,7 +182,7 @@
                 offsets[(ptype, field)] = pos
                 any_ptypes = True
                 if field in self._vector_fields:
-                    pos += 3 * pcount[ptype] * fs
+                    pos += self._vector_fields[field] * pcount[ptype] * fs
                 else:
                     pos += pcount[ptype] * fs
             pos += 4
@@ -203,6 +208,8 @@
                     field, req = field
                     if req is ZeroMass:
                         if m > 0.0 : continue
+                    elif isinstance(req, tuple) and ptype in req:
+                        pass
                     elif req != ptype:
                         continue
                 field_list.append((ptype, field))

This diff is so big that we needed to truncate the remainder.

Repository URL: https://bitbucket.org/yt_analysis/yt/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.



More information about the yt-svn mailing list