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

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Fri Mar 29 03:51:45 PDT 2013


3 new commits in yt:

https://bitbucket.org/yt_analysis/yt/commits/7e0900e6fa90/
Changeset:   7e0900e6fa90
Branch:      stable
User:        MatthewTurk
Date:        2013-03-29 11:50:51
Summary:     Merging from yt into stable
Affected #:  31 files

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/analysis_modules/halo_finding/rockstar/rockstar.py
--- a/yt/analysis_modules/halo_finding/rockstar/rockstar.py
+++ b/yt/analysis_modules/halo_finding/rockstar/rockstar.py
@@ -238,6 +238,7 @@
         tpf = ts[0]
 
         def _particle_count(field, data):
+            if data.NumberOfParticles == 0: return 0
             try:
                 data["particle_type"]
                 has_particle_type=True

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -36,6 +36,8 @@
 import itertools
 import shelve
 import cStringIO
+import fileinput
+from re import finditer
 
 from yt.funcs import *
 from yt.config import ytcfg
@@ -4036,7 +4038,7 @@
         sp1, ")"])
     """
     _type_name = "boolean"
-    _con_args = ("regions")
+    _con_args = ("regions",)
     def __init__(self, regions, fields = None, pf = None, **kwargs):
         # Center is meaningless, but we'll define it all the same.
         AMR3DData.__init__(self, [0.5]*3, fields, pf, **kwargs)
@@ -4374,6 +4376,230 @@
                 vv[:,i,j] = self.vertices[j,i::3]
         return vv
 
+    def export_obj(self, filename, transparency = 1.0, dist_fac = None,
+                   color_field = None, emit_field = None, color_map = "algae", 
+                   color_log = True, emit_log = True, plot_index = None, 
+                   color_field_max = None, color_field_min = None, 
+                   emit_field_max = None, emit_field_min = None):
+        r"""This exports the surface to the OBJ format, suitable for visualization
+        in many different programs (e.g., Blender).  NOTE: this exports an .obj file 
+        and an .mtl file, both with the general 'filename' as a prefix.  
+        The .obj file points to the .mtl file in its header, so if you move the 2 
+        files, make sure you change the .obj header to account for this. ALSO NOTE: 
+        the emit_field needs to be a combination of the other 2 fields used to 
+        have the emissivity track with the color.
+
+        Parameters
+        ----------
+        filename : string
+            The file this will be exported to.  This cannot be a file-like object.
+            Note - there are no file extentions included - both obj & mtl files 
+            are created.
+        transparency : float
+            This gives the transparency of the output surface plot.  Values
+            from 0.0 (invisible) to 1.0 (opaque).
+        dist_fac : float
+            Divide the axes distances by this amount.
+        color_field : string
+            Should a field be sample and colormapped?
+        emit_field : string
+            Should we track the emissivity of a field?
+              NOTE: this should be a combination of the other 2 fields being used.
+        color_map : string
+            Which color map should be applied?
+        color_log : bool
+            Should the color field be logged before being mapped?
+        emit_log : bool
+            Should the emitting field be logged before being mapped?
+        plot_index : integer
+            Index of plot for multiple plots.  If none, then only 1 plot.
+        color_field_max : float
+            Maximum value of the color field across all surfaces.
+        color_field_min : float
+            Minimum value of the color field across all surfaces.
+        emit_field_max : float
+            Maximum value of the emitting field across all surfaces.
+        emit_field_min : float
+            Minimum value of the emitting field across all surfaces.
+
+        Examples
+        --------
+
+        >>> sp = pf.h.sphere("max", (10, "kpc"))
+        >>> trans = 1.0
+        >>> distf = 3.1e18*1e3 # distances into kpc
+        >>> surf = pf.h.surface(sp, "Density", 5e-27)
+        >>> surf.export_obj("my_galaxy", transparency=trans, dist_fac = distf)
+
+        >>> sp = pf.h.sphere("max", (10, "kpc"))
+        >>> 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 = pf.h.surface(sp,'Density',r)
+        ...     surf.export_obj("my_galaxy", transparency=trans[i], 
+        ...                      color_field='Temperature', dist_fac = distf, 
+        ...                      plot_index = i, color_field_max = ma, 
+        ...                      color_field_min = mi)
+
+        >>> sp = pf.h.sphere("max", (10, "kpc"))
+        >>> rhos = [1e-24, 1e-25]
+        >>> 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}")
+        >>> for i, r in enumerate(rhos):
+        ...     surf = pf.h.surface(sp,'Density',r)
+        ...     surf.export_obj("my_galaxy", transparency=trans[i], 
+        ...                      color_field='Temperature', emit_field = 'Emissivity', 
+        ...                      dist_fac = distf, plot_index = i)
+
+        """
+        if self.vertices is None:
+            self.get_data(color_field,"face")
+        elif color_field is not None:
+            if color_field not in self.field_data:
+                self[color_field]
+        if emit_field is not None:
+            if color_field not in self.field_data:
+                self[emit_field]
+        only_on_root(self._export_obj, filename, transparency, dist_fac, color_field, emit_field, 
+                             color_map, color_log, emit_log, plot_index, color_field_max, 
+                             color_field_min, emit_field_max, emit_field_min)
+
+    def _color_samples_obj(self, cs, em, color_log, emit_log, color_map, arr, 
+                           color_field_max, color_field_min, 
+                           emit_field_max, emit_field_min): # this now holds for obj files
+        if color_log: cs = np.log10(cs)
+        if emit_log: em = np.log10(em)
+        if color_field_min is None:
+            mi = cs.min()
+        else:
+            mi = color_field_min
+            if color_log: mi = np.log10(mi)
+        if color_field_max is None:
+            ma = cs.max()
+        else:
+            ma = color_field_max
+            if color_log: ma = np.log10(ma)
+        cs = (cs - mi) / (ma - mi)
+        # to get color indicies for OBJ formatting
+        from yt.visualization._colormap_data import color_map_luts
+        lut = color_map_luts[color_map]
+        x = np.mgrid[0.0:1.0:lut[0].shape[0]*1j]
+        arr["cind"][:] = (np.interp(cs,x,x)*(lut[0].shape[0]-1)).astype("uint8")
+        # now, get emission
+        if emit_field_min is None:
+            emi = em.min()
+        else:
+            emi = emit_field_min
+            if emit_log: emi = np.log10(emi)
+        if emit_field_max is None:
+            ema = em.max()
+        else:
+            ema = emit_field_max
+            if emit_log: ema = np.log10(ema)
+        em = (em - emi)/(ema - emi)
+        x = np.mgrid[0.0:255.0:2j] # assume 1 emissivity per color
+        arr["emit"][:] = (np.interp(em,x,x))*2.0 # for some reason, max emiss = 2
+
+    @parallel_root_only
+    def _export_obj(self, filename, transparency, dist_fac = None, 
+                    color_field = None, emit_field = None, color_map = "algae", 
+                    color_log = True, emit_log = True, plot_index = None, 
+                    color_field_max = None, color_field_min = None, 
+                    emit_field_max = None, emit_field_min = None):
+        if plot_index is None:
+            plot_index = 0
+        if isinstance(filename, file):
+            fobj = filename + '.obj'
+            fmtl = filename + '.mtl'
+        else:
+            if plot_index == 0:
+                fobj = open(filename + '.obj', "w")
+                fmtl = open(filename + '.mtl', 'w')
+                cc = 1
+            else:
+                # read in last vertex
+                linesave = ''
+                for line in fileinput.input(filename + '.obj'):
+                    if line[0] == 'f':
+                        linesave = line
+                p = [m.start() for m in finditer(' ', linesave)]
+                cc = int(linesave[p[len(p)-1]:])+1
+                fobj = open(filename + '.obj', "a")
+                fmtl = open(filename + '.mtl', 'a')
+        ftype = [("cind", "uint8"), ("emit", "float")]
+        vtype = [("x","float"),("y","float"), ("z","float")]
+        if plot_index == 0:
+            fobj.write("# yt OBJ file\n")
+            fobj.write("# www.yt-project.com\n")
+            fobj.write("mtllib " + filename + '.mtl\n\n')  # use this material file for the faces
+            fmtl.write("# yt MLT file\n")
+            fmtl.write("# www.yt-project.com\n\n")
+        #(0) formulate vertices
+        nv = self.vertices.shape[1] # number of groups of vertices
+        f = np.empty(nv/self.vertices.shape[0], dtype=ftype) # store sets of face colors
+        v = np.empty(nv, dtype=vtype) # stores vertices
+        if color_field is not None:
+            cs = self[color_field]
+        else:
+            cs = np.empty(self.vertices.shape[1]/self.vertices.shape[0])
+        if emit_field is not None:
+            em = self[emit_field]
+        else:
+            em = np.empty(self.vertices.shape[1]/self.vertices.shape[0])            
+        self._color_samples_obj(cs, em, color_log, emit_log, color_map, f, 
+                                color_field_max, color_field_min, 
+                                emit_field_max, emit_field_min) # map color values to color scheme
+        from yt.visualization._colormap_data import color_map_luts # import colors for mtl file
+        lut = color_map_luts[color_map] # enumerate colors
+        # interpolate emissivity to enumerated colors
+        emiss = np.interp(np.mgrid[0:lut[0].shape[0]],np.mgrid[0:len(cs)],f["emit"][:])
+        if dist_fac is None: # then normalize by bounds
+            DLE = self.pf.domain_left_edge
+            DRE = self.pf.domain_right_edge
+            bounds = [(DLE[i], DRE[i]) for i in range(3)]
+            for i, ax in enumerate("xyz"):
+                # Do the bounds first since we cast to f32
+                tmp = self.vertices[i,:]
+                np.subtract(tmp, bounds[i][0], tmp)
+                w = bounds[i][1] - bounds[i][0]
+                np.divide(tmp, w, tmp)
+                np.subtract(tmp, 0.5, tmp) # Center at origin.
+                v[ax][:] = tmp   
+        else:
+            for i, ax in enumerate("xyz"):
+                tmp = self.vertices[i,:]
+                np.divide(tmp, dist_fac, tmp)
+                v[ax][:] = tmp
+        #(1) write all colors per surface to mtl file
+        for i in range(0,lut[0].shape[0]): 
+            omname = "material_" + str(i) + '_' + str(plot_index)  # name of the material
+            fmtl.write("newmtl " + omname +'\n') # the specific material (color) for this face
+            fmtl.write("Ka %.6f %.6f %.6f\n" %(0.0, 0.0, 0.0)) # ambient color, keep off
+            fmtl.write("Kd %.6f %.6f %.6f\n" %(lut[0][i], lut[1][i], lut[2][i])) # color of face
+            fmtl.write("Ks %.6f %.6f %.6f\n" %(0.0, 0.0, 0.0)) # specular color, keep off
+            fmtl.write("d %.6f\n" %(transparency))  # transparency
+            fmtl.write("em %.6f\n" %(emiss[i])) # emissivity per color
+            fmtl.write("illum 2\n") # not relevant, 2 means highlights on?
+            fmtl.write("Ns %.6f\n\n" %(0.0)) #keep off, some other specular thing
+        #(2) write vertices
+        for i in range(0,self.vertices.shape[1]):
+            fobj.write("v %.6f %.6f %.6f\n" %(v["x"][i], v["y"][i], v["z"][i]))    
+        fobj.write("#done defining vertices\n\n")
+        #(3) define faces and materials for each face
+        for i in range(0,self.triangles.shape[0]):
+            omname = 'material_' + str(f["cind"][i]) + '_' + str(plot_index) # which color to use
+            fobj.write("usemtl " + omname + '\n') # which material to use for this face (color)
+            fobj.write("f " + str(cc) + ' ' + str(cc+1) + ' ' + str(cc+2) + '\n\n') # vertices to color
+            cc = cc+3
+        fmtl.close()
+        fobj.close()
+
+
     def export_ply(self, filename, bounds = None, color_field = None,
                    color_map = "algae", color_log = True, sample_type = "face"):
         r"""This exports the surface to the PLY format, suitable for visualization
@@ -4606,22 +4832,46 @@
             mylog.error("Problem uploading.")
         return upload_id
 
+# Many of these items are set up specifically to ensure that
+# we are not breaking old pickle files.  This means we must only call the
+# _reconstruct_object and that we cannot mandate any additional arguments to
+# the reconstruction function.
+#
+# In the future, this would be better off being set up to more directly
+# reference objects or retain state, perhaps with a context manager.
+#
+# One final detail: time series or multiple parameter files in a single pickle
+# seems problematic.
+
+class ReconstructedObject(tuple):
+    pass
+
+def _check_nested_args(arg, ref_pf):
+    if not isinstance(arg, (tuple, list, ReconstructedObject)):
+        return arg
+    elif isinstance(arg, ReconstructedObject) and ref_pf == arg[0]:
+        return arg[1]
+    narg = [_check_nested_args(a, ref_pf) for a in arg]
+    return narg
+
+def _get_pf_by_hash(hash):
+    from yt.data_objects.static_output import _cached_pfs
+    for pf in _cached_pfs.values():
+        if pf._hash() == hash: return pf
+    return None
 
 def _reconstruct_object(*args, **kwargs):
     pfid = args[0]
     dtype = args[1]
+    pf = _get_pf_by_hash(pfid)
+    if not pf:
+        pfs = ParameterFileStore()
+        pf = pfs.get_pf_hash(pfid)
     field_parameters = args[-1]
     # will be much nicer when we can do pfid, *a, fp = args
-    args, new_args = args[2:-1], []
-    for arg in args:
-        if iterable(arg) and len(arg) == 2 \
-           and not isinstance(arg, types.DictType) \
-           and isinstance(arg[1], AMRData):
-            new_args.append(arg[1])
-        else: new_args.append(arg)
-    pfs = ParameterFileStore()
-    pf = pfs.get_pf_hash(pfid)
+    args = args[2:-1]
+    new_args = [_check_nested_args(a, pf) for a in args]
     cls = getattr(pf.h, dtype)
     obj = cls(*new_args)
     obj.field_parameters.update(field_parameters)
-    return pf, obj
+    return ReconstructedObject((pf, obj))

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/data_objects/field_info_container.py
--- a/yt/data_objects/field_info_container.py
+++ b/yt/data_objects/field_info_container.py
@@ -505,4 +505,3 @@
         if isinstance(data, FieldDetector): return True
         if getattr(data, "_type_name", None) == 'grid': return True
         raise NeedsOriginalGrid()
-

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/data_objects/tests/test_pickle.py
--- /dev/null
+++ b/yt/data_objects/tests/test_pickle.py
@@ -0,0 +1,69 @@
+"""
+Testsuite for pickling yt objects.
+
+Author: Elizabeth Tasker <tasker at astro1.sci.hokudai.ac.jp>
+Affiliation: Hokkaido University
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2013 Elizabeth Tasker. All Rights Reserved.
+
+  This file is part of yt.
+
+  yt is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+import cPickle
+import os
+import tempfile
+from yt.testing \
+    import fake_random_pf, assert_equal
+
+
+def setup():
+    """Test specific setup."""
+    from yt.config import ytcfg
+    ytcfg["yt", "__withintesting"] = "True"
+
+
+def test_save_load_pickle():
+    """Main test for loading pickled objects"""
+    test_pf = fake_random_pf(64)
+
+    # create extracted region from boolean (fairly complex object)
+    center = (test_pf.domain_left_edge + test_pf.domain_right_edge) / 2
+    sp_outer = test_pf.h.sphere(center, test_pf.domain_width[0])
+    sp_inner = test_pf.h.sphere(center, test_pf.domain_width[0] / 10.0)
+    sp_boolean = test_pf.h.boolean([sp_outer, "NOT", sp_inner])
+
+    minv, maxv = sp_boolean.quantities["Extrema"]("Density")[0]
+    contour_threshold = min(minv * 10.0, 0.9 * maxv)
+
+    contours = sp_boolean.extract_connected_sets(
+        "Density", 1, contour_threshold, maxv + 1, log_space=True, cache=True)
+
+    # save object
+    cpklfile = tempfile.NamedTemporaryFile(delete=False)
+    cPickle.dump(contours[1][0], cpklfile)
+    cpklfile.close()
+
+    # load object
+    test_load = cPickle.load(open(cpklfile.name, "rb"))
+
+    assert_equal.description = \
+        "%s: File was pickle-loaded succesfully" % __name__
+    yield assert_equal, test_load is not None, True
+    assert_equal.description = \
+        "%s: Length of pickle-loaded connected set object" % __name__
+    yield assert_equal, len(contours[1][0]), len(test_load)
+
+    os.remove(cpklfile.name)

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -801,8 +801,9 @@
     for i, ax in enumerate('xyz'):
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
         if data.pf.periodicity[i] == True:
-            np.subtract(DW[i], r, rdw)
             np.abs(r, r)
+            np.subtract(r, DW[i], rdw)
+            np.abs(rdw, rdw)
             np.minimum(r, rdw, r)
         np.power(r, 2.0, r)
         np.add(radius, r, radius)

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/chombo/data_structures.py
--- a/yt/frontends/chombo/data_structures.py
+++ b/yt/frontends/chombo/data_structures.py
@@ -39,8 +39,8 @@
      ST_CTIME
 
 from .definitions import \
-     pluto2enzoDict, \
-     yt2plutoFieldsDict, \
+     chombo2enzoDict, \
+     yt2chomboFieldsDict, \
      parameterDict \
 
 from yt.funcs import *
@@ -250,7 +250,7 @@
         seconds = 1 #self["Time"]
         for unit in sec_conversion.keys():
             self.time_units[unit] = seconds / sec_conversion[unit]
-        for key in yt2plutoFieldsDict:
+        for key in yt2chomboFieldsDict:
             self.conversion_factors[key] = 1.0
 
     def _setup_nounits_units(self):
@@ -270,29 +270,22 @@
 
     def _parse_parameter_file(self):
         """
-        Check to see whether a 'pluto.ini' or 'orion2.ini' file
+        Check to see whether an 'orion2.ini' file
         exists in the plot file directory. If one does, attempt to parse it.
-        Otherwise, assume the left edge starts at 0 and get the right edge
-        from the hdf5 file.
+        Otherwise grab the dimensions from the hdf5 file.
         """
-        if os.path.isfile('pluto.ini'):
-            self._parse_pluto_file('pluto.ini')
-        else:
-            if os.path.isfile('orion2.ini'): self._parse_pluto_file('orion2.ini')
-            self.unique_identifier = \
-                int(os.stat(self.parameter_filename)[ST_CTIME])
-            self.domain_left_edge = self.__calc_left_edge()
-            self.domain_right_edge = self.__calc_right_edge()
-            self.domain_dimensions = self.__calc_domain_dimensions()
-            self.dimensionality = 3
-            self.refine_by = self._handle['/level_0'].attrs['ref_ratio']
+        
+        if os.path.isfile('orion2.ini'): self._parse_inputs_file('orion2.ini')
+        self.unique_identifier = \
+                               int(os.stat(self.parameter_filename)[ST_CTIME])
+        self.domain_left_edge = self.__calc_left_edge()
+        self.domain_right_edge = self.__calc_right_edge()
+        self.domain_dimensions = self.__calc_domain_dimensions()
+        self.dimensionality = 3
+        self.refine_by = self._handle['/level_0'].attrs['ref_ratio']
         self.periodicity = (True, True, True)
 
-    def _parse_pluto_file(self, ini_filename):
-        """
-        Reads in an inputs file in the 'pluto.ini' format. Probably not
-        especially robust at the moment.
-        """
+    def _parse_inputs_file(self, ini_filename):
         self.fullplotdir = os.path.abspath(self.parameter_filename)
         self.ini_filename = self._localize( \
             self.ini_filename, ini_filename)
@@ -305,8 +298,8 @@
                 param, sep, vals = map(rstrip,line.partition(' '))
             except ValueError:
                 mylog.error("ValueError: '%s'", line)
-            if pluto2enzoDict.has_key(param):
-                paramName = pluto2enzoDict[param]
+            if chombo2enzoDict.has_key(param):
+                paramName = chombo2enzoDict[param]
                 t = map(parameterDict[paramName], vals.split())
                 if len(t) == 1:
                     self.parameters[paramName] = t[0]
@@ -336,13 +329,14 @@
 
     @classmethod
     def _is_valid(self, *args, **kwargs):
-        try:
-            fileh = h5py.File(args[0],'r')
-            valid = "Chombo_global" in fileh["/"]
-            fileh.close()
-            return valid
-        except:
-            pass
+        if not os.path.isfile('pluto.ini'):
+            try:
+                fileh = h5py.File(args[0],'r')
+                valid = "Chombo_global" in fileh["/"]
+                fileh.close()
+                return valid
+            except:
+                pass
         return False
 
     @parallel_root_only

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/chombo/definitions.py
--- a/yt/frontends/chombo/definitions.py
+++ b/yt/frontends/chombo/definitions.py
@@ -56,10 +56,10 @@
                  "NumberOfParticleAttributes": int,
                                  }
 
-pluto2enzoDict = {"GAMMA": "Gamma",
+chombo2enzoDict = {"GAMMA": "Gamma",
                   "Ref_ratio": "RefineBy"
                                     }
 
-yt2plutoFieldsDict = {}
-pluto2ytFieldsDict = {}
+yt2chomboFieldsDict = {}
+chombo2ytFieldsDict = {}
 

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/enzo/fields.py
--- a/yt/frontends/enzo/fields.py
+++ b/yt/frontends/enzo/fields.py
@@ -130,14 +130,20 @@
 def _ThermalEnergy(field, data):
     if data.pf["HydroMethod"] == 2:
         return data["TotalEnergy"]
-    else:
-        if data.pf["DualEnergyFormalism"]:
-            return data["GasEnergy"]
-        else:
-            return data["TotalEnergy"] - 0.5*(
-                   data["x-velocity"]**2.0
-                 + data["y-velocity"]**2.0
-                 + data["z-velocity"]**2.0 )
+    
+    if data.pf["DualEnergyFormalism"]:
+        return data["GasEnergy"]
+
+    if data.pf["HydroMethod"] in (4,6):
+        return data["TotalEnergy"] - 0.5*(
+            data["x-velocity"]**2.0
+            + data["y-velocity"]**2.0
+            + data["z-velocity"]**2.0 ) - data["MagneticEnergy"]
+
+    return data["TotalEnergy"] - 0.5*(
+        data["x-velocity"]**2.0
+        + data["y-velocity"]**2.0
+        + data["z-velocity"]**2.0 )
 add_field("ThermalEnergy", function=_ThermalEnergy,
           units=r"\rm{ergs}/\rm{g}")
 
@@ -171,22 +177,22 @@
 # We set up fields for both TotalEnergy and Total_Energy in the known fields
 # lists.  Note that this does not mean these will be the used definitions.
 add_enzo_field("TotalEnergy", function=NullFunc,
-          display_name = "$\rm{Total}\/\rm{Energy}$",
+          display_name = r"\rm{Total}\/ \rm{Energy}",
           units=r"\rm{ergs}/\rm{g}", convert_function=_convertEnergy)
 add_enzo_field("Total_Energy", function=NullFunc,
-          display_name = "$\rm{Total}\/\rm{Energy}$",
+          display_name = r"\rm{Total}\/ \rm{Energy}",
           units=r"\rm{ergs}/\rm{g}", convert_function=_convertEnergy)
 
 def _Total_Energy(field, data):
     return data["TotalEnergy"] / _convertEnergy(data)
 add_field("Total_Energy", function=_Total_Energy,
-          display_name = "$\rm{Total}\/\rm{Energy}$",
+          display_name = r"\rm{Total}\/ \rm{Energy}",
           units=r"\rm{ergs}/\rm{g}", convert_function=_convertEnergy)
 
 def _TotalEnergy(field, data):
     return data["Total_Energy"] / _convertEnergy(data)
 add_field("TotalEnergy", function=_TotalEnergy,
-          display_name = "$\rm{Total}\/\rm{Energy}$",
+          display_name = r"\rm{Total}\/ \rm{Energy}",
           units=r"\rm{ergs}/\rm{g}", convert_function=_convertEnergy)
 
 def _NumberDensity(field, data):
@@ -369,7 +375,7 @@
         if not filter.any(): return blank
         num = filter.sum()
     else:
-        filter = None
+        filter = Ellipsis
         num = data["particle_position_x"].size
     amr_utils.CICDeposit_3(data["particle_position_x"][filter].astype(np.float64),
                            data["particle_position_y"][filter].astype(np.float64),

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/pluto/api.py
--- /dev/null
+++ b/yt/frontends/pluto/api.py
@@ -0,0 +1,41 @@
+"""
+API for yt.frontends.pluto
+
+Author: Matthew Turk <matthewturk at gmail.com>
+Affiliation: UCSD
+Author: J.S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Author: Britton Smith <brittonsmith at gmail.com>
+Affiliation: MSU
+Homepage: http://yt.Chombotools.org/
+License:
+  Copyright (C) 2010-2011 Matthew Turk.  All Rights Reserved.
+
+  This file is part of yt.
+
+  yt is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from .data_structures import \
+      PlutoGrid, \
+      PlutoHierarchy, \
+      PlutoStaticOutput
+
+from .fields import \
+      PlutoFieldInfo, \
+      add_pluto_field
+
+from .io import \
+      IOHandlerChomboHDF5

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/pluto/data_structures.py
--- /dev/null
+++ b/yt/frontends/pluto/data_structures.py
@@ -0,0 +1,307 @@
+"""
+Data structures for Pluto.
+
+Author: Matthew Turk <matthewturk at gmail.com>
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2008-2011 Matthew Turk, J. S. Oishi.  All Rights Reserved.
+
+  This file is part of yt.
+
+  yt is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import h5py
+import re
+import os
+import weakref
+import numpy as np
+
+from collections import \
+     defaultdict
+from string import \
+     strip, \
+     rstrip
+from stat import \
+     ST_CTIME
+
+from .definitions import \
+     pluto2enzoDict, \
+     yt2plutoFieldsDict, \
+     parameterDict \
+
+from yt.funcs import *
+from yt.data_objects.grid_patch import \
+     AMRGridPatch
+from yt.data_objects.hierarchy import \
+     AMRHierarchy
+from yt.data_objects.static_output import \
+     StaticOutput
+from yt.utilities.definitions import \
+     mpc_conversion, sec_conversion
+from yt.utilities.parallel_tools.parallel_analysis_interface import \
+     parallel_root_only
+from yt.utilities.io_handler import \
+    io_registry
+
+from yt.data_objects.field_info_container import \
+    FieldInfoContainer, NullFunc
+from .fields import PlutoFieldInfo, KnownPlutoFields
+
+class PlutoGrid(AMRGridPatch):
+    _id_offset = 0
+    __slots__ = ["_level_id", "stop_index"]
+    def __init__(self, id, hierarchy, level, start, stop):
+        AMRGridPatch.__init__(self, id, filename = hierarchy.hierarchy_filename,
+                              hierarchy = hierarchy)
+        self.Parent = []
+        self.Children = []
+        self.Level = level
+        self.ActiveDimensions = stop - start + 1
+
+    def get_global_startindex(self):
+        """
+        Return the integer starting index for each dimension at the current
+        level.
+
+        """
+        if self.start_index != None:
+            return self.start_index
+        if self.Parent == []:
+            iLE = self.LeftEdge - self.pf.domain_left_edge
+            start_index = iLE / self.dds
+            return np.rint(start_index).astype('int64').ravel()
+        pdx = self.Parent[0].dds
+        start_index = (self.Parent[0].get_global_startindex()) + \
+            np.rint((self.LeftEdge - self.Parent[0].LeftEdge)/pdx)
+        self.start_index = (start_index*self.pf.refine_by).astype('int64').ravel()
+        return self.start_index
+
+    def _setup_dx(self):
+        # has already been read in and stored in hierarchy
+        self.dds = self.hierarchy.dds_list[self.Level]
+        self.field_data['dx'], self.field_data['dy'], self.field_data['dz'] = self.dds
+
+class PlutoHierarchy(AMRHierarchy):
+
+    grid = PlutoGrid
+
+    def __init__(self,pf,data_style='chombo_hdf5'):
+        self.domain_left_edge = pf.domain_left_edge
+        self.domain_right_edge = pf.domain_right_edge
+        self.data_style = data_style
+        self.field_indexes = {}
+        self.parameter_file = weakref.proxy(pf)
+        # for now, the hierarchy file is the parameter file!
+        self.hierarchy_filename = os.path.abspath(
+            self.parameter_file.parameter_filename)
+        self.directory = pf.fullpath
+        self._handle = pf._handle
+
+        self.float_type = self._handle['/level_0']['data:datatype=0'].dtype.name
+        self._levels = self._handle.keys()[2:]
+        AMRHierarchy.__init__(self,pf,data_style)
+
+    def _detect_fields(self):
+        ncomp = int(self._handle['/'].attrs['num_components'])
+        self.field_list = [c[1] for c in self._handle['/'].attrs.items()[-ncomp:]]
+          
+    def _setup_classes(self):
+        dd = self._get_data_reader_dict()
+        AMRHierarchy._setup_classes(self, dd)
+        self.object_types.sort()
+
+    def _count_grids(self):
+        self.num_grids = 0
+        for lev in self._levels:
+            self.num_grids += self._handle[lev]['Processors'].len()
+
+    def _parse_hierarchy(self):
+        f = self._handle # shortcut
+
+        # this relies on the first Group in the H5 file being
+        # 'Chombo_global' and the second 'Expressions'
+        levels = f.keys()[2:]
+        grids = []
+        self.dds_list = []
+        i = 0
+        for lev in levels:
+            level_number = int(re.match('level_(\d+)',lev).groups()[0])
+            boxes = f[lev]['boxes'].value
+            dx = f[lev].attrs['dx']
+            self.dds_list.append(dx * np.ones(3))
+            for level_id, box in enumerate(boxes):
+                si = np.array([box['lo_%s' % ax] for ax in 'ijk'])
+                ei = np.array([box['hi_%s' % ax] for ax in 'ijk'])
+                pg = self.grid(len(grids),self,level=level_number,
+                               start = si, stop = ei)
+                grids.append(pg)
+                grids[-1]._level_id = level_id
+                self.grid_left_edge[i] = dx*si.astype(self.float_type) + self.domain_left_edge
+                self.grid_right_edge[i] = dx*(ei.astype(self.float_type)+1) + self.domain_left_edge
+                self.grid_particle_count[i] = 0
+                self.grid_dimensions[i] = ei - si + 1
+                i += 1
+        self.grids = np.empty(len(grids), dtype='object')
+        for gi, g in enumerate(grids): self.grids[gi] = g
+#        self.grids = np.array(self.grids, dtype='object')
+
+    def _populate_grid_objects(self):
+        for g in self.grids:
+            g._prepare_grid()
+            g._setup_dx()
+
+        for g in self.grids:
+            g.Children = self._get_grid_children(g)
+            for g1 in g.Children:
+                g1.Parent.append(g)
+        self.max_level = self.grid_levels.max()
+
+    def _setup_derived_fields(self):
+        self.derived_field_list = []
+
+    def _get_grid_children(self, grid):
+        mask = np.zeros(self.num_grids, dtype='bool')
+        grids, grid_ind = self.get_box_grids(grid.LeftEdge, grid.RightEdge)
+        mask[grid_ind] = True
+        return [g for g in self.grids[mask] if g.Level == grid.Level + 1]
+
+    def _setup_data_io(self):
+        self.io = io_registry[self.data_style](self.parameter_file)
+
+class PlutoStaticOutput(StaticOutput):
+    _hierarchy_class = PlutoHierarchy
+    _fieldinfo_fallback = PlutoFieldInfo
+    _fieldinfo_known = KnownPlutoFields
+
+    def __init__(self, filename, data_style='chombo_hdf5',
+                 storage_filename = None, ini_filename = None):
+        self._handle = h5py.File(filename,'r')
+        self.current_time = self._handle.attrs['time']
+        self.ini_filename = ini_filename
+        self.fullplotdir = os.path.abspath(filename)
+        StaticOutput.__init__(self,filename,data_style)
+        self.storage_filename = storage_filename
+        self.cosmological_simulation = False
+
+        # These are parameters that I very much wish to get rid of.
+        self.parameters["HydroMethod"] = 'chombo' # always PPM DE
+        self.parameters["DualEnergyFormalism"] = 0 
+        self.parameters["EOSType"] = -1 # default
+
+    def __del__(self):
+        self._handle.close()
+
+    def _set_units(self):
+        """
+        Generates the conversion to various physical _units based on the parameter file
+        """
+        self.units = {}
+        self.time_units = {}
+        if len(self.parameters) == 0:
+            self._parse_parameter_file()
+        self._setup_nounits_units()
+        self.conversion_factors = defaultdict(lambda: 1.0)
+        self.time_units['1'] = 1
+        self.units['1'] = 1.0
+        self.units['unitary'] = 1.0 / (self.domain_right_edge - self.domain_left_edge).max()
+        seconds = 1 #self["Time"]
+        for unit in sec_conversion.keys():
+            self.time_units[unit] = seconds / sec_conversion[unit]
+        for key in yt2plutoFieldsDict:
+            self.conversion_factors[key] = 1.0
+
+    def _setup_nounits_units(self):
+        z = 0
+        mylog.warning("Setting 1.0 in code units to be 1.0 cm")
+        if not self.has_key("TimeUnits"):
+            mylog.warning("No time units.  Setting 1.0 = 1 second.")
+            self.conversion_factors["Time"] = 1.0
+        for unit in mpc_conversion.keys():
+            self.units[unit] = mpc_conversion[unit] / mpc_conversion["cm"]
+
+
+    def _localize(self, f, default):
+        if f is None:
+            return os.path.join(self.directory, default)
+        return f
+
+    def _parse_parameter_file(self):
+        """
+        Reads in an inputs file in the 'pluto.ini' format. Probably not
+        especially robust at the moment.
+        """
+
+        ini_filename = 'pluto.ini'
+        self.fullplotdir = os.path.abspath(self.parameter_filename)
+        self.ini_filename = self._localize( \
+            self.ini_filename, ini_filename)
+        self.unique_identifier = \
+                               int(os.stat(self.parameter_filename)[ST_CTIME])
+        lines = open(self.ini_filename).readlines()
+        # read the file line by line, storing important parameters
+        for lineI, line in enumerate(lines):
+            try:
+                param, sep, vals = map(rstrip,line.partition(' '))
+            except ValueError:
+                mylog.error("ValueError: '%s'", line)
+            if pluto2enzoDict.has_key(param):
+                paramName = pluto2enzoDict[param]
+                t = map(parameterDict[paramName], vals.split())
+                if len(t) == 1:
+                    self.parameters[paramName] = t[0]
+                else:
+                    if paramName == "RefineBy":
+                        self.parameters[paramName] = t[0]
+                    else:
+                        self.parameters[paramName] = t
+
+            # assumes 3D for now
+            elif param.startswith("X1-grid"):
+                t = vals.split()
+                low1 = float(t[1])
+                high1 = float(t[4])
+                N1 = int(t[2])
+            elif param.startswith("X2-grid"):
+                t = vals.split()
+                low2 = float(t[1])
+                high2 = float(t[4])
+                N2 = int(t[2])
+            elif param.startswith("X3-grid"):
+                t = vals.split()
+                low3 = float(t[1])
+                high3 = float(t[4])
+                N3 = int(t[2])
+            
+        self.dimensionality = 3
+        self.domain_left_edge = np.array([low1,low2,low3])
+        self.domain_right_edge = np.array([high1,high2,high3])
+        self.domain_dimensions = np.array([N1,N2,N3])
+        self.refine_by = self.parameters["RefineBy"]
+            
+    @classmethod
+    def _is_valid(self, *args, **kwargs):
+        return os.path.isfile('pluto.ini')
+
+    @parallel_root_only
+    def print_key_parameters(self):
+        for a in ["current_time", "domain_dimensions", "domain_left_edge",
+                  "domain_right_edge"]:
+            if not hasattr(self, a):
+                mylog.error("Missing %s in parameter file definition!", a)
+                continue
+            v = getattr(self, a)
+            mylog.info("Parameters: %-25s = %s", a, v)

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/pluto/definitions.py
--- /dev/null
+++ b/yt/frontends/pluto/definitions.py
@@ -0,0 +1,65 @@
+"""
+Various definitions for various other modules and routines
+
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2008-2011 J.S. Oishi.  All Rights Reserved.
+
+  This file is part of yt.
+
+  yt is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+parameterDict = {"CosmologyCurrentRedshift": float,
+                 "CosmologyComovingBoxSize": float,
+                 "CosmologyOmegaMatterNow": float,
+                 "CosmologyOmegaLambdaNow": float,
+                 "CosmologyHubbleConstantNow": float,
+                 "CosmologyInitialRedshift": float,
+                 "DualEnergyFormalismEta1": float,
+                 "DualEnergyFormalismEta2": float,
+                 "MetaDataString": str,
+                 "HydroMethod": int,
+                 "DualEnergyFormalism": int,
+                 "InitialTime": float,
+                 "ComovingCoordinates": int,
+                 "DensityUnits": float,
+                 "LengthUnits": float,
+                 "LengthUnit": float,
+                 "TemperatureUnits": float,
+                 "TimeUnits": float,
+                 "GravitationalConstant": float,
+                 "Gamma": float,
+                 "MultiSpecies": int,
+                 "CompilerPrecision": str,
+                 "CurrentTimeIdentifier": int,
+                 "RefineBy": int,
+                 "BoundaryConditionName": str,
+                 "TopGridRank": int,
+                 "TopGridDimensions": int,
+                 "EOSSoundSpeed": float,
+                 "EOSType": int,
+                 "NumberOfParticleAttributes": int,
+                                 }
+
+pluto2enzoDict = {"GAMMA": "Gamma",
+                  "Ref_ratio": "RefineBy"
+                                    }
+
+yt2plutoFieldsDict = {}
+pluto2ytFieldsDict = {}
+

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/pluto/fields.py
--- /dev/null
+++ b/yt/frontends/pluto/fields.py
@@ -0,0 +1,97 @@
+"""
+Pluto-specific fields
+
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2009-2011 J. S. Oishi, Matthew Turk.  All Rights Reserved.
+
+  This file is part of yt.
+
+  yt is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+from yt.data_objects.field_info_container import \
+    FieldInfoContainer, \
+    FieldInfo, \
+    NullFunc, \
+    ValidateParameter, \
+    ValidateDataField, \
+    ValidateProperty, \
+    ValidateSpatial, \
+    ValidateGridType
+import yt.data_objects.universal_fields
+import numpy as np
+
+KnownPlutoFields = FieldInfoContainer()
+add_pluto_field = KnownPlutoFields.add_field
+
+PlutoFieldInfo = FieldInfoContainer.create_with_fallback(FieldInfo)
+add_field = PlutoFieldInfo.add_field
+
+add_pluto_field("rho", function=NullFunc, take_log=True,
+                 validators = [ValidateDataField("density")],
+                 units=r"\rm{g}/\rm{cm}^3")
+
+KnownPlutoFields["rho"]._projected_units =r"\rm{g}/\rm{cm}^2"
+
+add_pluto_field("vx1", function=NullFunc, take_log=False,
+                 validators = [ValidateDataField("X-Momentum")],
+                 units=r"",display_name=r"M_x")
+KnownPlutoFields["vx1"]._projected_units=r""
+
+add_pluto_field("vx2", function=NullFunc, take_log=False,
+                 validators = [ValidateDataField("Y-Momentum")],
+                 units=r"",display_name=r"M_y")
+KnownPlutoFields["vx2"]._projected_units=r""
+
+add_pluto_field("vx3", function=NullFunc, take_log=False,
+                 validators = [ValidateDataField("Z-Momentum")],
+                 units=r"",display_name=r"M_z")
+KnownPlutoFields["vx3"]._projected_units=r""
+
+add_pluto_field("prs", function=NullFunc, take_log=True,
+                 validators = [ValidateDataField("energy-density")],
+                 units=r"\rm{erg}/\rm{cm}^3")
+
+def _Density(field,data):
+    """A duplicate of the density field. This is needed because when you try 
+    to instantiate a PlotCollection without passing in a center, the code
+    will try to generate one for you using the "Density" field, which gives an error 
+    if it isn't defined.
+
+    """
+    return data["rho"]
+add_field("Density",function=_Density, take_log=True,
+          units=r'\rm{g}/\rm{cm^3}')
+
+def _Xmomentum(field, data):
+    """ Generate x-momentum. """
+    return data["vx1"]*data["density"]
+add_field("X-momentum",function=_Xmomentum, take_log=False,
+          units=r'\rm{g}/\rm{cm^2 s}')
+
+def _Ymomentum(field, data):
+    """ Generate y-momentum  """
+    return data["vx2"]*data["density"]
+add_field("Y-momentum",function=_Ymomentum, take_log=False,
+          units=r'\rm{g}/\rm{cm^2 s}')
+
+def _Zmomentum(field,data):
+    """ Generate z-momentum"""
+    return data["vx3"]*data["density"]
+add_field("Z-Momentum",function=_Zmomentum, take_log=False,
+          units=r'\rm{g}/\rm{cm^2 s}')
+

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/pluto/io.py
--- /dev/null
+++ b/yt/frontends/pluto/io.py
@@ -0,0 +1,73 @@
+"""
+The data-file handling functions
+
+Author: Matthew Turk <matthewturk at gmail.com>
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2007-2011 Matthew Turk.  All Rights Reserved.
+
+  This file is part of yt.
+
+  yt is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+import h5py
+import os
+import re
+import numpy as np
+
+from yt.utilities.io_handler import \
+           BaseIOHandler
+
+class IOHandlerChomboHDF5(BaseIOHandler):
+    _data_style = "chombo_hdf5"
+    _offset_string = 'data:offsets=0'
+    _data_string = 'data:datatype=0'
+
+    def __init__(self, pf, *args, **kwargs):
+        BaseIOHandler.__init__(self, *args, **kwargs)
+        self.pf = pf
+        self._handle = pf._handle
+
+    _field_dict = None
+    @property
+    def field_dict(self):
+        if self._field_dict is not None:
+            return self._field_dict
+        ncomp = int(self._handle['/'].attrs['num_components'])
+        temp =  self._handle['/'].attrs.items()[-ncomp:]
+        val, keys = zip(*temp)
+        val = [int(re.match('component_(\d+)',v).groups()[0]) for v in val]
+        self._field_dict = dict(zip(keys,val))
+        return self._field_dict
+        
+    def _read_field_names(self,grid):
+        ncomp = int(self._handle['/'].attrs['num_components'])
+
+        fns = [c[1] for c in f['/'].attrs.items()[-ncomp-1:-1]]
+    
+    def _read_data(self,grid,field):
+
+        lstring = 'level_%i' % grid.Level
+        lev = self._handle[lstring]
+        dims = grid.ActiveDimensions
+        boxsize = dims.prod()
+        
+        grid_offset = lev[self._offset_string][grid._level_id]
+        start = grid_offset+self.field_dict[field]*boxsize
+        stop = start + boxsize
+        data = lev[self._data_string][start:stop]
+        
+        return data.reshape(dims, order='F')

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/pluto/setup.py
--- /dev/null
+++ b/yt/frontends/pluto/setup.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+import setuptools
+import os
+import sys
+import os.path
+
+
+def configuration(parent_package='', top_path=None):
+    from numpy.distutils.misc_util import Configuration
+    config = Configuration('pluto', parent_package, top_path)
+    config.make_config_py()  # installs __config__.py
+    #config.make_svn_version_py()
+    return config

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/setup.py
--- a/yt/frontends/setup.py
+++ b/yt/frontends/setup.py
@@ -20,4 +20,5 @@
     config.add_subpackage("maestro")
     config.add_subpackage("castro")
     config.add_subpackage("stream")
+    config.add_subpackage("pluto")
     return config

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -25,6 +25,7 @@
 
 import weakref
 import numpy as np
+import uuid
 
 from yt.utilities.io_handler import io_registry
 from yt.funcs import *
@@ -302,7 +303,10 @@
         #self._conversion_override = conversion_override
 
         self.stream_handler = stream_handler
-        StaticOutput.__init__(self, "InMemoryParameterFile", self._data_style)
+        name = "InMemoryParameterFile_%s" % (uuid.uuid4().hex)
+        from yt.data_objects.static_output import _cached_pfs
+        _cached_pfs[name] = self
+        StaticOutput.__init__(self, name, self._data_style)
 
         self.units = {}
         self.time_units = {}

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/mods.py
--- a/yt/mods.py
+++ b/yt/mods.py
@@ -102,6 +102,9 @@
 from yt.frontends.art.api import \
     ARTStaticOutput, ARTFieldInfo, add_art_field
 
+from yt.frontends.pluto.api import \
+     PlutoStaticOutput, PlutoFieldInfo, add_pluto_field
+
 #from yt.frontends.maestro.api import \
 #    MaestroStaticOutput, MaestroFieldInfo, add_maestro_field
 

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/utilities/decompose.py
--- a/yt/utilities/decompose.py
+++ b/yt/utilities/decompose.py
@@ -69,8 +69,8 @@
     """ Evaluate longest to shortest edge ratio
         BEWARE: lot's of magic here """
     eff_dim = (n_d > 1).sum()
-    ideal_bsize = eff_dim * (pieces * np.product(n_d) ** (eff_dim - 1)
-                             ) ** (1.0 / eff_dim)
+    exp = float(eff_dim - 1) / float(eff_dim)
+    ideal_bsize = eff_dim * pieces ** (1.0 / eff_dim) * np.product(n_d) ** exp
     mask = np.where(n_d > 1)
     nd_arr = np.array(n_d, dtype=np.float64)[mask]
     bsize = int(np.sum(ldom[mask] / nd_arr * np.product(nd_arr)))
@@ -109,6 +109,10 @@
     fac = factorize_number(pieces)
     nfactors = len(fac[:, 2])
     best = 0.0
+    p_size = np.ones(3, dtype=np.int)
+    if pieces == 1:
+        return p_size
+
     while np.all(fac[:, 2] > 0):
         ldom = np.ones(3, dtype=np.int)
         for nfac in range(nfactors):

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/utilities/definitions.py
--- a/yt/utilities/definitions.py
+++ b/yt/utilities/definitions.py
@@ -48,7 +48,8 @@
 y_names = ['z','z','y']
 
 # How many of each thing are in an Mpc
-mpc_conversion = {'mpc'   : mpc_per_mpc,
+mpc_conversion = {'Mpc'   : mpc_per_mpc,
+                  'mpc'   : mpc_per_mpc,
                   'kpc'   : kpc_per_mpc,
                   'pc'    : pc_per_mpc,
                   'au'    : au_per_mpc,
@@ -56,7 +57,7 @@
                   'miles' : miles_per_mpc,
                   'cm'    : cm_per_mpc}
 
-# How many seconds are in each thig
+# How many seconds are in each thing
 sec_conversion = {'Gyr'   : sec_per_Gyr,
                   'Myr'   : sec_per_Myr,
                   'years' : sec_per_year,

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/utilities/grid_data_format/writer.py
--- a/yt/utilities/grid_data_format/writer.py
+++ b/yt/utilities/grid_data_format/writer.py
@@ -57,7 +57,7 @@
     # don't forget to close the file.
     f.close()
 
-def save_field(pf, field_name):
+def save_field(pf, field_name, field_parameters=None):
     """
     Write a single field associated with the parameter file pf to the
     backup file.
@@ -68,6 +68,8 @@
         The yt parameter file that the field is associated with.
     field_name : string
         The name of the field to save.
+    field_parameters : dictionary
+        A dictionary of field parameters to set.
     """
 
     field_obj = pf.field_info[field_name]
@@ -85,12 +87,12 @@
                        particle_type_name="dark_matter")
 
     # now save the field
-    _write_field_to_gdf(pf, f, field_name, particle_type_name="dark_matter")
+    _write_field_to_gdf(pf, f, field_name, particle_type_name="dark_matter", field_parameters=field_parameters)
 
     # don't forget to close the file.
     f.close()
         
-def _write_field_to_gdf(pf, fhandle, field_name, particle_type_name):
+def _write_field_to_gdf(pf, fhandle, field_name, particle_type_name, field_parameters=None):
 
     # add field info to field_types group
     g = fhandle["field_types"]
@@ -122,6 +124,12 @@
     # now add actual data, grid by grid
     g = fhandle["data"]     
     for grid in pf.h.grids:
+
+        # set field parameters, if specified
+        if field_parameters is not None:
+            for k,v in field_parameters.iteritems():
+                grid.set_field_parameter(k,v)
+
         grid_group = g["grid_%010i" % (grid.id - grid._id_offset)]
         particles_group = grid_group["particles"]
         pt_group = particles_group[particle_type_name]

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -63,6 +63,7 @@
 # time
 sec_per_Gyr  = 31.5576e15
 sec_per_Myr  = 31.5576e12
+sec_per_kyr  = 31.5576e9
 sec_per_year = 31.5576e6   # "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -40,6 +40,11 @@
     y_dict, y_names, \
     axis_names, \
     axis_labels
+from yt.utilities.physical_constants import \
+    sec_per_Gyr, sec_per_Myr, \
+    sec_per_kyr, sec_per_year, \
+    sec_per_day, sec_per_hr
+
 import _MPL
 
 callback_registry = {}
@@ -1204,15 +1209,18 @@
           'min': 60.0,
           'minute': 60.0,
           'minutes': 60.0,
-          'h': 3600.0,
-          'hour': 3600.0,
-          'hours': 3600.0,
-          'd': 86400.0,
-          'day': 86400.0,
-          'days': 86400.0,
-          'y': 86400.0*365.25,
-          'year': 86400.0*365.25,
-          'years': 86400.0*365.25,
+          'h': sec_per_hr,
+          'hour': sec_per_hr,
+          'hours': sec_per_hr,
+          'd': sec_per_day,
+          'day': sec_per_day,
+          'days': sec_per_day,
+          'y': sec_per_year,
+          'year': sec_per_year,
+          'years': sec_per_year,
+          'kyr': sec_per_kyr,
+          'myr': sec_per_Myr,
+          'gyr': sec_per_Gyr,
           'ev': 1e-9 * 7.6e-8 / 6.03,
           'kev': 1e-12 * 7.6e-8 / 6.03,
           'mev': 1e-15 * 7.6e-8 / 6.03,
@@ -1230,13 +1238,14 @@
             self.bbox_dict = bbox_dict
         else:
             self.bbox_dict = self._bbox_dict
-        self.kwargs = {'color': 'w'}
+        self.kwargs = {'color': 'k'}
         self.kwargs.update(kwargs)
 
     def __call__(self, plot):
         if self.units is None:
             t = plot.data.pf.current_time * plot.data.pf['Time']
-            scale_keys = ['as', 'fs', 'ps', 'ns', 'us', 'ms', 's']
+            scale_keys = ['as', 'fs', 'ps', 'ns', 'us', 'ms', 's', 
+                          'hour', 'day', 'year', 'kyr', 'myr', 'gyr']
             self.units = 's'
             for k in scale_keys:
                 if t < self._time_conv[k]:

diff -r 7e5edbc1482c0a52360fb28ecd360da0c11eb2a7 -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -65,6 +65,7 @@
     ortho_find
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
     GroupOwnership
+from yt.utilities.exceptions import YTUnitNotRecognized
 from yt.data_objects.time_series import \
     TimeSeriesData
 
@@ -726,6 +727,8 @@
         """
         # blind except because it could be in conversion_factors or units
         if unit_name is not None:
+            if isinstance(unit_name, str):
+                unit_name = (unit_name, unit_name)
             for un in unit_name:
                 try:
                     self.pf[un]


https://bitbucket.org/yt_analysis/yt/commits/34a5e6774ceb/
Changeset:   34a5e6774ceb
Branch:      stable
User:        MatthewTurk
Date:        2013-03-29 11:51:18
Summary:     Updating version string
Affected #:  1 file

diff -r 7e0900e6fa901b693adc93574f7b217ddf73ed36 -r 34a5e6774ceb26896c9d767563951d185a720774 setup.py
--- a/setup.py
+++ b/setup.py
@@ -155,7 +155,7 @@
 
 import setuptools
 
-VERSION = "2.5"
+VERSION = "2.5.1"
 
 if os.path.exists('MANIFEST'):
     os.remove('MANIFEST')


https://bitbucket.org/yt_analysis/yt/commits/8dce70a9c689/
Changeset:   8dce70a9c689
Branch:      stable
User:        MatthewTurk
Date:        2013-03-29 11:51:24
Summary:     Added tag yt-2.5.1 for changeset 34a5e6774ceb
Affected #:  1 file

diff -r 34a5e6774ceb26896c9d767563951d185a720774 -r 8dce70a9c68991ef8c16b1f45244393508c36b0f .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -5163,3 +5163,4 @@
 3836676ee6307f9caf5ccdb0f0dd373676a68535 yt-2.3
 076cec2c57d2e4b508babbfd661f5daa1e34ec80 yt-2.4
 bd285a9a8a643ebb7b47b543e9343da84cd294c5 yt-2.5
+34a5e6774ceb26896c9d767563951d185a720774 yt-2.5.1

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