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

Bitbucket commits-noreply at bitbucket.org
Wed Sep 5 11:45:04 PDT 2012


5 new commits in yt:


https://bitbucket.org/yt_analysis/yt/changeset/77b5e3d096f5/
changeset:   77b5e3d096f5
branch:      yt
user:        samskillman
date:        2012-09-04 20:52:47
summary:     Remove axes unit label if units are '1', 'u', or 'unitary'. x(1) and y(1) look strange.
affected #:  1 file

diff -r 37540bd65173d499ac8d6397496e716753af2145 -r 77b5e3d096f57a4b11738e5fc268643ba70d4c84 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -657,13 +657,18 @@
             self.plots[f].cb = self.plots[f].figure.colorbar(
                 self.plots[f].image, cax = self.plots[f].cax)
 
+            if not md['unit'] in ['1', 'u', 'unitary']:
+                axes_unit_label = '\/\/('+md['unit'].encode('string-escape')+')'
+            else:
+                axes_unit_label = ''
+
             if self.oblique == False:
                 labels = [r'$\rm{'+axis_labels[axis_index][i].encode('string-escape')+
-                          r'\/\/('+md['unit'].encode('string-escape')+r')}$' for i in (0,1)]
+                        axes_unit_label + r'}$' for i in (0,1)]
             else:
-                labels = [r'$\rm{Image\/x}\/\/\rm{('+md['unit'].encode('string-escape')+r')}$',
-                          r'$\rm{Image\/y}\/\/\rm{('+md['unit'].encode('string-escape')+r')}$']
-                
+                labels = [r'$\rm{Image\/x'+axes_unit_label+'}$',
+                          r'$\rm{Image\/y'+axes_unit_label+'}$']
+
             self.plots[f].axes.set_xlabel(labels[0])
             self.plots[f].axes.set_ylabel(labels[1])
 



https://bitbucket.org/yt_analysis/yt/changeset/dd83c8b4e977/
changeset:   dd83c8b4e977
branch:      yt
user:        samskillman
date:        2012-09-05 18:16:56
summary:     Merging.
affected #:  4 files

diff -r 77b5e3d096f57a4b11738e5fc268643ba70d4c84 -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -28,7 +28,7 @@
 """
 
 import h5py
-import numpy as na
+import numpy as np
 import weakref
 from yt.funcs import *
 from yt.data_objects.grid_patch import \
@@ -43,7 +43,6 @@
 from .fields import AthenaFieldInfo, KnownAthenaFields
 from yt.data_objects.field_info_container import \
     FieldInfoContainer, NullFunc
-import pdb
 
 def _get_convert(fname):
     def _conv(data):
@@ -54,10 +53,13 @@
     _id_offset = 0
     def __init__(self, id, hierarchy, level, start, dimensions):
         df = hierarchy.storage_filename
-        if id == 0:
-            gname = 'id0/' + df + '.vtk'
+        if 'id0' not in hierarchy.parameter_file.filename:
+            gname = hierarchy.parameter_file.filename
         else:
-            gname = 'id%i/' % id + df[:-5] + '-id%i'%id + df[-5:] + '.vtk'
+            if id == 0:
+                gname = 'id0/%s.vtk' % df
+            else:
+                gname = 'id%i/%s-id%i%s.vtk' % (id, df[:-5], id, df[-5:] )
         AMRGridPatch.__init__(self, id, filename = gname,
                               hierarchy = hierarchy)
         self.filename = gname
@@ -77,7 +79,7 @@
         else:
             LE, RE = self.hierarchy.grid_left_edge[id,:], \
                      self.hierarchy.grid_right_edge[id,:]
-            self.dds = na.array((RE-LE)/self.ActiveDimensions)
+            self.dds = np.array((RE-LE)/self.ActiveDimensions)
         if self.pf.dimensionality < 2: self.dds[1] = 1.0
         if self.pf.dimensionality < 3: self.dds[2] = 1.0
         self.field_data['dx'], self.field_data['dy'], self.field_data['dz'] = self.dds
@@ -89,16 +91,16 @@
         grid['vtk_version'] = splitup[-1]
     elif "Really" in splitup:
         grid['time'] = splitup[-1]
-    elif 'PRIMITIVE' in splitup:
+    elif any(x in ['PRIMITIVE','CONSERVED'] for x in splitup):
         grid['time'] = float(splitup[4].rstrip(','))
         grid['level'] = int(splitup[6].rstrip(','))
         grid['domain'] = int(splitup[8].rstrip(','))
     elif "DIMENSIONS" in splitup:
-        grid['dimensions'] = na.array(splitup[-3:]).astype('int')
+        grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:
-        grid['left_edge'] = na.array(splitup[-3:]).astype('float64')
+        grid['left_edge'] = np.array(splitup[-3:]).astype('float64')
     elif "SPACING" in splitup:
-        grid['dds'] = na.array(splitup[-3:]).astype('float64')
+        grid['dds'] = np.array(splitup[-3:]).astype('float64')
     elif "CELL_DATA" in splitup:
         grid["ncells"] = int(splitup[-1])
     elif "SCALARS" in splitup:
@@ -110,8 +112,6 @@
         grid['read_field'] = field
         grid['read_type'] = 'vector'
 
-
-
 class AthenaHierarchy(AMRHierarchy):
 
     grid = AthenaGrid
@@ -125,7 +125,7 @@
         self.hierarchy_filename = self.parameter_file.filename
         #self.directory = os.path.dirname(self.hierarchy_filename)
         self._fhandle = file(self.hierarchy_filename,'rb')
-        AMRHierarchy.__init__(self,pf,data_style)
+        AMRHierarchy.__init__(self, pf, data_style)
 
         self._fhandle.close()
 
@@ -139,49 +139,41 @@
         while line != '':
             splitup = line.strip().split()
             if "DIMENSIONS" in splitup:
-                grid_dims = na.array(splitup[-3:]).astype('int')
+                grid_dims = np.array(splitup[-3:]).astype('int')
                 line = f.readline()
-                continue
             elif "CELL_DATA" in splitup:
                 grid_ncells = int(splitup[-1])
                 line = f.readline()
-                if na.prod(grid_dims) != grid_ncells:
+                if np.prod(grid_dims) != grid_ncells:
                     grid_dims -= 1
                     grid_dims[grid_dims==0]=1
-                if na.prod(grid_dims) != grid_ncells:
-                    mylog.error('product of dimensions %i not equal to number of cells %i' % 
-                          (na.prod(grid_dims), grid_ncells))
+                if np.prod(grid_dims) != grid_ncells:
+                    mylog.error('product of dimensions %i not equal to number of cells %i' %
+                          (np.prod(grid_dims), grid_ncells))
                     raise TypeError
                 break
             else:
-                del line
                 line = f.readline()
         read_table = False
         read_table_offset = f.tell()
         while line != '':
-            if len(line) == 0: break
             splitup = line.strip().split()
             if 'SCALARS' in splitup:
                 field = splitup[1]
                 if not read_table:
                     line = f.readline() # Read the lookup table line
                     read_table = True
-                field_map[field] = 'scalar',f.tell() - read_table_offset
+                field_map[field] = ('scalar', f.tell() - read_table_offset)
                 read_table=False
 
             elif 'VECTORS' in splitup:
                 field = splitup[1]
-                vfield = field+'_x'
-                field_map[vfield] = 'vector',f.tell() - read_table_offset
-                vfield = field+'_y'
-                field_map[vfield] = 'vector',f.tell() - read_table_offset
-                vfield = field+'_z'
-                field_map[vfield] = 'vector',f.tell() - read_table_offset
-            del line
+                for ax in 'xyz':
+                    field_map["%s_%s" % (field, ax)] =\
+                            ('vector', f.tell() - read_table_offset)
             line = f.readline()
 
         f.close()
-        del f
 
         self.field_list = field_map.keys()
         self._field_map = field_map
@@ -210,50 +202,48 @@
             if 'TABLE' in line.strip().split():
                 break
             if len(line) == 0: break
-            del line
             line = f.readline()
         f.close()
-        del f
 
-        if na.prod(grid['dimensions']) != grid['ncells']:
+        # It seems some datasets have a mismatch between ncells and 
+        # the actual grid dimensions.
+        if np.prod(grid['dimensions']) != grid['ncells']:
             grid['dimensions'] -= 1
             grid['dimensions'][grid['dimensions']==0]=1
-        if na.prod(grid['dimensions']) != grid['ncells']:
+        if np.prod(grid['dimensions']) != grid['ncells']:
             mylog.error('product of dimensions %i not equal to number of cells %i' % 
-                  (na.prod(grid['dimensions']), grid['ncells']))
+                  (np.prod(grid['dimensions']), grid['ncells']))
             raise TypeError
 
         dxs=[]
-        self.grids = na.empty(self.num_grids, dtype='object')
-        levels = na.zeros(self.num_grids, dtype='int32')
+        self.grids = np.empty(self.num_grids, dtype='object')
+        levels = np.zeros(self.num_grids, dtype='int32')
         single_grid_width = grid['dds']*grid['dimensions']
         grids_per_dim = (self.parameter_file.domain_width/single_grid_width).astype('int32')
-        glis = na.empty((self.num_grids,3), dtype='int64')
+        glis = np.empty((self.num_grids,3), dtype='int64')
         for i in range(self.num_grids):
             procz = i/(grids_per_dim[0]*grids_per_dim[1])
             procy = (i - procz*(grids_per_dim[0]*grids_per_dim[1]))/grids_per_dim[0]
-            procx = i - procz*(grids_per_dim[0]*grids_per_dim[1]) - procy*grids_per_dim[1]
+            procx = i - procz*(grids_per_dim[0]*grids_per_dim[1]) - procy*grids_per_dim[0]
             glis[i, 0] = procx*grid['dimensions'][0]
             glis[i, 1] = procy*grid['dimensions'][1]
             glis[i, 2] = procz*grid['dimensions'][2]
-        gdims = na.ones_like(glis)
+        gdims = np.ones_like(glis)
         gdims[:] = grid['dimensions']
         for i in range(levels.shape[0]):
             self.grids[i] = self.grid(i, self, levels[i],
                                       glis[i],
                                       gdims[i])
-            self.grids[i]._level_id = levels[i]
 
             dx = (self.parameter_file.domain_right_edge-
                   self.parameter_file.domain_left_edge)/self.parameter_file.domain_dimensions
             dx = dx/self.parameter_file.refine_by**(levels[i])
             dxs.append(grid['dds'])
-        dx = na.array(dxs)
+        dx = np.array(dxs)
         self.grid_left_edge = self.parameter_file.domain_left_edge + dx*glis
         self.grid_dimensions = gdims.astype("int32")
         self.grid_right_edge = self.grid_left_edge + dx*self.grid_dimensions
-        self.grid_particle_count = na.zeros([self.num_grids, 1], dtype='int64')
-        del levels, glis, gdims
+        self.grid_particle_count = np.zeros([self.num_grids, 1], dtype='int64')
 
     def _populate_grid_objects(self):
         for g in self.grids:
@@ -266,11 +256,11 @@
                 g1.Parent.append(g)
         self.max_level = self.grid_levels.max()
 
-    def _setup_derived_fields(self):
-        self.derived_field_list = []
+#     def _setup_derived_fields(self):
+#         self.derived_field_list = []
 
     def _get_grid_children(self, grid):
-        mask = na.zeros(self.num_grids, dtype='bool')
+        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]
@@ -283,10 +273,10 @@
 
     def __init__(self, filename, data_style='athena',
                  storage_filename = None, parameters = {}):
+        self.specified_parameters = parameters
         StaticOutput.__init__(self, filename, data_style)
         self.filename = filename
         self.storage_filename = filename[4:-4]
-        self.specified_parameters = parameters
 
     def _set_units(self):
         """
@@ -296,42 +286,16 @@
         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['cm'] = 1.0
         self.units['unitary'] = 1.0 / (self.domain_right_edge - self.domain_left_edge).max()
+
+    def _setup_nounits_units(self):
+        self.conversion_factors["Time"] = 1.0
         for unit in mpc_conversion.keys():
-            self.units[unit] = 1.0 * mpc_conversion[unit] / mpc_conversion["cm"]
-        for unit in sec_conversion.keys():
-            self.time_units[unit] = 1.0 / sec_conversion[unit]
-
-        # Here should read through and add fields.
-
-        #default_fields=['density']
-        # for field in self.field_list:
-        #     self.units[field] = 1.0
-        #     self._fieldinfo_known.add_field(field, function=NullFunc, take_log=False,
-        #             units="", projected_units="",
-        #             convert_function=None)
-
-        # This should be improved.
-        # self._handle = h5py.File(self.parameter_filename, "r")
-        # for field_name in self._handle["/field_types"]:
-        #     current_field = self._handle["/field_types/%s" % field_name]
-        #     try:
-        #         self.units[field_name] = current_field.attrs['field_to_cgs']
-        #     except:
-        #         self.units[field_name] = 1.0
-        #     try:
-        #         current_fields_unit = current_field.attrs['field_units'][0]
-        #     except:
-        #         current_fields_unit = ""
-        #     self._fieldinfo_known.add_field(field_name, function=NullFunc, take_log=False,
-        #            units=current_fields_unit, projected_units="", 
-        #            convert_function=_get_convert(field_name))
-
-        # self._handle.close()
-        # del self._handle
+            self.units[unit] = mpc_conversion[unit] / mpc_conversion["cm"]
 
     def _parse_parameter_file(self):
         self._handle = open(self.parameter_filename, "rb")
@@ -348,11 +312,15 @@
             if 'TABLE' in line.strip().split():
                 break
             if len(line) == 0: break
-            del line
             line = self._handle.readline()
 
         self.domain_left_edge = grid['left_edge']
-        self.domain_right_edge = -grid['left_edge']
+        if 'domain_right_edge' in self.specified_parameters:
+            self.domain_right_edge = np.array(self.specified_parameters['domain_right_edge'])
+        else:
+            mylog.info("Please set 'domain_right_edge' in parameters dictionary argument " +
+                    "if it is not equal to -domain_left_edge.")
+            self.domain_right_edge = -self.domain_left_edge
         self.domain_width = self.domain_right_edge-self.domain_left_edge
         self.domain_dimensions = self.domain_width/grid['dds']
         refine_by = None
@@ -360,32 +328,24 @@
         self.refine_by = refine_by
         self.dimensionality = 3
         self.current_time = grid["time"]
-        self.unique_identifier = None
+        self.unique_identifier = self._handle.__hash__()
         self.cosmological_simulation = False
         self.num_ghost_zones = 0
         self.field_ordering = 'fortran'
         self.boundary_conditions = [1]*6
 
-        self.nvtk = int(na.product(self.domain_dimensions/(grid['dimensions']-1)))
+        self.nvtk = int(np.product(self.domain_dimensions/(grid['dimensions']-1)))
 
-        # if self.cosmological_simulation:
-        #     self.current_redshift = sp["current_redshift"]
-        #     self.omega_lambda = sp["omega_lambda"]
-        #     self.omega_matter = sp["omega_matter"]
-        #     self.hubble_constant = sp["hubble_constant"]
-        # else:
         self.current_redshift = self.omega_lambda = self.omega_matter = \
             self.hubble_constant = self.cosmological_simulation = 0.0
         self.parameters['Time'] = self.current_time # Hardcode time conversion for now.
         self.parameters["HydroMethod"] = 0 # Hardcode for now until field staggering is supported.
         self._handle.close()
-        del self._handle
 
     @classmethod
     def _is_valid(self, *args, **kwargs):
         try:
-            fileh = file(args[0],'rb')
-            if "gridded_data_format" in fileh:
+            if 'vtk' in args[0]:
                 return True
         except:
             pass


diff -r 77b5e3d096f57a4b11738e5fc268643ba70d4c84 -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 yt/frontends/athena/fields.py
--- a/yt/frontends/athena/fields.py
+++ b/yt/frontends/athena/fields.py
@@ -38,16 +38,16 @@
     TranslationFunc
 import yt.data_objects.universal_fields
 
-log_translation_dict = {"Density": "density",
-                        "Pressure": "pressure"}
+log_translation_dict = {}
 
-translation_dict = {"x-velocity": "velocity_x",
+translation_dict = {"Density": "density",
+                    "Pressure": "pressure",
+                    "x-velocity": "velocity_x",
                     "y-velocity": "velocity_y",
-                    "z-velocity": "velocity_z"}
-                    
-# translation_dict = {"mag_field_x": "cell_centered_B_x ",
-#                     "mag_field_y": "cell_centered_B_y ",
-#                     "mag_field_z": "cell_centered_B_z "}
+                    "z-velocity": "velocity_z",
+                    "mag_field_x": "cell_centered_B_x ",
+                    "mag_field_y": "cell_centered_B_y ",
+                    "mag_field_z": "cell_centered_B_z "}
 
 AthenaFieldInfo = FieldInfoContainer.create_with_fallback(FieldInfo)
 add_field = AthenaFieldInfo.add_field
@@ -55,33 +55,30 @@
 KnownAthenaFields = FieldInfoContainer()
 add_athena_field = KnownAthenaFields.add_field
 
-add_athena_field("density", function=NullFunc, take_log=True,
-          units=r"\rm{g}/\rm{cm}^3",
-          projected_units =r"\rm{g}/\rm{cm}^2")
+add_athena_field("density", function=NullFunc, take_log=False,
+          units=r"",
+          projected_units =r"")
 
-add_athena_field("specific_energy", function=NullFunc, take_log=True,
-          units=r"\rm{erg}/\rm{g}")
-
-add_athena_field("pressure", function=NullFunc, take_log=True,
-          units=r"\rm{erg}/\rm{g}")
+add_athena_field("pressure", function=NullFunc, take_log=False,
+          units=r"")
 
 add_athena_field("velocity_x", function=NullFunc, take_log=False,
-          units=r"\rm{cm}/\rm{s}")
+          units=r"")
 
 add_athena_field("velocity_y", function=NullFunc, take_log=False,
-          units=r"\rm{cm}/\rm{s}")
+          units=r"")
 
 add_athena_field("velocity_z", function=NullFunc, take_log=False,
-          units=r"\rm{cm}/\rm{s}")
+          units=r"")
 
-add_athena_field("mag_field_x", function=NullFunc, take_log=False,
-          units=r"\rm{cm}/\rm{s}")
+add_athena_field("cell_centered_B_x", function=NullFunc, take_log=False,
+          units=r"")
 
-add_athena_field("mag_field_y", function=NullFunc, take_log=False,
-          units=r"\rm{cm}/\rm{s}")
+add_athena_field("cell_centered_B_y", function=NullFunc, take_log=False,
+          units=r"")
 
-add_athena_field("mag_field_z", function=NullFunc, take_log=False,
-          units=r"\rm{cm}/\rm{s}")
+add_athena_field("cell_centered_B_z", function=NullFunc, take_log=False,
+          units=r"")
 
 for f,v in log_translation_dict.items():
     add_field(f, TranslationFunc(v), take_log=True)


diff -r 77b5e3d096f57a4b11738e5fc268643ba70d4c84 -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 yt/frontends/athena/io.py
--- a/yt/frontends/athena/io.py
+++ b/yt/frontends/athena/io.py
@@ -27,7 +27,7 @@
 """
 from yt.utilities.io_handler import \
            BaseIOHandler
-import numpy as na
+import numpy as np
 
 class IOHandlerAthena(BaseIOHandler):
     _data_style = "athena"
@@ -46,24 +46,15 @@
     def _read_data_set(self,grid,field):
         f = file(grid.filename, 'rb')
         dtype, offset = grid.hierarchy._field_map[field]
-        grid_ncells = na.prod(grid.ActiveDimensions)
+        grid_ncells = np.prod(grid.ActiveDimensions)
         grid_dims = grid.ActiveDimensions
-        line = f.readline()
-        while True:
-            splitup = line.strip().split()
-            if 'CELL_DATA' in splitup:
-                f.readline()
-                read_table_offset = f.tell()
-                del line
-                break
-            del line; line = f.readline()
-
-
+        read_table_offset = get_read_table_offset(f)
         f.seek(read_table_offset+offset)
         if dtype == 'scalar':
-            data = na.fromfile(f, dtype='>f4', count=grid_ncells).reshape(grid_dims,order='F').copy()
+            data = np.fromfile(f, dtype='>f4',
+                    count=grid_ncells).reshape(grid_dims,order='F').copy()
         if dtype == 'vector':
-            data = na.fromfile(f, dtype='>f4', count=3*grid_ncells)
+            data = np.fromfile(f, dtype='>f4', count=3*grid_ncells)
             if '_x' in field:
                 data = data[0::3].reshape(grid_dims,order='F').copy()
             elif '_y' in field:
@@ -84,33 +75,33 @@
 
         f = file(grid.filename, 'rb')
         dtype, offset = grid.hierarchy._field_map[field]
-        grid_ncells = na.prod(grid.ActiveDimensions)
+        grid_ncells = np.prod(grid.ActiveDimensions)
 
-        line = f.readline()
-        while True:
-            splitup = line.strip().split()
-            if 'CELL_DATA' in splitup:
-                f.readline()
-                read_table_offset = f.tell()
-                del line
-                break
-            del line; line = f.readline()
-
+        read_table_offset = get_read_table_offset(f)
         f.seek(read_table_offset+offset)
         if dtype == 'scalar':
-            data = na.fromfile(f, dtype='>f4', count=grid_ncells).reshape(grid.ActiveDimensions,order='F')[sl].copy()
+            data = np.fromfile(f, dtype='>f4', 
+                    count=grid_ncells).reshape(grid.ActiveDimensions,order='F')[sl].copy()
         if dtype == 'vector':
-            data = na.fromfile(f, dtype='>f4', count=3*grid_ncells)
+            data = np.fromfile(f, dtype='>f4', count=3*grid_ncells)
             if '_x' in field:
                 data = data[0::3].reshape(grid.ActiveDimensions,order='F')[sl].copy()
             elif '_y' in field:
                 data = data[1::3].reshape(grid.ActiveDimensions,order='F')[sl].copy()
             elif '_z' in field:
                 data = data[2::3].reshape(grid.ActiveDimensions,order='F')[sl].copy()
+        f.close()
+        return data
 
-        f.close()
-        if grid.pf.field_ordering == 1:
-            return data.T
-        else:
-            return data
+def get_read_table_offset(f):
+    line = f.readline()
+    while True:
+        splitup = line.strip().split()
+        if 'CELL_DATA' in splitup:
+            f.readline()
+            read_table_offset = f.tell()
+            break
+        line = f.readline()
+    return read_table_offset
 
+


diff -r 77b5e3d096f57a4b11738e5fc268643ba70d4c84 -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 yt/utilities/io_handler.py
--- a/yt/utilities/io_handler.py
+++ b/yt/utilities/io_handler.py
@@ -42,7 +42,6 @@
         def __init__(cls, name, b, d):
             type.__init__(cls, name, b, d)
             if hasattr(cls, "_data_style"):
-                print 'Registering Class ', cls ,' with datastyle ', cls._data_style
                 io_registry[cls._data_style] = cls
 
     def __init__(self):



https://bitbucket.org/yt_analysis/yt/changeset/a1a294fb7205/
changeset:   a1a294fb7205
branch:      yt
user:        samskillman
date:        2012-09-05 18:18:21
summary:     Merging.
affected #:  22 files

diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -399,7 +399,6 @@
 # Now we dump all our SHA512 files out.
 
 echo '2c1933ab31246b4f4eba049d3288156e0a72f1730604e3ed7357849967cdd329e4647cf236c9442ecfb06d0aff03e6fc892a7ba2a5c1cf5c011b7ab9c619acec  Cython-0.16.tar.gz' > Cython-0.16.tar.gz.sha512
-echo 'b8a12bf05b3aafa71135e47da81440fd0f16a4bd91954bc5615ad3d3b7f9df7d5a7d5620dc61088dc6b04952c5c66ebda947a4cfa33ed1be614c8ca8c0f11dff  PhiloGL-1.4.2.zip' > PhiloGL-1.4.2.zip.sha512
 echo '44eea803870a66ff0bab08d13a8b3388b5578ebc1c807d1d9dca0a93e6371e91b15d02917a00b3b20dc67abb5a21dabaf9b6e9257a561f85eeff2147ac73b478  PyX-0.11.1.tar.gz' > PyX-0.11.1.tar.gz.sha512
 echo '1a754d560bfa433f0960ab3b5a62edb5f291be98ec48cf4e5941fa5b84139e200b87a52efbbd6fa4a76d6feeff12439eed3e7a84db4421940d1bbb576f7a684e  Python-2.7.2.tgz' > Python-2.7.2.tgz.sha512
 echo 'c017d3d59dd324ac91af0edc178c76b60a5f90fbb775cf843e39062f95bd846238f2c53705f8890ed3f34bc0e6e75671a73d13875eb0287d6201cb45f0a2d338  bzip2-1.0.5.tar.gz' > bzip2-1.0.5.tar.gz.sha512
@@ -599,11 +598,11 @@
     elif [ ! -e yt-hg ] 
     then
         YT_DIR="$PWD/yt-hg/"
-        ( ${HG_EXEC} --debug clone http://hg.yt-project.org/yt-supplemental/ 2>&1 ) 1>> ${LOG_FILE}
+        ( ${HG_EXEC} --debug clone https://bitbucket.org/yt_analysis/yt-supplemental/ 2>&1 ) 1>> ${LOG_FILE}
         # Recently the hg server has had some issues with timeouts.  In lieu of
         # a new webserver, we are now moving to a three-stage process.
         # First we clone the repo, but only up to r0.
-        ( ${HG_EXEC} --debug clone http://hg.yt-project.org/yt/ ./yt-hg 2>&1 ) 1>> ${LOG_FILE}
+        ( ${HG_EXEC} --debug clone https://bitbucket.org/yt_analysis/yt/ ./yt-hg 2>&1 ) 1>> ${LOG_FILE}
         # Now we update to the branch we're interested in.
         ( ${HG_EXEC} -R ${YT_DIR} up -C ${BRANCH} 2>&1 ) 1>> ${LOG_FILE}
     elif [ -e yt-hg ] 
@@ -682,7 +681,12 @@
 echo "Doing yt update, wiping local changes and updating to branch ${BRANCH}"
 MY_PWD=`pwd`
 cd $YT_DIR
-( ${HG_EXEC} pull && ${HG_EXEC} up -C ${BRANCH} 2>&1 ) 1>> ${LOG_FILE}
+( ${HG_EXEC} pull 2>1 && ${HG_EXEC} up -C 2>1 ${BRANCH} 2>&1 ) 1>> ${LOG_FILE}
+
+echo "Building Fortran kD-tree module."
+cd yt/utilities/kdtree
+( make 2>&1 ) 1>> ${LOG_FILE}
+cd ../../..
 
 echo "Installing yt"
 echo $HDF5_DIR > hdf5.cfg


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -81,3 +81,5 @@
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
+
+__version__ = "2.5-dev"


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -51,6 +51,7 @@
     pluginfilename = 'my_plugins.py',
     parallel_traceback = 'False',
     pasteboard_repo = '',
+    reconstruct_hierarchy = 'False',
     test_storage_dir = '/does/not/exist',
     enzo_db = '',
     hub_url = 'https://hub.yt-project.org/upload',


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -3077,7 +3077,7 @@
         """
         AMR3DData.__init__(self, center, fields, pf, **kwargs)
         self._norm_vec = na.array(normal)/na.sqrt(na.dot(normal,normal))
-        self.set_field_parameter("height_vector", self._norm_vec)
+        self.set_field_parameter("normal", self._norm_vec)
         self._height = fix_length(height, self.pf)
         self._radius = fix_length(radius, self.pf)
         self._d = -1.0 * na.dot(self._norm_vec, self.center)


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/data_objects/field_info_container.py
--- a/yt/data_objects/field_info_container.py
+++ b/yt/data_objects/field_info_container.py
@@ -220,7 +220,7 @@
 
     def get_field_parameter(self, param):
         self.requested_parameters.append(param)
-        if param in ['bulk_velocity', 'center', 'height_vector']:
+        if param in ['bulk_velocity', 'center', 'normal']:
             return na.random.random(3) * 1e-2
         else:
             return 0.0




diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -217,50 +217,181 @@
 add_field("Entropy", units=r"\rm{ergs}\ \rm{cm}^{3\gamma-3}",
           function=_Entropy)
 
+
+
+### spherical coordinates: r (radius)
+def _sph_r(field, data):
+    center = data.get_field_parameter("center")
+      
+    coords = na.array([data['x'] - center[0],
+                       data['y'] - center[1],
+                       data['z'] - center[2]]).transpose()
+
+    ## The spherical coordinates radius is simply the magnitude of the
+    ## coords vector.
+
+    return na.sqrt(na.sum(coords**2,axis=-1))
+
+def _Convert_sph_r_CGS(data):
+   return data.convert("cm")
+
+add_field("sph_r", function=_sph_r,
+         validators=[ValidateParameter("center")],
+         convert_function = _Convert_sph_r_CGS, units=r"\rm{cm}")
+
+
+### spherical coordinates: theta (angle with respect to normal)
+def _sph_theta(field, data):
+    center = data.get_field_parameter("center")
+    normal = data.get_field_parameter("normal")
+    
+    coords = na.array([data['x'] - center[0],
+                       data['y'] - center[1],
+                       data['z'] - center[2]]).transpose()
+
+    ## The angle (theta) with respect to the normal (J), is the arccos
+    ## of the dot product of the normal with the normalized coords
+    ## vector.
+    
+    tile_shape = list(coords.shape)[:-1] + [1]
+    J = na.tile(normal,tile_shape)
+
+    JdotCoords = na.sum(J*coords,axis=-1)
+    
+    return na.arccos( JdotCoords / na.sqrt(na.sum(coords**2,axis=-1)) )
+
+add_field("sph_theta", function=_sph_theta,
+         validators=[ValidateParameter("center"),ValidateParameter("normal")])
+
+
+### spherical coordinates: phi (angle in the plane perpendicular to the normal)
+def _sph_phi(field, data):
+    center = data.get_field_parameter("center")
+    normal = data.get_field_parameter("normal")
+    
+    coords = na.array([data['x'] - center[0],
+                       data['y'] - center[1],
+                       data['z'] - center[2]]).transpose()
+    
+    ## We have freedom with respect to what axis (xprime) to define
+    ## the disk angle. Here I've chosen to use the axis that is
+    ## perpendicular to the normal and the y-axis. When normal ==
+    ## y-hat, then set xprime = z-hat. With this definition, when
+    ## normal == z-hat (as is typical), then xprime == x-hat.
+    ##
+    ## The angle is then given by the arctan of the ratio of the
+    ## yprime-component and the xprime-component of the coords vector.
+
+    xprime = na.cross([0.0,1.0,0.0],normal)
+    if na.sum(xprime) == 0: xprime = na.array([0.0, 0.0, 1.0])
+    yprime = na.cross(normal,xprime)
+    
+    tile_shape = list(coords.shape)[:-1] + [1]
+    Jx = na.tile(xprime,tile_shape)
+    Jy = na.tile(yprime,tile_shape)
+    
+    Px = na.sum(Jx*coords,axis=-1)
+    Py = na.sum(Jy*coords,axis=-1)
+    
+    return na.arctan2(Py,Px)
+
+add_field("sph_phi", function=_sph_phi,
+         validators=[ValidateParameter("center"),ValidateParameter("normal")])
+
+
+
+### cylindrical coordinates: R (radius in the cylinder's plane)
+def _cyl_R(field, data):
+    center = data.get_field_parameter("center")
+    normal = data.get_field_parameter("normal")
+      
+    coords = na.array([data['x'] - center[0],
+                       data['y'] - center[1],
+                       data['z'] - center[2]]).transpose()
+
+    ## The cross product of the normal (J) with the coords vector
+    ## gives a vector of magnitude equal to the cylindrical radius.
+    
+    tile_shape = list(coords.shape)[:-1] + [1]
+    J = na.tile(normal,tile_shape)
+
+    JcrossCoords = na.cross(J,coords)
+    return na.sqrt(na.sum(JcrossCoords**2,axis=-1))
+
+def _Convert_cyl_R_CGS(data):
+   return data.convert("cm")
+
+add_field("cyl_R", function=_cyl_R,
+         validators=[ValidateParameter("center"),ValidateParameter("normal")],
+         convert_function = _Convert_cyl_R_CGS, units=r"\rm{cm}")
+
+
+### cylindrical coordinates: z (height above the cylinder's plane)
+def _cyl_z(field, data):
+    center = data.get_field_parameter("center")
+    normal = data.get_field_parameter("normal")
+    
+    coords = na.array([data['x'] - center[0],
+                       data['y'] - center[1],
+                       data['z'] - center[2]]).transpose()
+
+    ## The dot product of the normal (J) with the coords vector gives
+    ## the cylindrical height.
+    
+    tile_shape = list(coords.shape)[:-1] + [1]
+    J = na.tile(normal,tile_shape)
+
+    return na.sum(J*coords,axis=-1)  
+
+def _Convert_cyl_z_CGS(data):
+   return data.convert("cm")
+
+add_field("cyl_z", function=_cyl_z,
+         validators=[ValidateParameter("center"),ValidateParameter("normal")],
+         convert_function = _Convert_cyl_z_CGS, units=r"\rm{cm}")
+
+
+### cylindrical coordinates: theta (angle in the cylinder's plane)
+### [This is identical to the spherical coordinate's 'phi' angle.]
+def _cyl_theta(field, data):
+    return data['sph_phi']
+
+add_field("cyl_theta", function=_cyl_theta,
+         validators=[ValidateParameter("center"),ValidateParameter("normal")])
+
+
+### The old field DiskAngle is the same as the spherical coordinates'
+### 'theta' angle. I'm keeping DiskAngle for backwards compatibility.
+def _DiskAngle(field, data):
+    return data['sph_theta']
+
+add_field("DiskAngle", function=_DiskAngle,
+          take_log=False,
+          validators=[ValidateParameter("center"),
+                      ValidateParameter("normal")],
+          display_field=False)
+
+
+### The old field Height is the same as the cylindrical coordinates' z
+### field. I'm keeping Height for backwards compatibility.
 def _Height(field, data):
-    # We take the dot product of the radius vector with the height-vector
-    center = data.get_field_parameter("center")
-    r_vec = na.array([data["x"] - center[0],
-                      data["y"] - center[1],
-                      data["z"] - center[2]])
-    h_vec = na.array(data.get_field_parameter("height_vector"))
-    h_vec = h_vec / na.sqrt(h_vec[0]**2.0+
-                            h_vec[1]**2.0+
-                            h_vec[2]**2.0)
-    height = r_vec[0,:] * h_vec[0] \
-           + r_vec[1,:] * h_vec[1] \
-           + r_vec[2,:] * h_vec[2]
-    return na.abs(height)
+    return data['cyl_z']
+
 def _convertHeight(data):
     return data.convert("cm")
 def _convertHeightAU(data):
     return data.convert("au")
 add_field("Height", function=_Height,
           convert_function=_convertHeight,
-          validators=[ValidateParameter("height_vector")],
+          validators=[ValidateParameter("center"),
+                      ValidateParameter("normal")],
           units=r"cm", display_field=False)
 add_field("HeightAU", function=_Height,
           convert_function=_convertHeightAU,
-          validators=[ValidateParameter("height_vector")],
+          validators=[ValidateParameter("center"),
+                      ValidateParameter("normal")],
           units=r"AU", display_field=False)
 
-def _DiskAngle(field, data):
-    # We make both r_vec and h_vec into unit vectors
-    center = data.get_field_parameter("center")
-    r_vec = na.array([data["x"] - center[0],
-                      data["y"] - center[1],
-                      data["z"] - center[2]])
-    r_vec = r_vec/na.sqrt((r_vec**2.0).sum(axis=0))
-    h_vec = na.array(data.get_field_parameter("height_vector"))
-    dp = r_vec[0,:] * h_vec[0] \
-       + r_vec[1,:] * h_vec[1] \
-       + r_vec[2,:] * h_vec[2]
-    return na.arccos(dp)
-add_field("DiskAngle", function=_DiskAngle,
-          take_log=False,
-          validators=[ValidateParameter("height_vector"),
-                      ValidateParameter("center")],
-          display_field=False)
 
 def _DynamicalTime(field, data):
     """


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/frontends/enzo/data_structures.py
--- a/yt/frontends/enzo/data_structures.py
+++ b/yt/frontends/enzo/data_structures.py
@@ -441,11 +441,13 @@
         mylog.info("Finished rebuilding")
 
     def _populate_grid_objects(self):
+        reconstruct = ytcfg.getboolean("yt","reconstruct_hierarchy")
         for g,f in izip(self.grids, self.filenames):
             g._prepare_grid()
             g._setup_dx()
             g.set_filename(f[0])
-            #if g.Parent is not None: g._guess_properties_from_parent()
+            if reconstruct:
+                if g.Parent is not None: g._guess_properties_from_parent()
         del self.filenames # No longer needed.
         self.max_level = self.grid_levels.max()
 


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/frontends/enzo/fields.py
--- a/yt/frontends/enzo/fields.py
+++ b/yt/frontends/enzo/fields.py
@@ -183,6 +183,12 @@
           display_name = "\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}",
+          units=r"\rm{ergs}/\rm{g}", convert_function=_convertEnergy)
+
 def _NumberDensity(field, data):
     # We can assume that we at least have Density
     # We should actually be guaranteeing the presence of a .shape attribute,


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/frontends/flash/data_structures.py
--- a/yt/frontends/flash/data_structures.py
+++ b/yt/frontends/flash/data_structures.py
@@ -39,7 +39,7 @@
     mpc_conversion, sec_conversion
 from yt.utilities.io_handler import \
     io_registry
-
+from yt.utilities.physical_constants import cm_per_mpc
 from .fields import FLASHFieldInfo, add_flash_field, KnownFLASHFields
 from yt.data_objects.field_info_container import FieldInfoContainer, NullFunc, \
      ValidateDataField
@@ -229,13 +229,13 @@
         self.conversion_factors = defaultdict(lambda: 1.0)
         if "EOSType" not in self.parameters:
             self.parameters["EOSType"] = -1
-        if self.cosmological_simulation == 1:
-            self._setup_comoving_units()
         if "pc_unitsbase" in self.parameters:
             if self.parameters["pc_unitsbase"] == "CGS":
                 self._setup_cgs_units()
         else:
             self._setup_nounits_units()
+        if self.cosmological_simulation == 1:
+            self._setup_comoving_units()
         self.time_units['1'] = 1
         self.units['1'] = 1.0
         self.units['unitary'] = 1.0 / \
@@ -252,10 +252,10 @@
         self.conversion_factors['eint'] = (1.0 + self.current_redshift)**-2.0
         self.conversion_factors['ener'] = (1.0 + self.current_redshift)**-2.0
         self.conversion_factors['temp'] = (1.0 + self.current_redshift)**-2.0
-        self.conversion_factors['velx'] = (1.0 + self.current_redshift)
+        self.conversion_factors['velx'] = (1.0 + self.current_redshift)**-1.0
         self.conversion_factors['vely'] = self.conversion_factors['velx']
         self.conversion_factors['velz'] = self.conversion_factors['velx']
-        self.conversion_factors['particle_velx'] = (1.0 + self.current_redshift)
+        self.conversion_factors['particle_velx'] = (1.0 + self.current_redshift)**-1.0
         self.conversion_factors['particle_vely'] = \
             self.conversion_factors['particle_velx']
         self.conversion_factors['particle_velz'] = \
@@ -265,7 +265,8 @@
             self.conversion_factors["Time"] = 1.0
         for unit in mpc_conversion.keys():
             self.units[unit] = mpc_conversion[unit] / mpc_conversion["cm"]
-
+            self.units[unit] /= (1.0+self.current_redshift)
+            
     def _setup_cgs_units(self):
         self.conversion_factors['dens'] = 1.0
         self.conversion_factors['pres'] = 1.0
@@ -407,6 +408,7 @@
             self.omega_lambda = self.parameters['cosmologicalconstant']
             self.omega_matter = self.parameters['omegamatter']
             self.hubble_constant = self.parameters['hubbleconstant']
+            self.hubble_constant *= cm_per_mpc * 1.0e-5 * 1.0e-2 # convert to 'h'
         except:
             self.current_redshift = self.omega_lambda = self.omega_matter = \
                 self.hubble_constant = self.cosmological_simulation = 0.0


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/frontends/flash/io.py
--- a/yt/frontends/flash/io.py
+++ b/yt/frontends/flash/io.py
@@ -51,23 +51,6 @@
             count_list, conv_factors):
         pass
 
-    def _select_particles(self, grid, field):
-        f = self._handle
-        npart = f["/tracer particles"].shape[0]
-        total_selected = 0
-        start = 0
-        stride = 1e6
-        blki = self._particle_fields["particle_blk"]
-        bi = grid.id - grid._id_offset
-        fi = self._particle_fields[field]
-        tr = []
-        while start < npart:
-            end = min(start + stride - 1, npart)
-            gi = f["/tracer particles"][start:end,blki] == bi
-            tr.append(f["/tracer particles"][gi,fi])
-            start = end
-        return na.concatenate(tr)
-
     def _read_data_set(self, grid, field):
         f = self._handle
         if field in self._particle_fields:




diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/frontends/gdf/data_structures.py
--- a/yt/frontends/gdf/data_structures.py
+++ b/yt/frontends/gdf/data_structures.py
@@ -8,7 +8,7 @@
 Affiliation: KIPAC/SLAC/Stanford
 Homepage: http://yt-project.org/
 License:
-  Copyright (C) 2008-2011 Samuel W. Skillman, Matthew Turk, J. S. Oishi.  
+  Copyright (C) 2008-2011 Samuel W. Skillman, Matthew Turk, J. S. Oishi.
   All Rights Reserved.
 
   This file is part of yt.
@@ -79,7 +79,7 @@
 class GDFHierarchy(AMRHierarchy):
 
     grid = GDFGrid
-    
+
     def __init__(self, pf, data_style='grid_data_format'):
         self.parameter_file = weakref.proxy(pf)
         self.data_style = data_style
@@ -96,7 +96,7 @@
 
     def _detect_fields(self):
         self.field_list = self._fhandle['field_types'].keys()
-    
+
     def _setup_classes(self):
         dd = self._get_data_reader_dict()
         AMRHierarchy._setup_classes(self, dd)
@@ -104,14 +104,17 @@
 
     def _count_grids(self):
         self.num_grids = self._fhandle['/grid_parent_id'].shape[0]
-       
+
     def _parse_hierarchy(self):
-        f = self._fhandle 
-        dxs=[]
+        f = self._fhandle
+        dxs = []
         self.grids = na.empty(self.num_grids, dtype='object')
         levels = (f['grid_level'][:]).copy()
         glis = (f['grid_left_index'][:]).copy()
         gdims = (f['grid_dimensions'][:]).copy()
+        active_dims = ~((na.max(gdims, axis=0) == 1) &
+                        (self.parameter_file.domain_dimensions == 1))
+
         for i in range(levels.shape[0]):
             self.grids[i] = self.grid(i, self, levels[i],
                                       glis[i],
@@ -120,7 +123,7 @@
 
             dx = (self.parameter_file.domain_right_edge-
                   self.parameter_file.domain_left_edge)/self.parameter_file.domain_dimensions
-            dx = dx/self.parameter_file.refine_by**(levels[i])
+            dx[active_dims] = dx[active_dims]/self.parameter_file.refine_by**(levels[i])
             dxs.append(dx)
         dx = na.array(dxs)
         self.grid_left_edge = self.parameter_file.domain_left_edge + dx*glis
@@ -128,7 +131,7 @@
         self.grid_right_edge = self.grid_left_edge + dx*self.grid_dimensions
         self.grid_particle_count = f['grid_particle_count'][:]
         del levels, glis, gdims
- 
+
     def _populate_grid_objects(self):
         for g in self.grids:
             g._prepare_grid()
@@ -153,13 +156,13 @@
     _hierarchy_class = GDFHierarchy
     _fieldinfo_fallback = GDFFieldInfo
     _fieldinfo_known = KnownGDFFields
-    
+
     def __init__(self, filename, data_style='grid_data_format',
                  storage_filename = None):
         StaticOutput.__init__(self, filename, data_style)
         self.storage_filename = storage_filename
         self.filename = filename
-        
+
     def _set_units(self):
         """
         Generates the conversion to various physical _units based on the parameter file
@@ -190,12 +193,12 @@
             except:
                 current_fields_unit = ""
             self._fieldinfo_known.add_field(field_name, function=NullFunc, take_log=False,
-                   units=current_fields_unit, projected_units="", 
+                   units=current_fields_unit, projected_units="",
                    convert_function=_get_convert(field_name))
 
         self._handle.close()
         del self._handle
-        
+
     def _parse_parameter_file(self):
         self._handle = h5py.File(self.parameter_filename, "r")
         sp = self._handle["/simulation_parameters"].attrs
@@ -204,7 +207,7 @@
         self.domain_dimensions = sp["domain_dimensions"][:]
         refine_by = sp["refine_by"]
         if refine_by is None: refine_by = 2
-        self.refine_by = refine_by 
+        self.refine_by = refine_by
         self.dimensionality = sp["dimensionality"]
         self.current_time = sp["current_time"]
         self.unique_identifier = sp["unique_identifier"]
@@ -225,7 +228,7 @@
         self.parameters["HydroMethod"] = 0 # Hardcode for now until field staggering is supported.
         self._handle.close()
         del self._handle
-            
+
     @classmethod
     def _is_valid(self, *args, **kwargs):
         try:
@@ -238,4 +241,4 @@
 
     def __repr__(self):
         return self.basename.rsplit(".", 1)[0]
-        
+




diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/gui/reason/html/app/controller/Notebook.js
--- a/yt/gui/reason/html/app/controller/Notebook.js
+++ b/yt/gui/reason/html/app/controller/Notebook.js
@@ -73,9 +73,11 @@
     },
 
     addRequest: function(request_id, command) {
+        /*console.log("Adding request " + request_id);*/
         this.getRequestsStore().add({
             request_id: request_id, command: command,
         });
+        reason.pending.update([this.getRequestsStore().count()]);
     },
 
     addCell: function(cell) {
@@ -85,6 +87,7 @@
             var ind = this.getRequestsStore().find(
                 'request_id', cell['result_id']);
             if (ind != -1) {
+                /*console.log("Removing request " + cell['result_id']);*/
                 var rec = this.getRequestsStore().removeAt(ind);
             }
             reason.pending.update([this.getRequestsStore().count()]);


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/utilities/exceptions.py
--- a/yt/utilities/exceptions.py
+++ b/yt/utilities/exceptions.py
@@ -110,3 +110,10 @@
         return "You have not declared yourself to be inside the IPython" + \
                "Notebook.  Do so with this command:\n\n" + \
                "ytcfg['yt','ipython_notebook'] = 'True'"
+
+class YTUnitNotRecognized(YTException):
+    def __init__(self, unit):
+        self.unit = unit
+
+    def __str__(self):
+        return "This parameter file doesn't recognize %s" % self.unit


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/utilities/grid_data_format/writer.py
--- /dev/null
+++ b/yt/utilities/grid_data_format/writer.py
@@ -0,0 +1,169 @@
+"""
+Writing yt data to a GDF file.
+
+Authors: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2012 Casey W. Stark.  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 os
+
+import h5py
+import numpy as np
+
+from yt import __version__ as yt_version
+
+
+def write_to_gdf(pf, gdf_path, data_author=None, data_comment=None,
+                 particle_type_name="dark_matter"):
+    """
+    Write a parameter file to the given path in the Grid Data Format.
+
+    Parameters
+    ----------
+    pf : StaticOutput object
+        The yt data to write out.
+    gdf_path : string
+        The path of the file to output.
+
+    """
+    # Make sure we have the absolute path to the file first
+    gdf_path = os.path.abspath(gdf_path)
+
+    # Stupid check -- is the file already there?
+    # @todo: make this a specific exception/error.
+    if os.path.exists(gdf_path):
+        raise IOError("A file already exists in the location: %s. Please provide a new one or remove that file." % gdf_path)
+
+    ###
+    # Create and open the file with h5py
+    ###
+    f = h5py.File(gdf_path, "w")
+
+    ###
+    # "gridded_data_format" group
+    ###
+    g = f.create_group("gridded_data_format")
+    g.attrs["data_software"] = "yt"
+    g.attrs["data_software_version"] = yt_version
+    if data_author is not None:
+        g.attrs["data_author"] = data_author
+    if data_comment is not None:
+        g.attrs["data_comment"] = data_comment
+
+    ###
+    # "simulation_parameters" group
+    ###
+    g = f.create_group("simulation_parameters")
+    g.attrs["refine_by"] = pf.refine_by
+    g.attrs["dimensionality"] = pf.dimensionality
+    g.attrs["domain_dimensions"] = pf.domain_dimensions
+    g.attrs["current_time"] = pf.current_time
+    g.attrs["domain_left_edge"] = pf.domain_left_edge
+    g.attrs["domain_right_edge"] = pf.domain_right_edge
+    g.attrs["unique_identifier"] = pf.unique_identifier
+    g.attrs["cosmological_simulation"] = pf.cosmological_simulation
+    # @todo: Where is this in the yt API?
+    #g.attrs["num_ghost_zones"] = pf...
+    # @todo: Where is this in the yt API?
+    #g.attrs["field_ordering"] = pf...
+    # @todo: not yet supported by yt.
+    #g.attrs["boundary_conditions"] = pf...
+
+    if pf.cosmological_simulation:
+        g.attrs["current_redshift"] = pf.current_redshift
+        g.attrs["omega_matter"] = pf.omega_matter
+        g.attrs["omega_lambda"] = pf.omega_lambda
+        g.attrs["hubble_constant"] = pf.hubble_constant
+
+    ###
+    # "field_types" group
+    ###
+    g = f.create_group("field_types")
+
+    # Which field list should we iterate over?
+    for field_name in pf.h.field_list:
+        # create the subgroup with the field's name
+        sg = g.create_group(field_name)
+
+        # grab the display name and units from the field info container.
+        display_name = pf.field_info[field_name].display_name
+        units = pf.field_info[field_name].get_units()
+
+        # check that they actually contain something...
+        if display_name:
+            sg.attrs["field_name"] = display_name
+        else:
+            sg.attrs["field_name"] = field_name
+        if units:
+            sg.attrs["field_units"] = units
+        else:
+            sg.attrs["field_units"] = "None"
+        # @todo: the values must be in CGS already right?
+        sg.attrs["field_to_cgs"] = 1.0
+        # @todo: is this always true?
+        sg.attrs["staggering"] = 0
+
+    ###
+    # "particle_types" group
+    ###
+    g = f.create_group("particle_types")
+
+    # @todo: Particle type iterator
+    sg = g.create_group(particle_type_name)
+    sg["particle_type_name"] = particle_type_name
+
+    ###
+    # root datasets -- info about the grids
+    ###
+    f["grid_dimensions"] = pf.h.grid_dimensions
+    f["grid_left_index"] = pf.h.grid_left_edge
+    f["grid_level"] = pf.h.grid_levels
+    # @todo: Do we need to loop over the grids for this?
+    f["grid_parent_id"] = -1
+    f["grid_particle_count"] = pf.h.grid_particle_count
+
+    ###
+    # "data" group -- where we should spend the most time
+    ###
+    g = f.create_group("data")
+
+    for grid in pf.h.grids:
+        # add group for this grid
+
+        grid_group = g.create_group("grid_%010i" % grid.id)
+        # add group for the particles on this grid
+        particles_group = grid_group.create_group("particles")
+        pt_group = particles_group.create_group(particle_type_name)
+
+        # add the field data to the grid group
+        for field_name in pf.h.field_list:
+            # Check if this is a real field or particle data.
+            field_obj = pf.field_info[field_name]
+
+            if field_obj.particle_type:  # particle data
+                pt_group[field_name] = grid.get_data(field_name)
+            else:  # a field
+                grid_group[field_name] = grid.get_data(field_name)
+
+    # don't forget to close the file.
+    f.close()


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/utilities/parallel_tools/controller_system.py
--- /dev/null
+++ b/yt/utilities/parallel_tools/controller_system.py
@@ -0,0 +1,69 @@
+"""
+A queueing system based on MPI
+
+Author: Matthew Turk <matthewturk at gmail.com>
+Affiliation: Columbia
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2012 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/>.
+"""
+    
+try:
+    from .parallel_analysis_interface import MPI
+except ImportError:
+    pass
+from contextmanager import contextlib
+from abc import ABCMeta, abstractmethod, abstractproperty
+
+class WorkSplitter(object):
+    def __init__(self, controller, group1, group2):
+        self.group1 = group1
+        self.group2 = group2
+        self.controller = controller
+
+    @classmethod
+    def setup(cls, ng1, ng2):
+        pp, wg = ProcessorPool.from_sizes(
+            [(1, "controller"), (ng1, "group1"), (ng2, "group2")])
+        groupc = pp['controller']
+        group1 = pp['group1']
+        group2 = pp['group2']
+        obj = cls(groupc, group1, group2)
+        obj.run(wg.name)
+
+    def run(self, name):
+        if name == "controller":
+            self.run_controller()
+        elif name == "group1":
+            self.run_group1()
+        elif name == "group2":
+            self.run_group2()
+        else:
+            raise NotImplementedError
+
+    @abstractmethod
+    def run_controller(self):
+        pass
+
+    @abstractmethod
+    def run_group1(self):
+        pass
+
+    @abstractmethod
+    def run_group2(self):
+        pass


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/utilities/parallel_tools/io_runner.py
--- /dev/null
+++ b/yt/utilities/parallel_tools/io_runner.py
@@ -0,0 +1,195 @@
+"""
+A simple IO staging mechanism
+
+Author: Matthew Turk <matthewturk at gmail.com>
+Affiliation: Columbia
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2012 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 os
+from .parallel_analysis_interface import ProcessorPool
+from yt.utilities.io_handler import BaseIOHandler
+from contextlib import contextmanager
+import time
+
+try:
+    from .parallel_analysis_interface import MPI
+except ImportError:
+    pass
+
+YT_TAG_MESSAGE = 317 # Cell 317 knows where to go
+
+class IOCommunicator(BaseIOHandler):
+    def __init__(self, pf, wg, pool):
+        mylog.info("Initializing IOCommunicator")
+        self.pf = pf
+        self.wg = wg # We don't need to use this!
+        self.pool = pool
+        self.comm = pool.comm
+        # We read our grids here
+        self.grids = []
+        storage = {}
+        grids = pf.h.grids.tolist()
+        grids.sort(key=lambda a:a.filename)
+        for sto, g in parallel_objects(grids, storage = storage):
+            sto.result = self.comm.rank
+            sto.result_id = g.id
+            self.grids.append(g)
+        self._id_offset = pf.h.grids[0]._id_offset
+        mylog.info("Reading from disk ...")
+        self.initialize_data()
+        mylog.info("Broadcasting ...")
+        self.comm.comm.bcast(storage, root = wg.ranks[0])
+        mylog.info("Done.")
+        self.hooks = []
+
+    def initialize_data(self):
+        pf = self.pf
+        fields = [f for f in pf.h.field_list
+                  if not pf.field_info[f].particle_type]
+        pfields = [f for f in pf.h.field_list
+                   if pf.field_info[f].particle_type]
+        # Preload is only defined for Enzo ...
+        if pf.h.io._data_style == "enzo_packed_3d":
+            self.queue = pf.h.io.queue
+            pf.h.io.preload(self.grids, fields)
+            for g in self.grids:
+                for f in fields:
+                    if f not in self.queue[g.id]:
+                        d = na.zeros(g.ActiveDimensions, dtype='float64')
+                        self.queue[g.id][f] = d
+                for f in pfields:
+                    self.queue[g.id][f] = self._read(g, f)
+        else:
+            self.queue = {}
+            for g in self.grids:
+                for f in fields + pfields:
+                    self.queue[g.id][f] = pf.h.io._read(g, f)
+
+    def _read(self, g, f):
+        fi = self.pf.field_info[f]
+        if fi.particle_type and g.NumberOfParticles == 0:
+            # because this gets upcast to float
+            return na.array([],dtype='float64')
+        try:
+            temp = self.pf.h.io._read_data_set(g, f)
+        except:# self.pf.hierarchy.io._read_exception as exc:
+            if fi.not_in_all:
+                temp = na.zeros(g.ActiveDimensions, dtype='float64')
+            else:
+                raise
+        return temp
+
+    def wait(self):
+        status = MPI.Status()
+        while 1:
+            if self.comm.comm.Iprobe(MPI.ANY_SOURCE,
+                                YT_TAG_MESSAGE,
+                                status = status):
+                msg = self.comm.comm.recv(
+                        source = status.source, tag = YT_TAG_MESSAGE)
+                if msg['op'] == "end":
+                    mylog.debug("Shutting down IO.")
+                    break
+                self._send_data(msg, status.source)
+                status = MPI.Status()
+            else:
+                time.sleep(1e-2)
+
+    def _send_data(self, msg, dest):
+        grid_id = msg['grid_id']
+        field = msg['field']
+        ts = self.queue[grid_id][field].astype("float64")
+        mylog.debug("Opening send to %s (%s)", dest, ts.shape)
+        self.hooks.append(self.comm.comm.Isend([ts, MPI.DOUBLE], dest = dest))
+
+class IOHandlerRemote(BaseIOHandler):
+    _data_style = "remote"
+
+    def __init__(self, pf, wg, pool):
+        self.pf = pf
+        self.wg = wg # probably won't need
+        self.pool = pool
+        self.comm = pool.comm
+        self.proc_map = self.comm.comm.bcast(None,
+                root = pool['io'].ranks[0])
+        super(IOHandlerRemote, self).__init__()
+
+    def _read_data_set(self, grid, field):
+        dest = self.proc_map[grid.id]
+        msg = dict(grid_id = grid.id, field = field, op="read")
+        mylog.debug("Requesting %s for %s from %s", field, grid, dest)
+        if self.pf.field_info[field].particle_type:
+            data = na.empty(grid.NumberOfParticles, 'float64')
+        else:
+            data = na.empty(grid.ActiveDimensions, 'float64')
+        hook = self.comm.comm.Irecv([data, MPI.DOUBLE], source = dest)
+        self.comm.comm.send(msg, dest = dest, tag = YT_TAG_MESSAGE)
+        mylog.debug("Waiting for data.")
+        MPI.Request.Wait(hook)
+        return data
+
+    def _read_data_slice(self, grid, field, axis, coord):
+        sl = [slice(None), slice(None), slice(None)]
+        sl[axis] = slice(coord, coord + 1)
+        #sl = tuple(reversed(sl))
+        return self._read_data_set(grid,field)[sl]
+
+    def terminate(self):
+        msg = dict(op='end')
+        if self.wg.comm.rank == 0:
+            for rank in self.pool['io'].ranks:
+                mylog.debug("Sending termination message to %s", rank)
+                self.comm.comm.send(msg, dest=rank, tag=YT_TAG_MESSAGE)
+
+ at contextmanager
+def remote_io(pf, wg, pool):
+    original_io = pf.h.io
+    pf.h.io = IOHandlerRemote(pf, wg, pool)
+    yield
+    pf.h.io.terminate()
+    pf.h.io = original_io
+
+def io_nodes(fn, n_io, n_work, func, *args, **kwargs):
+    pool, wg = ProcessorPool.from_sizes([(n_io, "io"), (n_work, "work")])
+    rv = None
+    if wg.name == "work":
+        pf = load(fn)
+        with remote_io(pf, wg, pool):
+            rv = func(pf, *args, **kwargs)
+    elif wg.name == "io":
+        pf = load(fn)
+        io = IOCommunicator(pf, wg, pool)
+        io.wait()
+    # We should broadcast the result
+    rv = pool.comm.mpi_bcast(rv, root=pool['work'].ranks[0])
+    pool.free_all()
+    mylog.debug("Return value: %s", rv)
+    return rv
+
+# Here is an example of how to use this functionality.
+if __name__ == "__main__":
+    def gq(pf):
+        dd = pf.h.all_data()
+        return dd.quantities["TotalQuantity"]("CellMassMsun")
+    q = io_nodes("DD0087/DD0087", 8, 24, gq)
+    mylog.info(q)
+
+


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/utilities/parallel_tools/parallel_analysis_interface.py
--- a/yt/utilities/parallel_tools/parallel_analysis_interface.py
+++ b/yt/utilities/parallel_tools/parallel_analysis_interface.py
@@ -271,7 +271,7 @@
         self.size = size
         self.ranks = ranks
         self.comm = comm
-	self.name = name
+        self.name = name
 
 class ProcessorPool(object):
     comm = None
@@ -294,11 +294,9 @@
             raise RuntimeError
         if ranks is None:
             ranks = [self.available_ranks.pop(0) for i in range(size)]
-
-	# Default name to the workgroup number.
+        # Default name to the workgroup number.
         if name is None: 
-	    name = string(len(workgroups))
-	    
+            name = string(len(workgroups))
         group = self.comm.comm.Get_group().Incl(ranks)
         new_comm = self.comm.comm.Create(group)
         if self.comm.rank in ranks:


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -80,11 +80,11 @@
     def pixel_scale(self,plot):
         x0, x1 = plot.xlim
         xx0, xx1 = plot._axes.get_xlim()
-        dx = (xx0 - xx1)/(x1 - x0)
+        dx = (xx1 - xx0)/(x1 - x0)
         
         y0, y1 = plot.ylim
         yy0, yy1 = plot._axes.get_ylim()
-        dy = (yy0 - yy1)/(y1 - y0)
+        dy = (yy1 - yy0)/(y1 - y0)
 
         return (dx,dy)
 
@@ -295,30 +295,31 @@
 
 class GridBoundaryCallback(PlotCallback):
     _type_name = "grids"
-    def __init__(self, alpha=1.0, min_pix=1, annotate=False, periodic=True):
+    def __init__(self, alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True):
         """
-        annotate_grids(alpha=1.0, min_pix=1, annotate=False, periodic=True)
+        annotate_grids(alpha=1.0, min_pix=1, draw_ids=False, periodic=True)
 
         Adds grid boundaries to a plot, optionally with *alpha*-blending.
         Cuttoff for display is at *min_pix* wide.
-        *annotate* puts the grid id in the corner of the grid.  (Not so great in projections...)
+        *draw_ids* puts the grid id in the corner of the grid.  (Not so great in projections...)
+        Grids must be wider than *min_pix_ids* otherwise the ID will not be drawn.
         """
         PlotCallback.__init__(self)
         self.alpha = alpha
         self.min_pix = min_pix
-        self.annotate = annotate # put grid numbers in the corner.
+        self.min_pix_ids = min_pix_ids
+        self.draw_ids = draw_ids # put grid numbers in the corner.
         self.periodic = periodic
 
     def __call__(self, plot):
         x0, x1 = plot.xlim
         y0, y1 = plot.ylim
-        width, height = plot.image._A.shape
         xx0, xx1 = plot._axes.get_xlim()
         yy0, yy1 = plot._axes.get_ylim()
         xi = x_dict[plot.data.axis]
         yi = y_dict[plot.data.axis]
-        dx = width / (x1-x0)
-        dy = height / (y1-y0)
+        (dx, dy) = self.pixel_scale(plot)
+        (xpix, ypix) = plot.image._A.shape
         px_index = x_dict[plot.data.axis]
         py_index = y_dict[plot.data.axis]
         dom = plot.data.pf.domain_right_edge - plot.data.pf.domain_left_edge
@@ -331,29 +332,32 @@
         for px_off, py_off in zip(pxs.ravel(), pys.ravel()):
             pxo = px_off * dom[px_index]
             pyo = py_off * dom[py_index]
-            left_edge_px = (GLE[:,px_index]+pxo-x0)*dx
-            left_edge_py = (GLE[:,py_index]+pyo-y0)*dy
-            right_edge_px = (GRE[:,px_index]+pxo-x0)*dx
-            right_edge_py = (GRE[:,py_index]+pyo-y0)*dy
+            left_edge_x = (GLE[:,px_index]+pxo-x0)*dx + xx0
+            left_edge_y = (GLE[:,py_index]+pyo-y0)*dy + yy0
+            right_edge_x = (GRE[:,px_index]+pxo-x0)*dx + xx0
+            right_edge_y = (GRE[:,py_index]+pyo-y0)*dy + yy0
+            visible =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
+                       ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix )
+            if visible.nonzero()[0].size == 0: continue
             verts = na.array(
-                [(left_edge_px, left_edge_px, right_edge_px, right_edge_px),
-                 (left_edge_py, right_edge_py, right_edge_py, left_edge_py)])
-            visible =  ( right_edge_px - left_edge_px > self.min_pix ) & \
-                       ( right_edge_px - left_edge_px > self.min_pix )
+                [(left_edge_x, left_edge_x, right_edge_x, right_edge_x),
+                 (left_edge_y, right_edge_y, right_edge_y, left_edge_y)])
             verts=verts.transpose()[visible,:,:]
-            if verts.size == 0: continue
             edgecolors = (0.0,0.0,0.0,self.alpha)
-            verts[:,:,0]= (xx1-xx0)*(verts[:,:,0]/width) + xx0
-            verts[:,:,1]= (yy1-yy0)*(verts[:,:,1]/height) + yy0
             grid_collection = matplotlib.collections.PolyCollection(
                 verts, facecolors="none",
                 edgecolors=edgecolors)
             plot._axes.hold(True)
             plot._axes.add_collection(grid_collection)
-            if self.annotate:
-                ids = [g.id for g in plot.data._grids]
-                for n in range(len(left_edge_px)):
-                    plot._axes.text(left_edge_px[n]+2,left_edge_py[n]+2,ids[n])
+            if self.draw_ids:
+                visible_ids =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix_ids ) & \
+                               ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids )
+                active_ids = na.unique(plot.data['GridIndices'])
+                for i in na.where(visible_ids)[0]:
+                    plot._axes.text(
+                        left_edge_x[i] + (2 * (xx1 - xx0) / xpix),
+                        left_edge_y[i] + (2 * (yy1 - yy0) / ypix),
+                        "%d" % active_ids[i], clip_on=True)
             plot._axes.hold(False)
 
 class StreamlineCallback(PlotCallback):


diff -r dd83c8b4e9774d4a6e7937fb52416d95f72e7522 -r a1a294fb7205fa2861e65527b09d815043c7d51e yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -189,8 +189,8 @@
     _contour_info = None
     _vector_info = None
     _frb = None
-    def __init__(self, data_source, bounds, buff_size=(800,800), antialias = True, 
-                 periodic = True, origin='center-window', oblique=False):
+    def __init__(self, data_source, bounds, buff_size=(800,800), antialias=True, 
+                 periodic=True, origin='center-window', oblique=False):
         r"""
         PlotWindow(data_source, bounds, buff_size=(800,800), antialias = True)
         
@@ -354,25 +354,48 @@
 
         parameters
         ----------
-        width : float, array of floats, or (float, unit) tuple.
-            the width of the image.
+        width : float, array of floats, (float, unit) tuple, or arry of (float, unit) tuples.
+             Width can have four different formats to support windows with variable 
+             x and y widths.  They are:
+             
+             ==================================     =======================
+             format                                 example                
+             ==================================     =======================
+             (float, string)                        (10,'kpc')
+             ((float, string), (float, string))     ((10,'kpc'),(15,'kpc'))
+             float                                  0.2
+             (float, float)                         (0.2, 0.3)
+             ==================================     =======================
+             
+             For example, (10, 'kpc') requests a plot window that is 10 kiloparsecs 
+             wide in the x and y directions, ((10,'kpc'),(15,'kpc')) requests a window 
+             that is 10 kiloparsecs wide along the x axis and 15 kiloparsecs wide along 
+             the y axis.  In the other two examples, code units are assumed, for example
+             (0.2, 0.3) requests a plot that has and x width of 0.2 and a y width of 0.3 
+             in code units.  the width of the image.
         unit : str
             the unit the width has been specified in.
             defaults to code units.  If width is a tuple this 
             argument is ignored
 
         """
-        if iterable(width) and isinstance(width[1],str):
-            unit = width[1]
-            width = width[0]
-        elif not iterable(width):
-            width = (width,width)
+        if iterable(width): 
+            if isinstance(width[1],str):
+                w, unit = width
+                width = (w, w)
+            elif isinstance(width[1], tuple):
+                wx,unitx = width[0]
+                wy,unity = width[1]
+                width = (wx/self.pf[unitx],wy/self.pf[unity])
+        else:
+            width = (width, width)
         Wx, Wy = width
         width = (Wx,Wy)
         width = [w / self.pf[unit] for w in width]
 
         centerx = (self.xlim[1] + self.xlim[0])/2 
         centery = (self.ylim[1] + self.ylim[0])/2 
+        
         self.xlim = (centerx - width[0]/2.,
                      centerx + width[0]/2.)
         self.ylim = (centery - width[1]/2.,
@@ -428,16 +451,17 @@
         pass
 
 class PWViewer(PlotWindow):
+    _unit = None
+    _colormaps = defaultdict(lambda: 'algae')
+    _callbacks = []
+    _field_transform = {}
     """A viewer for PlotWindows.
 
     """
     def __init__(self, *args,**kwargs):
         setup = kwargs.pop("setup", True)
         PlotWindow.__init__(self, *args,**kwargs)
-        self._colormaps = defaultdict(lambda: 'algae')
         self.setup_callbacks()
-        self._callbacks = []
-        self._field_transform = {}
         for field in self._frb.data.keys():
             if self.pf.field_info[field].take_log:
                 self._field_transform[field] = log_transform
@@ -554,13 +578,50 @@
             callback.__doc__ = CallbackMaker.__init__.__doc__
             self.__dict__['annotate_'+cbname] = types.MethodType(callback,self)
 
+    @invalidate_plot
+    def set_axes_unit(self, unit_name):
+        r"""Set the unit for display on the x and y axes of the image.
+
+        Parameters
+        ----------
+        unit_name : string
+            A unit, available for conversion in the parameter file, that the
+            image extents will be displayed in.  If set to None, any previous
+            units will be reset.  If the unit is None, the default is chosen.
+
+        Raises
+        ------
+        YTUnitNotRecognized
+            If the unit is not known, this will be raised.
+
+        Examples
+        --------
+
+        >>> p = ProjectionPlot(pf, "y", "Density")
+        >>> p.show()
+        >>> p.set_axes_unit("kpc")
+        >>> p.show()
+        >>> p.set_axes_unit(None)
+        >>> p.show()
+        """
+        # blind except because it could be in conversion_factors or units
+        try:
+            self.pf[unit_name]
+        except KeyError: 
+            if unit_name is not None:
+                raise YTUnitNotRecognized(unit_name)
+        self._unit = unit_name
+
     def get_metadata(self, field, strip_mathml = True, return_string = True):
         fval = self._frb[field]
         mi = fval.min()
         ma = fval.max()
         x_width = self.xlim[1] - self.xlim[0]
         y_width = self.ylim[1] - self.ylim[0]
-        unit = get_smallest_appropriate_unit(x_width, self.pf)
+        if self._unit is None:
+            unit = get_smallest_appropriate_unit(x_width, self.pf)
+        else:
+            unit = self._unit
         units = self.get_field_units(field, strip_mathml)
         center = getattr(self._frb.data_source, "center", None)
         if center is None or self._frb.axis == 4:
@@ -647,10 +708,12 @@
 
             # This sets the size of the figure, and defaults to making one of the dimensions smaller.
             # This should protect against giant images in the case of a very large aspect ratio.
+            norm_size = 10.0
+            cbar_frac = 0.0
             if aspect > 1.0:
-                size = (10.0, 10.0/aspect)
+                size = (norm_size*(1.+cbar_frac), norm_size/aspect)
             else:
-                size = (10.0*aspect, 10.0)
+                size = (aspect*norm_size*(1.+cbar_frac), norm_size)
 
             self.plots[f] = WindowPlotMPL(self._frb[f], extent, self._field_transform[f], 
                                           self._colormaps[f], size, zlim)
@@ -672,10 +735,12 @@
             self.plots[f].axes.set_xlabel(labels[0])
             self.plots[f].axes.set_ylabel(labels[1])
 
+            field_name = self.data_source.pf.field_info[f].display_name
+            if field_name is None: field_name = f
             if md['units'] == None or md['units'] == '':
-                label = r'$\rm{'+f.encode('string-escape')+r'}$'
+                label = r'$\rm{'+field_name.encode('string-escape')+r'}$'
             else:
-                label = r'$\rm{'+f.encode('string-escape')+r'}\/\/('+md['units']+r')$'
+                label = r'$\rm{'+field_name.encode('string-escape')+r'}\/\/('+md['units']+r')$'
 
             self.plots[f].cb.set_label(label)
 
@@ -790,7 +855,8 @@
             raise YTNotInsideNotebook
 
 class SlicePlot(PWViewerMPL):
-    def __init__(self, pf, axis, fields, center='c', width=None, origin='center-window'):
+    def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
+                 origin='center-window'):
         r"""Creates a slice plot from a parameter file
         
         Given a pf object, an axis to slice along, and a field name
@@ -810,11 +876,12 @@
              or the axis name itself
         fields : string
              The name of the field(s) to be plotted.
-        center : two or three-element vector of sequence floats, 'c', or 'center'
+        center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'
              The coordinate of the center of the image.  If left blanck,
              the image centers on the location of the maximum density
              cell.  If set to 'c' or 'center', the plot is centered on
-             the middle of the domain.
+             the middle of the domain.  If set to 'max', will be at the point
+             of highest density.
         width : tuple or a float.
              Width can have four different formats to support windows with variable 
              x and y widths.  They are:
@@ -834,6 +901,9 @@
              the y axis.  In the other two examples, code units are assumed, for example
              (0.2, 0.3) requests a plot that has and x width of 0.2 and a y width of 0.3 
              in code units.  
+        axes_unit : A string
+            The name of the unit for the tick labels on the x and y axes.  
+            Defaults to None, which automatically picks an appropriate unit.
         origin : string
              The location of the origin of the plot coordinate system.
              Currently, can be set to three options: 'left-domain', corresponding
@@ -855,9 +925,10 @@
         (bounds,center) = GetBoundsAndCenter(axis, center, width, pf)
         slc = pf.h.slice(axis, center[axis], fields=fields)
         PWViewerMPL.__init__(self, slc, bounds, origin=origin)
+        self.set_axes_unit(axes_unit)
 
 class ProjectionPlot(PWViewerMPL):
-    def __init__(self, pf, axis, fields, center='c', width=None,
+    def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
                  weight_field=None, max_level=None, origin='center-window'):
         r"""Creates a projection plot from a parameter file
         
@@ -878,11 +949,12 @@
              or the axis name itself
         fields : string
             The name of the field(s) to be plotted.
-        center : A two or three-element vector of sequence floats, 'c', or 'center'
-            The coordinate of the center of the image.  If left blanck,
-            the image centers on the location of the maximum density
-            cell.  If set to 'c' or 'center', the plot is centered on
-            the middle of the domain.
+        center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'
+             The coordinate of the center of the image.  If left blanck,
+             the image centers on the location of the maximum density
+             cell.  If set to 'c' or 'center', the plot is centered on
+             the middle of the domain.  If set to 'max', will be at the point
+             of highest density.
         width : tuple or a float.
              Width can have four different formats to support windows with variable 
              x and y widths.  They are:
@@ -902,6 +974,9 @@
              the y axis.  In the other two examples, code units are assumed, for example
              (0.2, 0.3) requests a plot that has and x width of 0.2 and a y width of 0.3 
              in code units.
+        axes_unit : A string
+            The name of the unit for the tick labels on the x and y axes.  
+            Defaults to None, which automatically picks an appropriate unit.
         origin : A string
             The location of the origin of the plot coordinate system.
             Currently, can be set to three options: 'left-domain', corresponding
@@ -927,9 +1002,11 @@
         (bounds,center) = GetBoundsAndCenter(axis,center,width,pf)
         proj = pf.h.proj(axis,fields,weight_field=weight_field,max_level=max_level,center=center)
         PWViewerMPL.__init__(self,proj,bounds,origin=origin)
+        self.set_axes_unit(axes_unit)
 
 class OffAxisSlicePlot(PWViewerMPL):
-    def __init__(self, pf, normal, fields, center='c', width=(1,'unitary'), north_vector=None):
+    def __init__(self, pf, normal, fields, center='c', width=(1,'unitary'), 
+                 axes_unit=None, north_vector=None):
         r"""Creates an off axis slice plot from a parameter file
 
         Given a pf object, a normal vector defining a slicing plane, and
@@ -957,6 +1034,9 @@
             A tuple containing the width of image and the string key of
             the unit: (width, 'unit').  If set to a float, code units
             are assumed
+        axes_unit : A string
+            The name of the unit for the tick labels on the x and y axes.  
+            Defaults to None, which automatically picks an appropriate unit.
         north-vector : a sequence of floats
             A vector defining the 'up' direction in the plot.  This
             option sets the orientation of the slicing plane.  If not
@@ -968,6 +1048,7 @@
         # Hard-coding the origin keyword since the other two options
         # aren't well-defined for off-axis data objects
         PWViewerMPL.__init__(self,cutting,bounds,origin='center-window',periodic=False,oblique=True)
+        self.set_axes_unit(axes_unit)
 
 _metadata_template = """
 %(pf)s<br>
@@ -1147,10 +1228,13 @@
     figure = None
     def __init__(self, field, size):
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize = size, frameon = True)
+        fsize, axrect, caxrect = self._get_best_layout(size)
         # Hardcoding the axis dimensions for now
-        self.axes = self.figure.add_axes((.07,.10,.8,.8))
-        self.cax = self.figure.add_axes((.87,.10,.04,.8))
+        
+        self.figure = matplotlib.figure.Figure(figsize = fsize, 
+                                               frameon = True)
+        self.axes = self.figure.add_axes(axrect)
+        self.cax = self.figure.add_axes(caxrect)
 
     def save(self, name, canvas = None):
         if name[-4:] == '.png':
@@ -1169,9 +1253,47 @@
             else:
                 mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
                 canvas = FigureCanvasAgg(self.figure)
-        canvas.print_figure(fn, bbox_inches='tight')
+        canvas.print_figure(fn)
         return fn
 
+    def _get_best_layout(self, size):
+        aspect = 1.0*size[0]/size[1]
+
+        # add room for a colorbar
+        cbar_inches = 0.7
+        newsize = [size[0] + cbar_inches, size[1]]
+        
+        # add buffers for text, and a bit of whitespace on top
+        text_buffx = 1.0/(newsize[0])
+        text_bottomy = 0.7/size[1]
+        text_topy = 0.3/size[1]
+
+        # calculate how much room the colorbar takes
+        cbar_frac = cbar_inches/newsize[0] 
+        
+        # Calculate y fraction, then use to make x fraction.
+        yfrac = 1.0-text_bottomy-text_topy
+        ysize = yfrac*size[1]
+        xsize = aspect*ysize
+        xfrac = xsize/newsize[0]
+
+        # Now make sure it all fits!
+        xbig = xfrac + text_buffx + 2.0*cbar_frac
+        ybig = yfrac + text_bottomy + text_topy
+
+        if xbig > 1:
+            xsize /= xbig
+            ysize /= xbig
+        if ybig > 1:
+            xsize /= ybig
+            ysize /= ybig
+        xfrac = xsize/newsize[0]
+        yfrac = ysize/newsize[1]
+
+        axrect = (text_buffx, text_bottomy, xfrac, yfrac )
+        caxrect = (text_buffx+xfrac, text_bottomy, cbar_frac/4., yfrac )
+        return newsize, axrect, caxrect
+
     def _repr_png_(self):
         canvas = FigureCanvasAgg(self.figure)
         f = cStringIO.StringIO()
@@ -1193,3 +1315,5 @@
         self.image = self.axes.imshow(data, origin='lower', extent = extent,
                                       norm = norm, vmin = self.zmin, 
                                       vmax = self.zmax, cmap = cmap)
+        self.image.axes.ticklabel_format(scilimits=(-4,3))
+



https://bitbucket.org/yt_analysis/yt/changeset/8a25dddac85f/
changeset:   8a25dddac85f
branch:      yt
user:        samskillman
date:        2012-09-05 18:32:57
summary:     Adding docstrings about the unit labels when set to 1, u, or unitary.
affected #:  1 file

diff -r a1a294fb7205fa2861e65527b09d815043c7d51e -r 8a25dddac85f759ba83671b1799d69ff0732a717 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -588,6 +588,8 @@
             A unit, available for conversion in the parameter file, that the
             image extents will be displayed in.  If set to None, any previous
             units will be reset.  If the unit is None, the default is chosen.
+            If unit_name is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
 
         Raises
         ------
@@ -904,6 +906,8 @@
         axes_unit : A string
             The name of the unit for the tick labels on the x and y axes.  
             Defaults to None, which automatically picks an appropriate unit.
+            If axes_unit is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
         origin : string
              The location of the origin of the plot coordinate system.
              Currently, can be set to three options: 'left-domain', corresponding
@@ -977,6 +981,8 @@
         axes_unit : A string
             The name of the unit for the tick labels on the x and y axes.  
             Defaults to None, which automatically picks an appropriate unit.
+            If axes_unit is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
         origin : A string
             The location of the origin of the plot coordinate system.
             Currently, can be set to three options: 'left-domain', corresponding
@@ -1037,6 +1043,8 @@
         axes_unit : A string
             The name of the unit for the tick labels on the x and y axes.  
             Defaults to None, which automatically picks an appropriate unit.
+            If axes_unit is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
         north-vector : a sequence of floats
             A vector defining the 'up' direction in the plot.  This
             option sets the orientation of the slicing plane.  If not



https://bitbucket.org/yt_analysis/yt/changeset/2825fd89deeb/
changeset:   2825fd89deeb
branch:      yt
user:        ngoldbaum
date:        2012-09-05 20:45:02
summary:     Merged in samskillman/yt (pull request #265)
affected #:  1 file

diff -r 1a3c927ef00cd6469864c6b8759c3574805ad092 -r 2825fd89deeba490c2d5dfc1c0200ed5493f0a1f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -588,6 +588,8 @@
             A unit, available for conversion in the parameter file, that the
             image extents will be displayed in.  If set to None, any previous
             units will be reset.  If the unit is None, the default is chosen.
+            If unit_name is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
 
         Raises
         ------
@@ -720,13 +722,18 @@
             self.plots[f].cb = self.plots[f].figure.colorbar(
                 self.plots[f].image, cax = self.plots[f].cax)
 
+            if not md['unit'] in ['1', 'u', 'unitary']:
+                axes_unit_label = '\/\/('+md['unit'].encode('string-escape')+')'
+            else:
+                axes_unit_label = ''
+
             if self.oblique == False:
                 labels = [r'$\rm{'+axis_labels[axis_index][i].encode('string-escape')+
-                          r'\/\/('+md['unit'].encode('string-escape')+r')}$' for i in (0,1)]
+                        axes_unit_label + r'}$' for i in (0,1)]
             else:
-                labels = [r'$\rm{Image\/x}\/\/\rm{('+md['unit'].encode('string-escape')+r')}$',
-                          r'$\rm{Image\/y}\/\/\rm{('+md['unit'].encode('string-escape')+r')}$']
-                
+                labels = [r'$\rm{Image\/x'+axes_unit_label+'}$',
+                          r'$\rm{Image\/y'+axes_unit_label+'}$']
+
             self.plots[f].axes.set_xlabel(labels[0])
             self.plots[f].axes.set_ylabel(labels[1])
 
@@ -899,6 +906,8 @@
         axes_unit : A string
             The name of the unit for the tick labels on the x and y axes.  
             Defaults to None, which automatically picks an appropriate unit.
+            If axes_unit is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
         origin : string
              The location of the origin of the plot coordinate system.
              Currently, can be set to three options: 'left-domain', corresponding
@@ -972,6 +981,8 @@
         axes_unit : A string
             The name of the unit for the tick labels on the x and y axes.  
             Defaults to None, which automatically picks an appropriate unit.
+            If axes_unit is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
         origin : A string
             The location of the origin of the plot coordinate system.
             Currently, can be set to three options: 'left-domain', corresponding
@@ -1032,6 +1043,8 @@
         axes_unit : A string
             The name of the unit for the tick labels on the x and y axes.  
             Defaults to None, which automatically picks an appropriate unit.
+            If axes_unit is '1', 'u', or 'unitary', it will not display the 
+            units, and only show the axes name.
         north-vector : a sequence of floats
             A vector defining the 'up' direction in the plot.  This
             option sets the orientation of the slicing plane.  If not

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