[yt-svn] commit/yt-3.0: 163 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Sat Aug 17 08:51:54 PDT 2013


163 new commits in yt-3.0:

https://bitbucket.org/yt_analysis/yt-3.0/commits/ca2d16d5733d/
Changeset:   ca2d16d5733d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-16 19:46:51
Summary:     Have detected fields formatted correctly
Affected #:  1 file

diff -r 44637ca2b97b0a33b3986163ed4f1bfa7d3a3cbf -r ca2d16d5733dfceff01f6de8e1dc345e7bac799a yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -177,7 +177,7 @@
         self.fluid_field_list = self._detect_fluid_fields()
         self.particle_field_list = self._detect_particle_fields()
         self.field_list = self.fluid_field_list + self.particle_field_list
-        mylog.debug("Detected fields:", self.field_list)
+        mylog.debug("Detected fields:", (self.field_list,))
 
     def _detect_fluid_fields(self):
         return [art_to_yt[f] for f in yt_to_art.values() if f in


https://bitbucket.org/yt_analysis/yt-3.0/commits/95b22808fd62/
Changeset:   95b22808fd62
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-16 19:51:42
Summary:     First pass at a new ARTIOOctreeContainer that can be dynamically generated for
subsets of SFC values.
Affected #:  2 files

diff -r ca2d16d5733dfceff01f6de8e1dc345e7bac799a -r 95b22808fd621b7b738ed8259ca9ab3ca55c9038 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -7,6 +7,10 @@
 import sys 
 
 from yt.geometry.selection_routines cimport SelectorObject
+from yt.geometry.oct_container cimport \
+    OctreeContainer, OctAllocationContainer
+from yt.geometry.oct_visitors cimport \
+    OctVisitorData, oct_visitor_function, Oct
 from libc.stdint cimport int32_t, int64_t
 from libc.stdlib cimport malloc, free
 import  data_structures  
@@ -103,8 +107,12 @@
     int artio_particle_read_species_begin(artio_fileset_handle *handle, int species)
     int artio_particle_read_species_end(artio_fileset_handle *handle) 
    
+    
+cdef extern from "artio_internal.h":
+    np.int64_t artio_sfc_index( artio_fileset_handle *handle, int coords[3] )
+    void artio_sfc_coords( artio_fileset_handle *handle, int64_t index, int coords[3] )
 
-cdef check_artio_status(int status, char *fname="[unknown]"):
+cdef void check_artio_status(int status, char *fname="[unknown]"):
     if status!=ARTIO_SUCCESS :
         callername = sys._getframe().f_code.co_name
         nline = sys._getframe().f_lineno
@@ -513,3 +521,155 @@
     else :
         artio_fileset_close(handle) 
     return True
+
+cdef class ARTIOOctreeContainer(OctreeContainer):
+    # This is a transitory, created-on-demand OctreeContainer.  It should not
+    # be considered to be long-lasting, and during its creation it will read
+    # the index file.  This means that when created it will then be able to
+    # provide coordinates, but then on subsequent IO accesses it will pass over
+    # the file again, despite knowing the indexing system already.  Because of
+    # this, we will avoid creating it as long as possible.
+
+    cdef public np.int64_t sfc_start
+    cdef public np.int64_t sfc_end
+    cdef public artio_fileset artio_handle
+    cdef Oct **root_octs
+
+    def __init__(self, domain_dimensions, domain_left_edge, domain_right_edge,
+                 int64_t sfc_start, int64_t sfc_end, artio_fileset artio_handle):
+        self.root_octs = NULL
+        self.sfc_start = sfc_start
+        self.sfc_end = sfc_end
+        self.artio_handle = artio_handle
+        self.max_domain = 1
+        # Note the final argument is partial_coverage, which indicates whether
+        # or not an Oct can be partially refined.
+        super(ARTIOOctreeContainer, self).__init__(domain_dimensions,
+            domain_left_edge, domain_right_edge, 1)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    def _initialize_root_mesh(self):
+        # We actually will not be initializing the root mesh here, we will be
+        # initializing the entire mesh between sfc_start and sfc_end.
+        cdef np.int64_t oct_ind, sfc, nadded, tot_octs
+        cdef int status
+        cdef artio_fileset_handle *handle = self.artio_handle.handle
+        cdef double dpos[3]
+        cdef int num_oct_levels, level, i
+        cdef int max_level = self.artio_handle.max_level
+        cdef int *num_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
+        cdef int *tot_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
+        cdef int *ind_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
+        for level in range(max_level + 1):
+            tot_octs_per_level[level] = 0
+        status = artio_grid_cache_sfc_range(handle,
+            self.sfc_start, self.sfc_end )
+        check_artio_status(status) 
+        status = artio_grid_count_octs_in_sfc_range(
+                handle, self.sfc_start, self.sfc_end, &tot_octs )
+        tot_octs += ((self.sfc_end + 1) - self.sfc_start) # Root octs
+        # Now we iterate and create them, level by level.
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            status = artio_grid_read_root_cell_begin( handle, sfc, 
+                    dpos, NULL, &num_oct_levels, num_octs_per_level )
+            check_artio_status(status) 
+            tot_octs_per_level[0] += 1
+            for level in range(num_oct_levels):
+                # Now we are simply counting so we can pre-allocate arrays.
+                # Because the grids have all been cached this should be fine.
+                tot_octs_per_level[level + 1] += num_octs_per_level[level]
+            status = artio_grid_read_root_cell_end( handle )
+            check_artio_status(status)
+        cdef np.int64_t tot = 0
+        for i in range(max_level + 1):
+            tot += tot_octs_per_level[i]
+            if i > 0:
+                ind_octs_per_level[i] = \
+                    ind_octs_per_level[i-1] + tot_octs_per_level[i-1]
+            else:
+                ind_octs_per_level[i] = 0
+        self.allocate_domains([tot])
+        self.root_octs = <Oct **> malloc(sizeof(Oct *) * tot_octs_per_level[0])
+        for i in range(tot_octs_per_level[0]):
+            self.root_octs[i] = NULL
+        # Now we have everything counted, and we need to create the appropriate
+        # number of arrays.
+        cdef np.ndarray[np.float64_t, ndim=2] pos
+        pos = np.empty((tot, 3), dtype="float64")
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            status = artio_grid_read_root_cell_begin( handle, sfc, 
+                    dpos, NULL, &num_oct_levels, num_octs_per_level )
+            check_artio_status(status) 
+            for i in range(3):
+                pos[ind_octs_per_level[0], i] = dpos[i]
+            ind_octs_per_level[0] += 1
+            # Now we iterate over all the children
+            for level in range(1, num_oct_levels+1):
+                status = artio_grid_read_level_begin(handle, level)
+                check_artio_status(status) 
+                for oct_ind in range(num_octs_per_level[level - 1]):
+                    status = artio_grid_read_oct(handle, dpos, NULL, NULL)
+                    check_artio_status(status)
+                    for i in range(3):
+                        pos[ind_octs_per_level[level], i] = dpos[i]
+                    ind_octs_per_level[level] += 1
+                status = artio_grid_read_level_end(handle)
+                check_artio_status(status)
+            status = artio_grid_read_root_cell_end( handle )
+            check_artio_status(status)
+        nadded = self.add(1, 0, pos[:tot_octs_per_level[0], :])
+        for level in range(1, max_level + 1):
+            if tot_octs_per_level[level] == 0: break
+            nadded += self.add(1, level,
+                pos[nadded:nadded+tot_octs_per_level[level], :])
+        assert(tot - nadded == 0)
+        free(num_octs_per_level)
+        free(tot_octs_per_level)
+        free(ind_octs_per_level)
+
+    # These are the items we need to subclass
+    cdef void visit_all_octs(self, SelectorObject selector,
+                        oct_visitor_function *func,
+                        OctVisitorData *data):
+        cdef np.int64_t index, j
+        cdef int coords[3]
+        cdef int i, vc
+        cdef np.float64_t pos[3], dds[3]
+        for i in range(3):
+            dds[i] = (self.DRE[i] - self.DLE[i]) / self.nn[i]
+        cdef Oct *o
+        vc = self.partial_coverage
+        for index in range(self.sfc_start, self.sfc_end + 1):
+            artio_sfc_coords(self.artio_handle.handle, index, coords)
+            for j in range(3):
+                pos[j] = self.DLE[j] + (coords[j] + 0.5) * dds[j]
+            selector.recursively_visit_octs(
+                o, pos, dds, 0, func, data, vc)
+    
+    def __dealloc__(self):
+        if self.root_octs != NULL: free(self.root_octs)
+        if self.domains != NULL: free(self.domains)
+
+    cdef Oct* next_root(self, int domain_id, int ind[3]):
+        # NOTE: We don't care about domain_id here.
+        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, ind)
+        cdef Oct *next = self.root_octs[index - self.sfc_start]
+        if next != NULL: return next
+        cdef OctAllocationContainer *cont = self.domains[0]
+        if cont.n_assigned >= cont.n: raise RuntimeError
+        next = &cont.my_octs[cont.n_assigned]
+        self.root_octs[index - self.sfc_start] = next
+        cont.n_assigned += 1
+        self.nocts += 1
+        return next
+
+    cdef int get_root(self, int ind[3], Oct **o):
+        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, ind)
+        o[0] = self.root_octs[index - self.sfc_start]
+        return 1
+

diff -r ca2d16d5733dfceff01f6de8e1dc345e7bac799a -r 95b22808fd621b7b738ed8259ca9ab3ca55c9038 yt/geometry/oct_container.pxd
--- a/yt/geometry/oct_container.pxd
+++ b/yt/geometry/oct_container.pxd
@@ -56,7 +56,7 @@
     cdef int partial_coverage
     cdef int nn[3]
     cdef np.float64_t DLE[3], DRE[3]
-    cdef public int nocts
+    cdef public np.int64_t nocts
     cdef public int max_domain
     cdef Oct *get(self, np.float64_t ppos[3], OctInfo *oinfo = ?)
     cdef int get_root(self, int ind[3], Oct **o)


https://bitbucket.org/yt_analysis/yt-3.0/commits/cb5446fbcab1/
Changeset:   cb5446fbcab1
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-16 22:26:39
Summary:     A few more changes before fixing the root mesh issues.
Affected #:  1 file

diff -r 95b22808fd621b7b738ed8259ca9ab3ca55c9038 -r cb5446fbcab17088075583726fedaed74c663eae yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -537,6 +537,8 @@
 
     def __init__(self, domain_dimensions, domain_left_edge, domain_right_edge,
                  int64_t sfc_start, int64_t sfc_end, artio_fileset artio_handle):
+        if sfc_start % 8 != 0 or sfc_end % 8 != 0:
+            raise RuntimeError
         self.root_octs = NULL
         self.sfc_start = sfc_start
         self.sfc_end = sfc_end
@@ -572,28 +574,23 @@
         check_artio_status(status) 
         status = artio_grid_count_octs_in_sfc_range(
                 handle, self.sfc_start, self.sfc_end, &tot_octs )
-        tot_octs += ((self.sfc_end + 1) - self.sfc_start) # Root octs
         # Now we iterate and create them, level by level.
         for sfc in range(self.sfc_start, self.sfc_end + 1):
             status = artio_grid_read_root_cell_begin( handle, sfc, 
                     dpos, NULL, &num_oct_levels, num_octs_per_level )
             check_artio_status(status) 
             tot_octs_per_level[0] += 1
-            for level in range(num_oct_levels):
+            for level in range(1, num_oct_levels+1):
                 # Now we are simply counting so we can pre-allocate arrays.
                 # Because the grids have all been cached this should be fine.
-                tot_octs_per_level[level + 1] += num_octs_per_level[level]
+                tot_octs_per_level[level] += num_octs_per_level[level-1]
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
         cdef np.int64_t tot = 0
         for i in range(max_level + 1):
+            ind_octs_per_level[i] = tot
             tot += tot_octs_per_level[i]
-            if i > 0:
-                ind_octs_per_level[i] = \
-                    ind_octs_per_level[i-1] + tot_octs_per_level[i-1]
-            else:
-                ind_octs_per_level[i] = 0
-        self.allocate_domains([tot])
+        self.allocate_domains([tot*2])
         self.root_octs = <Oct **> malloc(sizeof(Oct *) * tot_octs_per_level[0])
         for i in range(tot_octs_per_level[0]):
             self.root_octs[i] = NULL
@@ -622,12 +619,16 @@
                 check_artio_status(status)
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
-        nadded = self.add(1, 0, pos[:tot_octs_per_level[0], :])
-        for level in range(1, max_level + 1):
+        nadded = 0
+        cdef np.int64_t si, ei
+        si = 0
+        for level in range(max_level + 1):
+            ei = si + tot_octs_per_level[level]
             if tot_octs_per_level[level] == 0: break
-            nadded += self.add(1, level,
-                pos[nadded:nadded+tot_octs_per_level[level], :])
-        assert(tot - nadded == 0)
+            nadded = self.add(1, level, pos[si:ei, :])
+            assert(nadded == (ei-si))
+            si = ei
+        artio_grid_clear_sfc_cache(handle)
         free(num_octs_per_level)
         free(tot_octs_per_level)
         free(ind_octs_per_level)
@@ -648,6 +649,7 @@
             artio_sfc_coords(self.artio_handle.handle, index, coords)
             for j in range(3):
                 pos[j] = self.DLE[j] + (coords[j] + 0.5) * dds[j]
+            o = self.root_octs[index - self.sfc_start]
             selector.recursively_visit_octs(
                 o, pos, dds, 0, func, data, vc)
     
@@ -657,7 +659,12 @@
 
     cdef Oct* next_root(self, int domain_id, int ind[3]):
         # NOTE: We don't care about domain_id here.
-        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, ind)
+        cdef int i, i2[3]
+        for i in range(3):
+            i2[i] = ind[2-i]
+        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, i2)
+        assert(index <= self.sfc_end)
+        assert(index >= self.sfc_start)
         cdef Oct *next = self.root_octs[index - self.sfc_start]
         if next != NULL: return next
         cdef OctAllocationContainer *cont = self.domains[0]
@@ -669,7 +676,10 @@
         return next
 
     cdef int get_root(self, int ind[3], Oct **o):
-        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, ind)
+        cdef int i, i2[3]
+        for i in range(3):
+            i2[i] = ind[2-i]
+        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, i2)
         o[0] = self.root_octs[index - self.sfc_start]
         return 1
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/d0c1756daf37/
Changeset:   d0c1756daf37
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-17 00:28:48
Summary:     Setting up masks and changing RAMSESOctreeContainer to SparseOctreeContainer.

We now set up a masked set of root-level Octs for ARTIO.  This will be handled
in more detail in the IO process.
Affected #:  3 files

diff -r cb5446fbcab17088075583726fedaed74c663eae -r d0c1756daf374bf69e58538f90b549b8b274071d yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -8,7 +8,8 @@
 
 from yt.geometry.selection_routines cimport SelectorObject
 from yt.geometry.oct_container cimport \
-    OctreeContainer, OctAllocationContainer
+    OctreeContainer, OctAllocationContainer, \
+    SparseOctreeContainer
 from yt.geometry.oct_visitors cimport \
     OctVisitorData, oct_visitor_function, Oct
 from libc.stdint cimport int32_t, int64_t
@@ -522,7 +523,12 @@
         artio_fileset_close(handle) 
     return True
 
-cdef class ARTIOOctreeContainer(OctreeContainer):
+def get_coords(artio_fileset handle, np.int64_t s):
+    cdef int coords[3]
+    artio_sfc_coords(handle.handle, s, coords)
+    return (coords[0], coords[1], coords[2])
+
+cdef class ARTIOOctreeContainer(SparseOctreeContainer):
     # This is a transitory, created-on-demand OctreeContainer.  It should not
     # be considered to be long-lasting, and during its creation it will read
     # the index file.  This means that when created it will then be able to
@@ -535,19 +541,16 @@
     cdef public artio_fileset artio_handle
     cdef Oct **root_octs
 
-    def __init__(self, domain_dimensions, domain_left_edge, domain_right_edge,
+    def __init__(self, oct_dimensions, domain_left_edge, domain_right_edge,
                  int64_t sfc_start, int64_t sfc_end, artio_fileset artio_handle):
-        if sfc_start % 8 != 0 or sfc_end % 8 != 0:
-            raise RuntimeError
-        self.root_octs = NULL
+        self.artio_handle = artio_handle
         self.sfc_start = sfc_start
         self.sfc_end = sfc_end
-        self.artio_handle = artio_handle
-        self.max_domain = 1
         # Note the final argument is partial_coverage, which indicates whether
         # or not an Oct can be partially refined.
-        super(ARTIOOctreeContainer, self).__init__(domain_dimensions,
-            domain_left_edge, domain_right_edge, 1)
+        super(ARTIOOctreeContainer, self).__init__(oct_dimensions,
+            domain_left_edge, domain_right_edge)
+        self._initialize_root_mesh()
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -555,11 +558,13 @@
     def _initialize_root_mesh(self):
         # We actually will not be initializing the root mesh here, we will be
         # initializing the entire mesh between sfc_start and sfc_end.
-        cdef np.int64_t oct_ind, sfc, nadded, tot_octs
+        cdef np.int64_t oct_ind, sfc, nadded, tot_octs, ipos
+        cdef np.uint8_t bits
         cdef int status
         cdef artio_fileset_handle *handle = self.artio_handle.handle
         cdef double dpos[3]
-        cdef int num_oct_levels, level, i
+        cdef int coords[3]
+        cdef int num_oct_levels, level, i, j
         cdef int max_level = self.artio_handle.max_level
         cdef int *num_octs_per_level = <int *>malloc(
             (max_level + 1)*sizeof(int))
@@ -575,36 +580,64 @@
         status = artio_grid_count_octs_in_sfc_range(
                 handle, self.sfc_start, self.sfc_end, &tot_octs )
         # Now we iterate and create them, level by level.
+        # Note that we are doing a bit of magic to figure out how many root
+        # nodes we will need at most
+        cdef int nmask = self.nn[0] * self.nn[1] * self.nn[2] / 8
+        cdef np.uint8_t *mask = <np.uint8_t *> malloc(
+            self.nn[0] * self.nn[1] * self.nn[2]) # one bit for each one
+        for i in range(nmask): mask[i] = 0
         for sfc in range(self.sfc_start, self.sfc_end + 1):
             status = artio_grid_read_root_cell_begin( handle, sfc, 
                     dpos, NULL, &num_oct_levels, num_octs_per_level )
             check_artio_status(status) 
-            tot_octs_per_level[0] += 1
+            artio_sfc_coords(handle, sfc, coords)
+            # Now we mask that bit
+            for i in range(3):
+                coords[i] = <int> (coords[i]/2)
+            ipos = ((coords[0]*self.nn[1])+coords[1])*self.nn[2]+coords[2]
+            bits = ipos % 8
+            mask[ <int> (ipos/8) ] |= (1 << bits)
             for level in range(1, num_oct_levels+1):
                 # Now we are simply counting so we can pre-allocate arrays.
                 # Because the grids have all been cached this should be fine.
                 tot_octs_per_level[level] += num_octs_per_level[level-1]
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
+        cdef np.int64_t num_root = 0
+        for i in range(nmask):
+            for j in range(8):
+                num_root += ((mask[i] >> j) & 1)
+        tot_octs_per_level[0] = num_root
         cdef np.int64_t tot = 0
         for i in range(max_level + 1):
             ind_octs_per_level[i] = tot
             tot += tot_octs_per_level[i]
-        self.allocate_domains([tot*2])
-        self.root_octs = <Oct **> malloc(sizeof(Oct *) * tot_octs_per_level[0])
-        for i in range(tot_octs_per_level[0]):
-            self.root_octs[i] = NULL
+        self.allocate_domains([tot], num_root)
         # Now we have everything counted, and we need to create the appropriate
         # number of arrays.
         cdef np.ndarray[np.float64_t, ndim=2] pos
         pos = np.empty((tot, 3), dtype="float64")
+        # We do a special case for level 0
+        cdef np.float64_t dds[3]
+        for i in range(3):
+            dds[i] = (self.DRE[i] - self.DLE[i])/self.nn[i]
         for sfc in range(self.sfc_start, self.sfc_end + 1):
             status = artio_grid_read_root_cell_begin( handle, sfc, 
-                    dpos, NULL, &num_oct_levels, num_octs_per_level )
+                    dpos, NULL, &num_oct_levels, num_octs_per_level)
             check_artio_status(status) 
+            artio_sfc_coords(handle, sfc, coords)
+            # Now we check if we have added yet or not
             for i in range(3):
-                pos[ind_octs_per_level[0], i] = dpos[i]
-            ind_octs_per_level[0] += 1
+                coords[i] = <int> (coords[i]/2)
+            ipos = ((coords[0]*self.nn[1])+coords[1])*self.nn[2]+coords[2]
+            bits = ipos % 8
+            if ((mask[<int>(ipos/8)] >> bits) & 1) == 1:
+                # We add it here
+                for i in range(3):
+                    dpos[i] = self.DLE[i] + (coords[i]+0.5)*dds[i]
+                    pos[ind_octs_per_level[0], i] = dpos[i]
+                mask[<int>(ipos/8)] -= (1 << bits)
+                ind_octs_per_level[0] += 1
             # Now we iterate over all the children
             for level in range(1, num_oct_levels+1):
                 status = artio_grid_read_level_begin(handle, level)
@@ -620,66 +653,20 @@
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
         nadded = 0
+        free(mask)
         cdef np.int64_t si, ei
         si = 0
         for level in range(max_level + 1):
             ei = si + tot_octs_per_level[level]
             if tot_octs_per_level[level] == 0: break
             nadded = self.add(1, level, pos[si:ei, :])
-            assert(nadded == (ei-si))
+            if nadded != (ei - si):
+                print level, nadded, ei, si, self.max_root,
+                print ind_octs_per_level[level]
+                print pos[si:ei,:]
+                raise RuntimeError
             si = ei
         artio_grid_clear_sfc_cache(handle)
         free(num_octs_per_level)
         free(tot_octs_per_level)
         free(ind_octs_per_level)
-
-    # These are the items we need to subclass
-    cdef void visit_all_octs(self, SelectorObject selector,
-                        oct_visitor_function *func,
-                        OctVisitorData *data):
-        cdef np.int64_t index, j
-        cdef int coords[3]
-        cdef int i, vc
-        cdef np.float64_t pos[3], dds[3]
-        for i in range(3):
-            dds[i] = (self.DRE[i] - self.DLE[i]) / self.nn[i]
-        cdef Oct *o
-        vc = self.partial_coverage
-        for index in range(self.sfc_start, self.sfc_end + 1):
-            artio_sfc_coords(self.artio_handle.handle, index, coords)
-            for j in range(3):
-                pos[j] = self.DLE[j] + (coords[j] + 0.5) * dds[j]
-            o = self.root_octs[index - self.sfc_start]
-            selector.recursively_visit_octs(
-                o, pos, dds, 0, func, data, vc)
-    
-    def __dealloc__(self):
-        if self.root_octs != NULL: free(self.root_octs)
-        if self.domains != NULL: free(self.domains)
-
-    cdef Oct* next_root(self, int domain_id, int ind[3]):
-        # NOTE: We don't care about domain_id here.
-        cdef int i, i2[3]
-        for i in range(3):
-            i2[i] = ind[2-i]
-        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, i2)
-        assert(index <= self.sfc_end)
-        assert(index >= self.sfc_start)
-        cdef Oct *next = self.root_octs[index - self.sfc_start]
-        if next != NULL: return next
-        cdef OctAllocationContainer *cont = self.domains[0]
-        if cont.n_assigned >= cont.n: raise RuntimeError
-        next = &cont.my_octs[cont.n_assigned]
-        self.root_octs[index - self.sfc_start] = next
-        cont.n_assigned += 1
-        self.nocts += 1
-        return next
-
-    cdef int get_root(self, int ind[3], Oct **o):
-        cdef int i, i2[3]
-        for i in range(3):
-            i2[i] = ind[2-i]
-        cdef np.int64_t index = artio_sfc_index(self.artio_handle.handle, i2)
-        o[0] = self.root_octs[index - self.sfc_start]
-        return 1
-

diff -r cb5446fbcab17088075583726fedaed74c663eae -r d0c1756daf374bf69e58538f90b549b8b274071d yt/geometry/oct_container.pxd
--- a/yt/geometry/oct_container.pxd
+++ b/yt/geometry/oct_container.pxd
@@ -71,12 +71,15 @@
     cdef Oct *next_root(self, int domain_id, int ind[3])
     cdef Oct *next_child(self, int domain_id, int ind[3], Oct *parent)
 
-cdef class RAMSESOctreeContainer(OctreeContainer):
+cdef class SparseOctreeContainer(OctreeContainer):
     cdef OctKey *root_nodes
     cdef void *tree_root
     cdef int num_root
     cdef int max_root
 
+cdef class RAMSESOctreeContainer(SparseOctreeContainer):
+    pass
+
 cdef extern from "search.h" nogil:
     void *tsearch(const void *key, void **rootp,
                     int (*compar)(const void *, const void *))

diff -r cb5446fbcab17088075583726fedaed74c663eae -r d0c1756daf374bf69e58538f90b549b8b274071d yt/geometry/oct_container.pyx
--- a/yt/geometry/oct_container.pyx
+++ b/yt/geometry/oct_container.pyx
@@ -640,7 +640,7 @@
     else:
         return 1
 
-cdef class RAMSESOctreeContainer(OctreeContainer):
+cdef class SparseOctreeContainer(OctreeContainer):
 
     def __init__(self, domain_dimensions, domain_left_edge, domain_right_edge):
         cdef int i, j, k, p
@@ -744,6 +744,9 @@
         if self.root_nodes != NULL: free(self.root_nodes)
         if self.domains != NULL: free(self.domains)
 
+cdef class RAMSESOctreeContainer(SparseOctreeContainer):
+    pass
+
 cdef class ARTOctreeContainer(OctreeContainer):
 
     @cython.boundscheck(False)


https://bitbucket.org/yt_analysis/yt-3.0/commits/38ec3eaade79/
Changeset:   38ec3eaade79
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-17 00:35:10
Summary:     Move a free to a bit later in the routine.
Affected #:  1 file

diff -r d0c1756daf374bf69e58538f90b549b8b274071d -r 38ec3eaade79d7747a2b00e58f26d22dad63bf7c yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -653,7 +653,6 @@
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
         nadded = 0
-        free(mask)
         cdef np.int64_t si, ei
         si = 0
         for level in range(max_level + 1):
@@ -667,6 +666,7 @@
                 raise RuntimeError
             si = ei
         artio_grid_clear_sfc_cache(handle)
+        free(mask)
         free(num_octs_per_level)
         free(tot_octs_per_level)
         free(ind_octs_per_level)


https://bitbucket.org/yt_analysis/yt-3.0/commits/1acbf29d0140/
Changeset:   1acbf29d0140
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-17 20:30:44
Summary:     Initial ARTIOOctreeSubset implementation.
Affected #:  2 files

diff -r 38ec3eaade79d7747a2b00e58f26d22dad63bf7c -r 1acbf29d0140b7bea3edf89ec71808689bf06fae yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -577,8 +577,6 @@
         status = artio_grid_cache_sfc_range(handle,
             self.sfc_start, self.sfc_end )
         check_artio_status(status) 
-        status = artio_grid_count_octs_in_sfc_range(
-                handle, self.sfc_start, self.sfc_end, &tot_octs )
         # Now we iterate and create them, level by level.
         # Note that we are doing a bit of magic to figure out how many root
         # nodes we will need at most

diff -r 38ec3eaade79d7747a2b00e58f26d22dad63bf7c -r 1acbf29d0140b7bea3edf89ec71808689bf06fae yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -29,7 +29,7 @@
 
 from .definitions import yt_to_art, art_to_yt, ARTIOconstants
 from _artio_caller import \
-    artio_is_valid, artio_fileset
+    artio_is_valid, artio_fileset, ARTIOOctreeContainer
 from yt.utilities.definitions import \
     mpc_conversion, sec_conversion
 from .fields import ARTIOFieldInfo, KnownARTIOFields, b2t
@@ -39,11 +39,54 @@
     GeometryHandler, YTDataChunk
 from yt.data_objects.static_output import \
     StaticOutput
+from yt.data_objects.octree_subset import \
+    OctreeSubset
+from yt.data_objects.data_containers import \
+    YTFieldData
 
 from yt.data_objects.field_info_container import \
     FieldInfoContainer, NullFunc
 
 
+class ARTIOOctreeSubset(OctreeSubset):
+    _domain_offset = 0
+    domain_id = 1
+    _con_args = ("base_region", "sfc_start", "sfc_end", "pf")
+    _type_name = 'particle_octree_subset'
+
+    def __init__(self, base_region, sfc_start, sfc_end, pf):
+        self.field_data = YTFieldData()
+        self.field_parameters = {}
+        self.sfc_start = sfc_start
+        self.sfc_end = sfc_end
+        self.pf = pf
+        self.hierarchy = self.pf.hierarchy
+        self._last_mask = None
+        self._last_selector_id = None
+        self._current_particle_type = 'all'
+        self._current_fluid_type = self.pf.default_fluid_type
+        self.base_region = base_region
+        self.base_selector = base_region.selector
+
+    _oct_handler = None
+
+    @property
+    def oct_handler(self):
+        if self._oct_handler is None: 
+            self._oct_handler = ARTIOOctreeContainer(
+                self.pf.domain_dimensions/2, # Octs, not cells
+                self.pf.domain_left_edge, self.pf.domain_right_edge,
+                self.sfc_start, self.sfc_end, self.pf._handle)
+        return self._oct_handler
+
+    @property
+    def min_ind(self):
+        return self.sfc_start
+
+    @property
+    def max_ind(self):
+        return self.sfc_end
+
 class ARTIOChunk(object):
 
     def __init__(self, pf, selector, sfc_start, sfc_end):
@@ -230,7 +273,15 @@
         yield YTDataChunk(dobj, "all", oobjs, self._data_size)
 
     def _chunk_spatial(self, dobj, ngz):
-        raise NotImplementedError
+        if ngz > 0:
+            raise NotImplementedError
+        sobjs = getattr(dobj._current_chunk, "objs", dobj._chunk_info)
+        # These are ARTIOChunk objects
+        for i,og in enumerate(sobjs):
+            g = ARTIOOctreeSubset(dobj, og.sfc_start, og.sfc_end, self.pf)
+            if ngz > 0:
+                g = g.retrieve_ghost_zones(ngz, [], smoothed=True)
+            yield YTDataChunk(dobj, "spatial", [g], None)
 
     def _chunk_io(self, dobj, cache = True):
         # _current_chunk is made from identify_base_chunk


https://bitbucket.org/yt_analysis/yt-3.0/commits/f9a7e0e022b0/
Changeset:   f9a7e0e022b0
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-17 20:34:27
Summary:     Replacing "particle_octree_subset" with "indexed_particle_subset".

This better reflects that these selectors are based on indices.  I do not
believe that, as of yet, indices are used in them directly.
Affected #:  3 files

diff -r 1acbf29d0140b7bea3edf89ec71808689bf06fae -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -181,7 +181,7 @@
     # This is some subset of an octree.  Note that the sum of subsets of an
     # octree may multiply include data files.  While we can attempt to mitigate
     # this, it's unavoidable for many types of data storage on disk.
-    _type_name = 'particle_octree_subset'
+    _type_name = 'indexed_octree_subset'
     _con_args = ('data_files', 'pf', 'min_ind', 'max_ind')
     domain_id = -1
     def __init__(self, base_region, data_files, pf, min_ind = 0, max_ind = 0):

diff -r 1acbf29d0140b7bea3edf89ec71808689bf06fae -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -52,7 +52,7 @@
     _domain_offset = 0
     domain_id = 1
     _con_args = ("base_region", "sfc_start", "sfc_end", "pf")
-    _type_name = 'particle_octree_subset'
+    _type_name = 'indexed_octree_subset'
 
     def __init__(self, base_region, sfc_start, sfc_end, pf):
         self.field_data = YTFieldData()

diff -r 1acbf29d0140b7bea3edf89ec71808689bf06fae -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -1167,7 +1167,7 @@
 
 octree_subset_selector = OctreeSubsetSelector
 
-cdef class ParticleOctreeSubsetSelector(SelectorObject):
+cdef class IndexedOctreeSubsetSelector(SelectorObject):
     # This is a numpy array, which will be a bool of ndim 1
     cdef np.uint64_t min_ind
     cdef np.uint64_t max_ind
@@ -1212,7 +1212,7 @@
         # checking this.
         return self.base_selector.select_grid(left_edge, right_edge, level, o)
 
-particle_octree_subset_selector = ParticleOctreeSubsetSelector
+indexed_octree_subset_selector = IndexedOctreeSubsetSelector
 
 cdef class AlwaysSelector(SelectorObject):
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/414b18365f8c/
Changeset:   414b18365f8c
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-17 20:42:37
Summary:     Merging with tip
Affected #:  7 files

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/data_objects/derived_quantities.py
--- a/yt/data_objects/derived_quantities.py
+++ b/yt/data_objects/derived_quantities.py
@@ -40,7 +40,7 @@
     gravitational_constant_cgs, \
     mass_sun_cgs, \
     HUGE
-
+from yt.utilities.math_utils import prec_accum
 
 __CUDA_BLOCK_SIZE = 256
 
@@ -119,12 +119,15 @@
     This function takes no arguments and returns the sum of cell masses and
     particle masses in the object.
     """
-    baryon_mass = data["CellMassMsun"].sum()
     try:
-        particle_mass = data["ParticleMassMsun"].sum()
-        total_mass = baryon_mass + particle_mass
+        cell_mass = _TotalQuantity(data,["CellMassMsun"])
     except KeyError:
-        total_mass = baryon_mass
+        cell_mass = 0.0
+    try:
+        particle_mass = _TotalQuantity(data,["ParticleMassMsun"])
+    except KeyError:
+        particle_mass = 0.0
+    total_mass = cell_mass + particle_mass
     return [total_mass]
 def _combTotalMass(data, total_mass):
     return total_mass.sum()
@@ -146,15 +149,15 @@
     """
     x = y = z = den = 0
     if use_cells: 
-        x += (data["x"] * data["CellMassMsun"]).sum()
-        y += (data["y"] * data["CellMassMsun"]).sum()
-        z += (data["z"] * data["CellMassMsun"]).sum()
-        den += data["CellMassMsun"].sum()
+        x += (data["x"] * data["CellMassMsun"]).sum(dtype=np.float64)
+        y += (data["y"] * data["CellMassMsun"]).sum(dtype=np.float64)
+        z += (data["z"] * data["CellMassMsun"]).sum(dtype=np.float64)
+        den += data["CellMassMsun"].sum(dtype=np.float64)
     if use_particles:
-        x += (data["particle_position_x"] * data["ParticleMassMsun"]).sum()
-        y += (data["particle_position_y"] * data["ParticleMassMsun"]).sum()
-        z += (data["particle_position_z"] * data["ParticleMassMsun"]).sum()
-        den += data["ParticleMassMsun"].sum()
+        x += (data["particle_position_x"] * data["ParticleMassMsun"]).sum(dtype=np.float64)
+        y += (data["particle_position_y"] * data["ParticleMassMsun"]).sum(dtype=np.float64)
+        z += (data["particle_position_z"] * data["ParticleMassMsun"]).sum(dtype=np.float64)
+        den += data["ParticleMassMsun"].sum(dtype=np.float64)
 
     return x,y,z, den
 def _combCenterOfMass(data, x,y,z, den):
@@ -169,8 +172,8 @@
     :param field: The field to average
     :param weight: The field to weight by
     """
-    num = (data[field] * data[weight]).sum()
-    den = data[weight].sum()
+    num = (data[field] * data[weight]).sum(dtype=np.float64)
+    den = data[weight].sum(dtype=np.float64)
     return num, den
 def _combWeightedAverageQuantity(data, field, weight):
     return field.sum()/weight.sum()
@@ -186,11 +189,11 @@
 
     Returns the weighted variance and the weighted mean.
     """
-    my_weight = data[weight].sum()
+    my_weight = data[weight].sum(dtype=np.float64)
     if my_weight == 0:
         return 0.0, 0.0, 0.0
-    my_mean = (data[field] * data[weight]).sum() / my_weight
-    my_var2 = (data[weight] * (data[field] - my_mean)**2).sum() / my_weight
+    my_mean = (data[field] * data[weight]).sum(dtype=np.float64) / my_weight
+    my_var2 = (data[weight] * (data[field] - my_mean)**2).sum(dtype=np.float64) / my_weight
     return my_weight, my_mean, my_var2
 def _combWeightedVariance(data, my_weight, my_mean, my_var2):
     all_weight = my_weight.sum()
@@ -204,10 +207,10 @@
     """
     This function returns the mass-weighted average velocity in the object.
     """
-    xv = (data["x-velocity"] * data["CellMassMsun"]).sum()
-    yv = (data["y-velocity"] * data["CellMassMsun"]).sum()
-    zv = (data["z-velocity"] * data["CellMassMsun"]).sum()
-    w = data["CellMassMsun"].sum()
+    xv = (data["x-velocity"] * data["CellMassMsun"]).sum(dtype=np.float64)
+    yv = (data["y-velocity"] * data["CellMassMsun"]).sum(dtype=np.float64)
+    zv = (data["z-velocity"] * data["CellMassMsun"]).sum(dtype=np.float64)
+    w = data["CellMassMsun"].sum(dtype=np.float64)
     return xv, yv, zv, w
 def _combBulkVelocity(data, xv, yv, zv, w):
     w = w.sum()
@@ -225,7 +228,7 @@
     amx = data["SpecificAngularMomentumX"]*data["CellMassMsun"]
     amy = data["SpecificAngularMomentumY"]*data["CellMassMsun"]
     amz = data["SpecificAngularMomentumZ"]*data["CellMassMsun"]
-    j_mag = [amx.sum(), amy.sum(), amz.sum()]
+    j_mag = [amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)]
     return [j_mag]
 
 def _StarAngularMomentumVector(data):
@@ -241,13 +244,13 @@
     amx = sLx * star_mass
     amy = sLy * star_mass
     amz = sLz * star_mass
-    j_mag = [amx.sum(), amy.sum(), amz.sum()]
+    j_mag = [amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)]
     return [j_mag]
 
 def _combAngularMomentumVector(data, j_mag):
     if len(j_mag.shape) < 2: j_mag = np.expand_dims(j_mag, 0)
-    L_vec = j_mag.sum(axis=0)
-    L_vec_norm = L_vec / np.sqrt((L_vec**2.0).sum())
+    L_vec = j_mag.sum(axis=0,dtype=np.float64)
+    L_vec_norm = L_vec / np.sqrt((L_vec**2.0).sum(dtype=np.float64))
     return L_vec_norm
 add_quantity("AngularMomentumVector", function=_AngularMomentumVector,
              combine_function=_combAngularMomentumVector, n_ret=1)
@@ -260,13 +263,13 @@
     This function returns the spin parameter for the baryons, but it uses
     the particles in calculating enclosed mass.
     """
-    m_enc = data["CellMassMsun"].sum() + data["ParticleMassMsun"].sum()
+    m_enc = _TotalMass(data)
     amx = data["SpecificAngularMomentumX"]*data["CellMassMsun"]
     amy = data["SpecificAngularMomentumY"]*data["CellMassMsun"]
     amz = data["SpecificAngularMomentumZ"]*data["CellMassMsun"]
-    j_mag = np.array([amx.sum(), amy.sum(), amz.sum()])
-    e_term_pre = np.sum(data["CellMassMsun"]*data["VelocityMagnitude"]**2.0)
-    weight=data["CellMassMsun"].sum()
+    j_mag = np.array([amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)])
+    e_term_pre = np.sum(data["CellMassMsun"]*data["VelocityMagnitude"]**2.0,dtype=np.float64)
+    weight=data["CellMassMsun"].sum(dtype=np.float64)
     return j_mag, m_enc, e_term_pre, weight
 def _combBaryonSpinParameter(data, j_mag, m_enc, e_term_pre, weight):
     # Because it's a vector field, we have to ensure we have enough dimensions
@@ -285,15 +288,15 @@
     This function returns the spin parameter for the baryons, but it uses
     the particles in calculating enclosed mass.
     """
-    m_enc = data["CellMassMsun"].sum() + data["ParticleMassMsun"].sum()
+    m_enc = _TotalMass(data)
     amx = data["ParticleSpecificAngularMomentumX"]*data["ParticleMassMsun"]
-    if amx.size == 0: return (np.zeros((3,), dtype='float64'), m_enc, 0, 0)
+    if amx.size == 0: return (np.zeros((3,), dtype=np.float64), m_enc, 0, 0)
     amy = data["ParticleSpecificAngularMomentumY"]*data["ParticleMassMsun"]
     amz = data["ParticleSpecificAngularMomentumZ"]*data["ParticleMassMsun"]
-    j_mag = np.array([amx.sum(), amy.sum(), amz.sum()])
+    j_mag = np.array([amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)])
     e_term_pre = np.sum(data["ParticleMassMsun"]
-                       *data["ParticleVelocityMagnitude"]**2.0)
-    weight=data["ParticleMassMsun"].sum()
+                       *data["ParticleVelocityMagnitude"]**2.0,dtype=np.float64)
+    weight=data["ParticleMassMsun"].sum(dtype=np.float64)
     return j_mag, m_enc, e_term_pre, weight
 add_quantity("ParticleSpinParameter", function=_ParticleSpinParameter,
              combine_function=_combBaryonSpinParameter, n_ret=4)
@@ -340,19 +343,19 @@
     kinetic = 0.5 * (data["CellMass"] * 
                      ((data["x-velocity"] - bv_x)**2 + 
                       (data["y-velocity"] - bv_y)**2 +
-                      (data["z-velocity"] - bv_z)**2)).sum()
+                      (data["z-velocity"] - bv_z)**2)).sum(dtype=np.float64)
 
     if (include_particles):
-	mass_to_use = data["TotalMass"]
+        mass_to_use = data["TotalMass"]
         kinetic += 0.5 * (data["Dark_Matter_Mass"] *
                           ((data["cic_particle_velocity_x"] - bv_x)**2 +
                            (data["cic_particle_velocity_y"] - bv_y)**2 +
-                           (data["cic_particle_velocity_z"] - bv_z)**2)).sum()
+                           (data["cic_particle_velocity_z"] - bv_z)**2)).sum(dtype=np.float64)
     else:
-	mass_to_use = data["CellMass"]
+        mass_to_use = data["CellMass"]
     # Add thermal energy to kinetic energy
     if (include_thermal_energy):
-        thermal = (data["ThermalEnergy"] * mass_to_use).sum()
+        thermal = (data["ThermalEnergy"] * mass_to_use).sum(dtype=np.float64)
         kinetic += thermal
     if periodic_test:
         kinetic = np.ones_like(kinetic)
@@ -679,9 +682,9 @@
     totals = []
     for field in fields:
         if data[field].size < 1:
-            totals.append(0.0)
+            totals.append(np.zeros(1,dtype=prec_accum[data[field].dtype])[0])
             continue
-        totals.append(data[field].sum())
+        totals.append(data[field].sum(dtype=prec_accum[data[field].dtype]))
     return len(fields), totals
 def _combTotalQuantity(data, n_fields, totals):
     totals = np.atleast_2d(totals)
@@ -698,7 +701,7 @@
     pos = [data[(particle_type,"particle_position_%s"%ax)] for ax in "xyz"]
     pos = np.array(pos).T
     mas = data[(particle_type,"particle_mass")]
-    calc_radius= lambda x,y:np.sqrt(np.sum((x-y)**2.0,axis=1))
+    calc_radius= lambda x,y:np.sqrt(np.sum((x-y)**2.0,axis=1,dtype=np.float64))
     density = 0
     if pos.shape[0]==0:
         return -1.0,[-1.,-1.,-1.]
@@ -715,7 +718,7 @@
         center = 0.5*(le+re)
         idx = calc_radius(pos,center)<bin_size
         pos, mas = pos[idx],mas[idx]
-        density = max(density,mas.sum()/bin_size**3.0)
+        density = max(density,mas.sum(dtype=np.float64)/bin_size**3.0)
     return density, center
 def _combParticleDensityCenter(data,densities,centers):
     i = np.argmax(densities)

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -350,7 +350,7 @@
                             if selected_mass[ispec] :
                                 count = len(data[selected_mass[ispec]])
                                 data[selected_mass[ispec]].resize(count+1)
-                                data[selected_mass[ispec]][count] = self.parameters["particle_species_mass"][0]
+                                data[selected_mass[ispec]][count] = self.parameters["particle_species_mass"][ispec]
                         
                     status = artio_particle_read_species_end( self.handle )
                     check_artio_status(status)

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -339,6 +339,15 @@
         for unit in mpc_conversion.keys():
             self.units[unit] = self.parameters['unit_l']\
                 * mpc_conversion[unit] / mpc_conversion["cm"]
+        if self.cosmological_simulation:
+            for unit in mpc_conversion:
+                self.units["%sh" % unit] = self.units[unit] * \
+                    self.hubble_constant
+                self.units["%shcm" % unit] = \
+                    (self.units["%sh" % unit] /
+                        (1 + self.current_redshift))
+                self.units["%scm" % unit] = \
+                    self.units[unit] / (1 + self.current_redshift)
 
         for unit in sec_conversion.keys():
             self.time_units[unit] = self.parameters['unit_t']\

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/frontends/artio/fields.py
--- a/yt/frontends/artio/fields.py
+++ b/yt/frontends/artio/fields.py
@@ -34,6 +34,9 @@
     ValidateSpatial, \
     ValidateGridType
 import yt.data_objects.universal_fields
+from yt.data_objects.particle_fields import \
+    particle_deposition_functions, \
+    particle_vector_functions
 import numpy as np
 
 KnownARTIOFields = FieldInfoContainer()
@@ -247,51 +250,20 @@
     pf = "particle_velocity_%s" % ax
     add_artio_field(pf, function=NullFunc,
                     particle_type=True)
-add_artio_field("particle_mass", function=NullFunc, particle_type=True)
-add_artio_field("particle_index", function=NullFunc, particle_type=True)
 
 for ax in 'xyz':
     pf = "particle_position_%s" % ax
     add_artio_field(pf, function=NullFunc,
                     particle_type=True)
 
-
-def ParticleMass(field, data):
-    return data['particle_mass']
-
-
-def _convertParticleMass(field, data):
-    return data.convert('particle_mass')
-add_field("ParticleMass",
-          function=ParticleMass,
+def _convertParticleMass(data):
+    return np.float64(data.convert('particle_mass'))
+add_field("particle_mass",
+          function=NullFunc,
           convert_function=_convertParticleMass,
           units=r"\rm{g}",
           particle_type=True)
-
-
-def ParticleMassMsunAll(field, data):
-    return data['all', 'particle_mass'] * \
-        data.pf.conversion_factors['particle_mass_msun']
-add_field(('all', "ParticleMassMsun"),
-          function=ParticleMassMsunAll,
-          units=r"\rm{M\odot}", particle_type=True)
-
-
-def ParticleMassMsunStars(field, data):
-    return data['stars', 'particle_mass'] * \
-        data.pf.conversion_factors['particle_mass_msun']
-add_field(('stars', "ParticleMassMsun"),
-          function=ParticleMassMsunStars,
-          units=r"\rm{M\odot}", particle_type=True)
-
-
-def ParticleMassMsunNbody(field, data):
-    return data['nbody', 'particle_mass'] * \
-        data.pf.conversion_factors['particle_mass_msun']
-add_field(('nbody', "ParticleMassMsun"),
-          function=ParticleMassMsunNbody,
-          units=r"\rm{M\odot}", particle_type=True)
-
+add_artio_field("particle_index", function=NullFunc, particle_type=True)
 
 #add_artio_field("creation_time", function=NullFunc, particle_type=True)
 def _particle_age(field, data):
@@ -303,6 +275,15 @@
 add_field(("stars","particle_age"), function=_particle_age, units=r"\rm{s}",
           particle_type=True)
 
+# We can now set up particle vector and particle deposition fields.
+
+for ptype in ("all", "nbody", "stars"):
+    particle_vector_functions(ptype,
+        ["particle_position_%s" % ax for ax in 'xyz'],
+        ["particle_velocity_%s" % ax for ax in 'xyz'],
+        ARTIOFieldInfo)
+    particle_deposition_functions(ptype, "Coordinates", "particle_mass",
+        ARTIOFieldInfo)
 
 def mass_dm(field, data):
     tr = np.ones(data.ActiveDimensions, dtype='float32')

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -49,4 +49,7 @@
         for onechunk in chunks:
             for artchunk in onechunk.objs:
                 artchunk.fill_particles(tr, fields)
+        for ftype, fname in tr.keys():
+            if fname == "particle_mass":
+                tr[ftype, fname] = tr[ftype, fname].astype("float64")
         return tr

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/utilities/math_utils.py
--- a/yt/utilities/math_utils.py
+++ b/yt/utilities/math_utils.py
@@ -30,6 +30,41 @@
 import numpy as np
 import math
 
+prec_accum = {
+    np.int:                 np.int64,
+    np.int8:                np.int64,
+    np.int16:               np.int64,
+    np.int32:               np.int64,
+    np.int64:               np.int64,
+    np.uint8:               np.uint64,
+    np.uint16:              np.uint64,
+    np.uint32:              np.uint64,
+    np.uint64:              np.uint64,
+    np.float:               np.float64,
+    np.float16:             np.float64,
+    np.float32:             np.float64,
+    np.float64:             np.float64,
+    np.complex:             np.complex128,
+    np.complex64:           np.complex128,
+    np.complex128:          np.complex128,
+    np.dtype('int'):        np.int64,
+    np.dtype('int8'):       np.int64,
+    np.dtype('int16'):      np.int64,
+    np.dtype('int32'):      np.int64,
+    np.dtype('int64'):      np.int64,
+    np.dtype('uint8'):      np.uint64,
+    np.dtype('uint16'):     np.uint64,
+    np.dtype('uint32'):     np.uint64,
+    np.dtype('uint64'):     np.uint64,
+    np.dtype('float'):      np.float64,
+    np.dtype('float16'):    np.float64,
+    np.dtype('float32'):    np.float64,
+    np.dtype('float64'):    np.float64,
+    np.dtype('complex'):    np.complex128,
+    np.dtype('complex64'):  np.complex128,
+    np.dtype('complex128'): np.complex128,
+}
+
 def periodic_position(pos, pf):
     r"""Assuming periodicity, find the periodic position within the domain.
 

diff -r f9a7e0e022b02cfddee1dae96b944682b7c9dde9 -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1100,12 +1100,15 @@
 
     def _send_zmq(self):
         try:
-            # pre-IPython v0.14
+            # pre-IPython v1.0
             from IPython.zmq.pylab.backend_inline import send_figure as display
         except ImportError:
-            # IPython v0.14+
+            # IPython v1.0+
             from IPython.core.display import display
         for k, v in sorted(self.plots.iteritems()):
+            # Due to a quirk in the matplotlib API, we need to create
+            # a dummy canvas variable here that is never used.
+            canvas = FigureCanvasAgg(v.figure)  # NOQA
             display(v.figure)
 
     def show(self):


https://bitbucket.org/yt_analysis/yt-3.0/commits/804b2c01eb99/
Changeset:   804b2c01eb99
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-17 20:57:29
Summary:     Begin to transition "all" to be handled as a concatenated field in memory and
add fill() and fill_particle() stubs to the ARTIOOctreeSubset class.
Affected #:  4 files

diff -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 -r 804b2c01eb99fa4a02aa4a0022104dc731edd712 yt/data_objects/particle_fields.py
--- a/yt/data_objects/particle_fields.py
+++ b/yt/data_objects/particle_fields.py
@@ -41,6 +41,30 @@
     mass_sun_cgs, \
     mh
 
+def _field_concat(fname):
+    def _AllFields(field, data):
+        v = []
+        for ptype in data.pf.particle_types:
+            if ptype == "all" or \
+                ptype in data.pf.known_filters:
+                  continue
+            v.append(data[ptype, fname].copy())
+        rv = np.concatenate(v, axis=0)
+        return rv
+    return _AllFields
+
+def _field_concat_slice(fname, axi):
+    def _AllFields(field, data):
+        v = []
+        for ptype in data.pf.particle_types:
+            if ptype == "all" or \
+                ptype in data.pf.known_filters:
+                  continue
+            v.append(data[ptype, fname][:,axi])
+        rv = np.concatenate(v, axis=0)
+        return rv
+    return _AllFields
+
 def particle_deposition_functions(ptype, coord_name, mass_name, registry):
     orig = set(registry.keys())
     def particle_count(field, data):

diff -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 -r 804b2c01eb99fa4a02aa4a0022104dc731edd712 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -87,6 +87,12 @@
     def max_ind(self):
         return self.sfc_end
 
+    def fill(self, fields):
+        raise NotImplementedError
+
+    def fill_particles(self, field_data, fields):
+        raise NotImplementedError
+
 class ARTIOChunk(object):
 
     def __init__(self, pf, selector, sfc_start, sfc_end):
@@ -447,10 +453,10 @@
                         "species_%02d_secondary_variable_labels"
                         % (species, )])
 
-        self.particle_types = ["all"]
-        self.particle_types.extend(
-            list(set(art_to_yt[s] for s in
-                     self.artio_parameters["particle_species_labels"])))
+        self.particle_types = ("all",) + tuple(
+            set(art_to_yt[s] for s in
+                self.artio_parameters["particle_species_labels"]))
+        self.particle_types = tuple(self.particle_types)
 
         self.current_time = b2t(self.artio_parameters["tl"][0])
 

diff -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 -r 804b2c01eb99fa4a02aa4a0022104dc731edd712 yt/frontends/artio/fields.py
--- a/yt/frontends/artio/fields.py
+++ b/yt/frontends/artio/fields.py
@@ -36,7 +36,9 @@
 import yt.data_objects.universal_fields
 from yt.data_objects.particle_fields import \
     particle_deposition_functions, \
-    particle_vector_functions
+    particle_vector_functions, \
+    particle_scalar_functions, \
+    _field_concat, _field_concat_slice
 import numpy as np
 
 KnownARTIOFields = FieldInfoContainer()
@@ -277,7 +279,7 @@
 
 # We can now set up particle vector and particle deposition fields.
 
-for ptype in ("all", "nbody", "stars"):
+for ptype in ("nbody", "stars"):
     particle_vector_functions(ptype,
         ["particle_position_%s" % ax for ax in 'xyz'],
         ["particle_velocity_%s" % ax for ax in 'xyz'],
@@ -285,6 +287,13 @@
     particle_deposition_functions(ptype, "Coordinates", "particle_mass",
         ARTIOFieldInfo)
 
+for fname in ["particle_position_%s" % ax for ax in 'xyz'] + \
+             ["particle_velocity_%s" % ax for ax in 'xyz'] + \
+             ["particle_index", "particle_species"]:
+    func = _field_concat(fname)
+    ARTIOFieldInfo.add_field(("all", fname), function=func,
+            particle_type = True)
+
 def mass_dm(field, data):
     tr = np.ones(data.ActiveDimensions, dtype='float32')
     idx = data["particle_type"] < 5

diff -r 414b18365f8c0dcc5eaa1d7179ef834a3e1c1146 -r 804b2c01eb99fa4a02aa4a0022104dc731edd712 yt/frontends/sph/fields.py
--- a/yt/frontends/sph/fields.py
+++ b/yt/frontends/sph/fields.py
@@ -39,7 +39,8 @@
 import yt.data_objects.universal_fields
 from yt.data_objects.particle_fields import \
     particle_deposition_functions, \
-    particle_scalar_functions
+    particle_scalar_functions, \
+    _field_concat, _field_concat_slice
 from yt.utilities.physical_constants import \
     mass_sun_cgs
 
@@ -68,30 +69,6 @@
         return data.convert(cf)
     return _convert
 
-def _field_concat(fname):
-    def _AllFields(field, data):
-        v = []
-        for ptype in data.pf.particle_types:
-            if ptype == "all" or \
-                ptype in data.pf.known_filters:
-                  continue
-            v.append(data[ptype, fname].copy())
-        rv = np.concatenate(v, axis=0)
-        return rv
-    return _AllFields
-
-def _field_concat_slice(fname, axi):
-    def _AllFields(field, data):
-        v = []
-        for ptype in data.pf.particle_types:
-            if ptype == "all" or \
-                ptype in data.pf.known_filters:
-                  continue
-            v.append(data[ptype, fname][:,axi])
-        rv = np.concatenate(v, axis=0)
-        return rv
-    return _AllFields
-
 # TIPSY
 # =====
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/d8c7e6882214/
Changeset:   d8c7e6882214
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-19 18:58:59
Summary:     First pass at implementing an ARTIO fill function for spatial data.
Affected #:  2 files

diff -r 804b2c01eb99fa4a02aa4a0022104dc731edd712 -r d8c7e688221443e3f0d0293a55d63b60ab6e86a1 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -540,6 +540,7 @@
     cdef public np.int64_t sfc_end
     cdef public artio_fileset artio_handle
     cdef Oct **root_octs
+    cdef np.int64_t *level_indices
 
     def __init__(self, oct_dimensions, domain_left_edge, domain_right_edge,
                  int64_t sfc_start, int64_t sfc_end, artio_fileset artio_handle):
@@ -550,6 +551,7 @@
         # or not an Oct can be partially refined.
         super(ARTIOOctreeContainer, self).__init__(oct_dimensions,
             domain_left_edge, domain_right_edge)
+        self.level_indices = NULL
         self._initialize_root_mesh()
 
     @cython.boundscheck(False)
@@ -568,10 +570,10 @@
         cdef int max_level = self.artio_handle.max_level
         cdef int *num_octs_per_level = <int *>malloc(
             (max_level + 1)*sizeof(int))
-        cdef int *tot_octs_per_level = <int *>malloc(
-            (max_level + 1)*sizeof(int))
-        cdef int *ind_octs_per_level = <int *>malloc(
-            (max_level + 1)*sizeof(int))
+        cdef np.int64_t *tot_octs_per_level = <np.int64_t *>malloc(
+            (max_level + 1)*sizeof(np.int64_t))
+        self.level_indices = <np.int64_t *>malloc(
+            (max_level + 1)*sizeof(np.int64_t))
         for level in range(max_level + 1):
             tot_octs_per_level[level] = 0
         status = artio_grid_cache_sfc_range(handle,
@@ -608,7 +610,7 @@
         tot_octs_per_level[0] = num_root
         cdef np.int64_t tot = 0
         for i in range(max_level + 1):
-            ind_octs_per_level[i] = tot
+            self.level_indices[i] = tot
             tot += tot_octs_per_level[i]
         self.allocate_domains([tot], num_root)
         # Now we have everything counted, and we need to create the appropriate
@@ -633,9 +635,9 @@
                 # We add it here
                 for i in range(3):
                     dpos[i] = self.DLE[i] + (coords[i]+0.5)*dds[i]
-                    pos[ind_octs_per_level[0], i] = dpos[i]
+                    pos[self.level_indices[0], i] = dpos[i]
                 mask[<int>(ipos/8)] -= (1 << bits)
-                ind_octs_per_level[0] += 1
+                self.level_indices[0] += 1
             # Now we iterate over all the children
             for level in range(1, num_oct_levels+1):
                 status = artio_grid_read_level_begin(handle, level)
@@ -644,8 +646,8 @@
                     status = artio_grid_read_oct(handle, dpos, NULL, NULL)
                     check_artio_status(status)
                     for i in range(3):
-                        pos[ind_octs_per_level[level], i] = dpos[i]
-                    ind_octs_per_level[level] += 1
+                        pos[self.level_indices[level], i] = dpos[i]
+                    self.level_indices[level] += 1
                 status = artio_grid_read_level_end(handle)
                 check_artio_status(status)
             status = artio_grid_read_root_cell_end( handle )
@@ -654,12 +656,13 @@
         cdef np.int64_t si, ei
         si = 0
         for level in range(max_level + 1):
-            ei = si + tot_octs_per_level[level]
+            ei = self.level_indices[level] = \
+                si + tot_octs_per_level[level]
             if tot_octs_per_level[level] == 0: break
             nadded = self.add(1, level, pos[si:ei, :])
             if nadded != (ei - si):
                 print level, nadded, ei, si, self.max_root,
-                print ind_octs_per_level[level]
+                print self.level_indices[level]
                 print pos[si:ei,:]
                 raise RuntimeError
             si = ei
@@ -667,4 +670,81 @@
         free(mask)
         free(num_octs_per_level)
         free(tot_octs_per_level)
-        free(ind_octs_per_level)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    def fill_sfc(self, 
+                 np.ndarray[np.uint8_t, ndim=1] levels,
+                 np.ndarray[np.uint8_t, ndim=1] cell_inds,
+                 np.ndarray[np.int64_t, ndim=1] file_inds,
+                 field_indices, dest_fields):
+        cdef np.ndarray[np.float32_t, ndim=2] source
+        cdef np.ndarray[np.float64_t, ndim=1] dest
+        cdef int n, status, i, di, num_oct_levels, nf, ngv, max_level
+        cdef np.int64_t sfc
+        cdef np.float64_t val
+        cdef artio_fileset_handle *handle = self.artio_handle.handle
+        cdef double dpos[3]
+        # We duplicate some of the grid_variables stuff here so that we can
+        # potentially release the GIL
+        nf = len(field_indices)
+        ngv = self.artio_handle.num_grid_variables
+        max_level = self.artio_handle.max_level
+        cdef int *num_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
+        cdef float *grid_variables = <float *>malloc(
+            8 * ngv * sizeof(float))
+        cdef int* field_ind = <int*> malloc(
+            nf * sizeof(int))
+        cdef np.float32_t **field_vals = <np.float32_t**> malloc(
+            nf * sizeof(np.float32_t*))
+        cdef np.int64_t *local_ind = <np.int64_t *> malloc(
+            max_level * sizeof(np.int64_t))
+        for i in range(max_level):
+            # This will help us keep track of where we are in the flattened
+            # array, which will be indexed by file_ind.
+            local_ind[i] = self.level_indices[i]
+        source_arrays = []
+        for i in range(nf):
+            field_ind[i] = field_indices[i]
+            # This zeros should be an empty once we handle the root grid
+            source = np.zeros((self.nocts, 8), dtype="float32")
+            source_arrays.append(source)
+            field_vals[i] = <np.float32_t*> source.data
+        # First we need to walk the mesh in the file.  Then we fill in the dest
+        # location based on the file index.
+        status = artio_grid_cache_sfc_range(handle,
+            self.sfc_start, self.sfc_end )
+        check_artio_status(status) 
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            status = artio_grid_read_root_cell_begin( handle, sfc, 
+                    dpos, NULL, &num_oct_levels, num_octs_per_level)
+            check_artio_status(status) 
+            for level in range(1, num_oct_levels+1):
+                status = artio_grid_read_level_begin(handle, level)
+                check_artio_status(status) 
+                for oct_ind in range(num_octs_per_level[level - 1]):
+                    status = artio_grid_read_oct(handle, dpos, grid_variables, NULL)
+                    check_artio_status(status)
+                    for j in range(8):
+                        for i in range(nf):
+                            field_vals[i][local_ind[level - 1] * 8 + j] = \
+                                grid_variables[ngv * j + i]
+                    local_ind[level - 1] += 1
+                status = artio_grid_read_level_end(handle)
+                check_artio_status(status)
+            status = artio_grid_read_root_cell_end( handle )
+            check_artio_status(status)
+        # Now we have all our sources.
+        artio_grid_clear_sfc_cache(handle)
+        for j in range(nf):
+            dest = dest_fields[j]
+            source = source_arrays[j]
+            for i in range(levels.shape[0]):
+                dest[i] = source[file_inds[i], cell_inds[i]]
+        free(field_ind)
+        free(field_vals)
+        free(local_ind)
+        free(grid_variables)
+        free(num_octs_per_level)

diff -r 804b2c01eb99fa4a02aa4a0022104dc731edd712 -r d8c7e688221443e3f0d0293a55d63b60ab6e86a1 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -88,7 +88,20 @@
         return self.sfc_end
 
     def fill(self, fields):
-        raise NotImplementedError
+        # Here we get a copy of the file, which we skip through and read the
+        # bits we want.
+        handle = self.oct_handler.artio_handle
+        field_indices = [handle.parameters["grid_variable_labels"].index(
+                        yt_to_art[f]) for (ft, f) in fields]
+        cell_count = self.selector.count_oct_cells(
+            self.oct_handler, self.domain_id)
+        self.data_size = cell_count
+        levels, cell_inds, file_inds = self.oct_handler.file_index_octs(
+            self.selector, self.domain_id, cell_count)
+        tr = [np.zeros(cell_count, dtype="float64") for field in fields]
+        self.oct_handler.fill_sfc(levels, cell_inds, file_inds, field_indices, tr)
+        tr = dict((field, v) for field, v in zip(fields, tr))
+        return tr
 
     def fill_particles(self, field_data, fields):
         raise NotImplementedError


https://bitbucket.org/yt_analysis/yt-3.0/commits/8566578ec51b/
Changeset:   8566578ec51b
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-19 20:05:51
Summary:     Switch selectors for ARTIO Octree Subset and push selector out into IO
Affected #:  3 files

diff -r d8c7e688221443e3f0d0293a55d63b60ab6e86a1 -r 8566578ec51bf2803149b968f28c455b5ce09173 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -656,8 +656,8 @@
         cdef np.int64_t si, ei
         si = 0
         for level in range(max_level + 1):
-            ei = self.level_indices[level] = \
-                si + tot_octs_per_level[level]
+            self.level_indices[level] = si
+            ei = si + tot_octs_per_level[level]
             if tot_octs_per_level[level] == 0: break
             nadded = self.add(1, level, pos[si:ei, :])
             if nadded != (ei - si):
@@ -742,7 +742,9 @@
             dest = dest_fields[j]
             source = source_arrays[j]
             for i in range(levels.shape[0]):
-                dest[i] = source[file_inds[i], cell_inds[i]]
+                if levels[i] == 0: continue
+                oct_ind = self.level_indices[levels[i] - 1]
+                dest[i] = source[file_inds[i] + oct_ind, cell_inds[i]]
         free(field_ind)
         free(field_vals)
         free(local_ind)

diff -r d8c7e688221443e3f0d0293a55d63b60ab6e86a1 -r 8566578ec51bf2803149b968f28c455b5ce09173 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -52,7 +52,7 @@
     _domain_offset = 0
     domain_id = 1
     _con_args = ("base_region", "sfc_start", "sfc_end", "pf")
-    _type_name = 'indexed_octree_subset'
+    _type_name = 'octree_subset'
 
     def __init__(self, base_region, sfc_start, sfc_end, pf):
         self.field_data = YTFieldData()
@@ -87,17 +87,17 @@
     def max_ind(self):
         return self.sfc_end
 
-    def fill(self, fields):
+    def fill(self, fields, selector):
         # Here we get a copy of the file, which we skip through and read the
         # bits we want.
         handle = self.oct_handler.artio_handle
         field_indices = [handle.parameters["grid_variable_labels"].index(
                         yt_to_art[f]) for (ft, f) in fields]
-        cell_count = self.selector.count_oct_cells(
+        cell_count = selector.count_oct_cells(
             self.oct_handler, self.domain_id)
         self.data_size = cell_count
         levels, cell_inds, file_inds = self.oct_handler.file_index_octs(
-            self.selector, self.domain_id, cell_count)
+            selector, self.domain_id, cell_count)
         tr = [np.zeros(cell_count, dtype="float64") for field in fields]
         self.oct_handler.fill_sfc(levels, cell_inds, file_inds, field_indices, tr)
         tr = dict((field, v) for field, v in zip(fields, tr))
@@ -108,9 +108,8 @@
 
 class ARTIOChunk(object):
 
-    def __init__(self, pf, selector, sfc_start, sfc_end):
+    def __init__(self, pf, sfc_start, sfc_end):
         self.pf = pf
-        self.selector = selector
         self.sfc_start = sfc_start
         self.sfc_end = sfc_end
 
@@ -147,10 +146,10 @@
             raise RuntimeError("ARTIOChunk.icoords called before fill")
         return (int)(self._fcoords/2**-self._ires)
 
-    def fill(self, fields):
+    def fill(self, fields, selector):
         art_fields = [yt_to_art[f[1]] for f in fields]
         (self._fcoords, self._ires, artdata) = \
-            self.pf._handle.read_grid_chunk(self.selector,
+            self.pf._handle.read_grid_chunk(selector,
                                             self.sfc_start,
                                             self.sfc_end, art_fields)
         data = {}
@@ -159,7 +158,7 @@
         self._data_size = len(self._fcoords)
         return data
 
-    def fill_particles(self, field_data, fields):
+    def fill_particles(self, field_data, fields, selector):
         art_fields = {}
         for s, f in fields:
             for i in range(self.pf.num_species):
@@ -168,7 +167,7 @@
                         art_fields[(i, yt_to_art[f])] = 1
 
         species_data = self.pf._handle.read_particle_chunk(
-            self.selector, self.sfc_start, self.sfc_end, art_fields.keys())
+            selector, self.sfc_start, self.sfc_end, art_fields.keys())
 
         for s, f in fields:
             af = yt_to_art[f]
@@ -276,7 +275,7 @@
                 mylog.debug("Running selector on artio base grid")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges(
                     dobj.selector)
-            dobj._chunk_info = [ARTIOChunk(self.pf, dobj.selector, start, end)
+            dobj._chunk_info = [ARTIOChunk(self.pf, start, end)
                                 for (start, end) in list_sfc_ranges]
             mylog.info("Created %d chunks for ARTIO" % len(list_sfc_ranges))
         dobj._current_chunk = list(self._chunk_all(dobj))[0]

diff -r d8c7e688221443e3f0d0293a55d63b60ab6e86a1 -r 8566578ec51bf2803149b968f28c455b5ce09173 yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -36,7 +36,7 @@
         cp = 0
         for onechunk in chunks:
             for artchunk in onechunk.objs:
-                rv = artchunk.fill(fields)
+                rv = artchunk.fill(fields, selector)
                 for f in fields:
                     tr[f].resize(cp+artchunk.data_size)
                     tr[f][cp:cp+artchunk.data_size] = rv.pop(f)
@@ -48,7 +48,7 @@
         tr = dict((ftuple, np.empty(0, dtype='float32')) for ftuple in fields)
         for onechunk in chunks:
             for artchunk in onechunk.objs:
-                artchunk.fill_particles(tr, fields)
+                artchunk.fill_particles(tr, fields, selector)
         for ftype, fname in tr.keys():
             if fname == "particle_mass":
                 tr[ftype, fname] = tr[ftype, fname].astype("float64")


https://bitbucket.org/yt_analysis/yt-3.0/commits/344b137ba500/
Changeset:   344b137ba500
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-19 20:18:19
Summary:     Spatial gives correct results for L > 0
Affected #:  1 file

diff -r 8566578ec51bf2803149b968f28c455b5ce09173 -r 344b137ba5003bd387992e8208fe48862d31b8c1 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -700,8 +700,8 @@
         cdef np.float32_t **field_vals = <np.float32_t**> malloc(
             nf * sizeof(np.float32_t*))
         cdef np.int64_t *local_ind = <np.int64_t *> malloc(
-            max_level * sizeof(np.int64_t))
-        for i in range(max_level):
+            (max_level + 1) * sizeof(np.int64_t))
+        for i in range(max_level + 1):
             # This will help us keep track of where we are in the flattened
             # array, which will be indexed by file_ind.
             local_ind[i] = self.level_indices[i]
@@ -729,9 +729,9 @@
                     check_artio_status(status)
                     for j in range(8):
                         for i in range(nf):
-                            field_vals[i][local_ind[level - 1] * 8 + j] = \
+                            field_vals[i][local_ind[level] * 8 + j] = \
                                 grid_variables[ngv * j + i]
-                    local_ind[level - 1] += 1
+                    local_ind[level] += 1
                 status = artio_grid_read_level_end(handle)
                 check_artio_status(status)
             status = artio_grid_read_root_cell_end( handle )
@@ -743,7 +743,7 @@
             source = source_arrays[j]
             for i in range(levels.shape[0]):
                 if levels[i] == 0: continue
-                oct_ind = self.level_indices[levels[i] - 1]
+                oct_ind = self.level_indices[levels[i]]
                 dest[i] = source[file_inds[i] + oct_ind, cell_inds[i]]
         free(field_ind)
         free(field_vals)


https://bitbucket.org/yt_analysis/yt-3.0/commits/a6ea31a825de/
Changeset:   a6ea31a825de
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-19 20:23:23
Summary:     Enable "all" and "deposit"/"all" fields.
Affected #:  1 file

diff -r 344b137ba5003bd387992e8208fe48862d31b8c1 -r a6ea31a825deaf25e98366f0a15dab90efe1a7a9 yt/frontends/artio/fields.py
--- a/yt/frontends/artio/fields.py
+++ b/yt/frontends/artio/fields.py
@@ -279,7 +279,14 @@
 
 # We can now set up particle vector and particle deposition fields.
 
-for ptype in ("nbody", "stars"):
+for fname in ["particle_position_%s" % ax for ax in 'xyz'] + \
+             ["particle_velocity_%s" % ax for ax in 'xyz'] + \
+             ["particle_index", "particle_species"]:
+    func = _field_concat(fname)
+    ARTIOFieldInfo.add_field(("all", fname), function=func,
+            particle_type = True)
+
+for ptype in ("nbody", "stars", "all"):
     particle_vector_functions(ptype,
         ["particle_position_%s" % ax for ax in 'xyz'],
         ["particle_velocity_%s" % ax for ax in 'xyz'],
@@ -287,13 +294,6 @@
     particle_deposition_functions(ptype, "Coordinates", "particle_mass",
         ARTIOFieldInfo)
 
-for fname in ["particle_position_%s" % ax for ax in 'xyz'] + \
-             ["particle_velocity_%s" % ax for ax in 'xyz'] + \
-             ["particle_index", "particle_species"]:
-    func = _field_concat(fname)
-    ARTIOFieldInfo.add_field(("all", fname), function=func,
-            particle_type = True)
-
 def mass_dm(field, data):
     tr = np.ones(data.ActiveDimensions, dtype='float32')
     idx = data["particle_type"] < 5


https://bitbucket.org/yt_analysis/yt-3.0/commits/aab8903d082f/
Changeset:   aab8903d082f
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-19 23:08:17
Summary:     First draft of SFC particle reader for ARTIOOctContainer.
Affected #:  1 file

diff -r a6ea31a825deaf25e98366f0a15dab90efe1a7a9 -r aab8903d082f7a741fe0d9447b14a4d2156e50b1 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -528,6 +528,26 @@
     artio_sfc_coords(handle.handle, s, coords)
     return (coords[0], coords[1], coords[2])
 
+cdef struct particle_var_pointers:
+    # The number of particles we have filled
+    np.int64_t count
+    # Number of primary variables and pointers to their indices
+    int n_p
+    int p_ind[16] # Max of 16 vars
+    # Number of secondary variables and pointers to their indices
+    int n_s
+    int s_ind[16] # Max of 16 vars
+    # Pointers to the bools and data arrays for mass, pid and species
+    int n_mass
+    np.float32_t *mass
+    int n_pid
+    np.int64_t *pid
+    int n_species
+    np.int8_t *species
+    # Pointers to the pointers to primary and secondary vars
+    np.float64_t *pvars[16]
+    np.float32_t *svars[16]
+
 cdef class ARTIOOctreeContainer(SparseOctreeContainer):
     # This is a transitory, created-on-demand OctreeContainer.  It should not
     # be considered to be long-lasting, and during its creation it will read
@@ -750,3 +770,142 @@
         free(local_ind)
         free(grid_variables)
         free(num_octs_per_level)
+
+    def fill_sfc_particles(self, fields):
+        cdef int status, ispec, subspecies
+        cdef np.int64_t sfc, particle, pid, ind, vind
+        cdef int num_species = self.artio_handle.num_species
+        cdef artio_fileset_handle *handle = self.artio_handle.handle
+        cdef int *num_particles_per_species =  <int *>malloc(
+            sizeof(int)*num_species) 
+        cdef int *accessed_species =  <int *>malloc(
+            sizeof(int)*num_species) 
+        cdef int *total_particles = <int *>malloc(
+            sizeof(int)*num_species) 
+        cdef particle_var_pointers *vpoints = <particle_var_pointers *> malloc(
+            sizeof(particle_var_pointers)*num_species)
+        cdef double *primary_variables
+        cdef float *secondary_variables
+        cdef np.int64_t tp
+
+        cdef np.ndarray[np.int8_t, ndim=1] npi8arr
+        cdef np.ndarray[np.int64_t, ndim=1] npi64arr
+        cdef np.ndarray[np.float32_t, ndim=1] npf32arr
+        cdef np.ndarray[np.float64_t, ndim=1] npf64arr
+
+        # Now we set up our field pointers
+        params = self.artio_handle.parameters
+
+        npri_vars = params["num_primary_variables"]
+        nsec_vars = params["num_secondary_variables"]
+        primary_variables = <double *>malloc(sizeof(double) * max(npri_vars))
+        secondary_variables = <float *>malloc(sizeof(double) * max(nsec_vars))
+
+        for ispec in range(num_species):
+            total_particles[ispec] = 0
+            accessed_species[ispec] = 0
+            # Initialize our vpoints array
+            vpoints[ispec].count = 0
+            vpoints[ispec].n_mass = 0
+            vpoints[ispec].n_pid = 0
+            vpoints[ispec].n_s = 0
+            vpoints[ispec].n_p = 0
+
+        status = artio_particle_cache_sfc_range( handle,
+                self.sfc_start, self.sfc_end +1 ) 
+        check_artio_status(status)
+
+        # Pass through once.  We want every single particle.
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            status = artio_particle_read_root_cell_begin( handle, sfc,
+                    num_particles_per_species )
+            check_artio_status(status)
+
+            for ispec in range(num_species):
+                total_particles[ispec] += num_particles_per_species[ispec]
+
+            status = artio_particle_read_root_cell_end( handle )
+            check_artio_status(status)
+
+        # Now we allocate our final fields, which will be filled
+        #for ispec in range(num_species):
+        #    print "In SFC %s to %s reading %s of species %s" % (
+        #        self.sfc_start, self.sfc_end + 1, total_particles[ispec], ispec)
+        data = {}
+        for species, field in sorted(fields):
+            pri_vars = params.get(
+                "species_%02u_primary_variable_labels" % (species,), [])
+            sec_vars = params.get(
+                "species_%02u_secondary_variable_labels" % (species,), [])
+            tp = total_particles[species]
+            if field == "MASS":
+                vpoints[species].n_mass = 1
+                npf32arr = data[(species, field)] = np.zeros(tp, dtype="float32")
+                # We fill this *now*
+                npf32arr += params["particle_species_mass"][ispec]
+                vpoints[species].mass = <np.float32_t*> npf32arr.data
+            elif field == "PID":
+                vpoints[species].n_pid = 1
+                npi64arr = data[(species, field)] = np.empty(tp, dtype="int64")
+                vpoints[species].pid = <np.int64_t*> npf32arr.data
+            elif field == "SPECIES":
+                vpoints[species].n_species = 1
+                npi8arr = data[(species, field)] = np.empty(tp, dtype="int8")
+                # We fill this *now*
+                npi8arr += species
+                vpoints[species].species = <np.int8_t*> npf32arr.data
+            elif npri_vars[species] > 0 and field in pri_vars :
+                npf64arr = data[(species, field)] = np.empty(tp, dtype="float64")
+                vpoints[species].p_ind[vpoints[species].n_p] = \
+                    pri_vars.index(field)
+                vpoints[species].pvars[vpoints[species].n_p] = \
+                    <np.float64_t *> npf64arr.data
+                vpoints[species].n_p += 1
+            elif nsec_vars[species] > 0 and field in sec_vars :
+                vpoints[species].s_ind[vpoints[species].n_s] = \
+                    sec_vars.index(field)
+                npf32arr = data[(species, field)] = np.empty(tp, dtype="float32")
+                vpoints[species].svars[vpoints[species].n_s] = \
+                    <np.float32_t *> npf32arr.data
+                vpoints[species].n_s += 1
+
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            status = artio_particle_read_root_cell_begin( handle, sfc,
+                    num_particles_per_species )
+            check_artio_status(status)
+            for ispec in range(num_species) : 
+                if accessed_species[ispec] == 0: continue
+                status = artio_particle_read_species_begin(handle, ispec);
+                check_artio_status(status)
+ 
+                for particle in range(num_particles_per_species[ispec]) :
+                    status = artio_particle_read_particle(handle,
+                            &pid, &subspecies, primary_variables,
+                            secondary_variables)
+                    check_artio_status(status)
+                    ind = vpoints[ispec].count
+
+                    for i in range(vpoints[ispec].n_p):
+                        vind = vpoints[ispec].p_ind[i]
+                        vpoints[ispec].pvars[i][ind] = primary_variables[vind]
+                        
+                    for i in range(vpoints[ispec].n_s):
+                        vind = vpoints[ispec].s_ind[i]
+                        vpoints[ispec].svars[i][ind] = secondary_variables[vind]
+                        
+                    if vpoints[ispec].n_pid:
+                        vpoints[ispec].pid[ind] = pid
+
+                status = artio_particle_read_species_end( handle )
+                check_artio_status(status)
+                    
+            status = artio_particle_read_root_cell_end( handle )
+            check_artio_status(status)
+        free(num_particles_per_species)
+        free(total_particles)
+        free(accessed_species)
+        free(vpoints)
+        free(primary_variables)
+        free(secondary_variables)
+        return data
+ 


https://bitbucket.org/yt_analysis/yt-3.0/commits/cf841e03b4c0/
Changeset:   cf841e03b4c0
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-20 03:32:56
Summary:     sfc_end should be the end, not sfc_end + 1.
Affected #:  1 file

diff -r aab8903d082f7a741fe0d9447b14a4d2156e50b1 -r cf841e03b4c01c55c74f33d0e2950a6d4e7ce443 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -812,7 +812,7 @@
             vpoints[ispec].n_p = 0
 
         status = artio_particle_cache_sfc_range( handle,
-                self.sfc_start, self.sfc_end +1 ) 
+                self.sfc_start, self.sfc_end ) 
         check_artio_status(status)
 
         # Pass through once.  We want every single particle.


https://bitbucket.org/yt_analysis/yt-3.0/commits/8c5066a5e107/
Changeset:   8c5066a5e107
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-20 04:14:44
Summary:     Simplify and correct some logic in the OctreeSubset particle reader.
Affected #:  1 file

diff -r cf841e03b4c01c55c74f33d0e2950a6d4e7ce443 -r 8c5066a5e107d90c4c83800bc925e2060d1e0247 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -801,6 +801,8 @@
         primary_variables = <double *>malloc(sizeof(double) * max(npri_vars))
         secondary_variables = <float *>malloc(sizeof(double) * max(nsec_vars))
 
+        cdef particle_var_pointers *vp
+
         for ispec in range(num_species):
             total_particles[ispec] = 0
             accessed_species[ispec] = 0
@@ -808,8 +810,9 @@
             vpoints[ispec].count = 0
             vpoints[ispec].n_mass = 0
             vpoints[ispec].n_pid = 0
+            vpoints[ispec].n_species = 0
+            vpoints[ispec].n_p = 0
             vpoints[ispec].n_s = 0
-            vpoints[ispec].n_p = 0
 
         status = artio_particle_cache_sfc_range( handle,
                 self.sfc_start, self.sfc_end ) 
@@ -838,36 +841,33 @@
             sec_vars = params.get(
                 "species_%02u_secondary_variable_labels" % (species,), [])
             tp = total_particles[species]
+            vp = &vpoints[species]
             if field == "MASS":
-                vpoints[species].n_mass = 1
+                vp.n_mass = 1
                 npf32arr = data[(species, field)] = np.zeros(tp, dtype="float32")
                 # We fill this *now*
                 npf32arr += params["particle_species_mass"][ispec]
-                vpoints[species].mass = <np.float32_t*> npf32arr.data
+                vp.mass = <np.float32_t*> npf32arr.data
             elif field == "PID":
-                vpoints[species].n_pid = 1
-                npi64arr = data[(species, field)] = np.empty(tp, dtype="int64")
-                vpoints[species].pid = <np.int64_t*> npf32arr.data
+                vp.n_pid = 1
+                npi64arr = data[(species, field)] = np.zeros(tp, dtype="int64")
+                vp.pid = <np.int64_t*> npi64arr.data
             elif field == "SPECIES":
-                vpoints[species].n_species = 1
-                npi8arr = data[(species, field)] = np.empty(tp, dtype="int8")
+                vp.n_species = 1
+                npi8arr = data[(species, field)] = np.zeros(tp, dtype="int8")
                 # We fill this *now*
                 npi8arr += species
-                vpoints[species].species = <np.int8_t*> npf32arr.data
+                vp.species = <np.int8_t*> npi8arr.data
             elif npri_vars[species] > 0 and field in pri_vars :
-                npf64arr = data[(species, field)] = np.empty(tp, dtype="float64")
-                vpoints[species].p_ind[vpoints[species].n_p] = \
-                    pri_vars.index(field)
-                vpoints[species].pvars[vpoints[species].n_p] = \
-                    <np.float64_t *> npf64arr.data
-                vpoints[species].n_p += 1
+                npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
+                vp.p_ind[vp.n_p] = pri_vars.index(field)
+                vp.pvars[vp.n_p] = <np.float64_t *> npf64arr.data
+                vp.n_p += 1
             elif nsec_vars[species] > 0 and field in sec_vars :
-                vpoints[species].s_ind[vpoints[species].n_s] = \
-                    sec_vars.index(field)
-                npf32arr = data[(species, field)] = np.empty(tp, dtype="float32")
-                vpoints[species].svars[vpoints[species].n_s] = \
-                    <np.float32_t *> npf32arr.data
-                vpoints[species].n_s += 1
+                npf32arr = data[(species, field)] = np.zeros(tp, dtype="float32")
+                vp.s_ind[vp.n_s] = sec_vars.index(field)
+                vp.svars[vp.n_s] = <np.float32_t *> npf32arr.data
+                vp.n_s += 1
 
         for sfc in range(self.sfc_start, self.sfc_end + 1):
             status = artio_particle_read_root_cell_begin( handle, sfc,
@@ -877,24 +877,27 @@
                 if accessed_species[ispec] == 0: continue
                 status = artio_particle_read_species_begin(handle, ispec);
                 check_artio_status(status)
+                vp = &vpoints[ispec]
  
                 for particle in range(num_particles_per_species[ispec]) :
                     status = artio_particle_read_particle(handle,
                             &pid, &subspecies, primary_variables,
                             secondary_variables)
                     check_artio_status(status)
-                    ind = vpoints[ispec].count
+                    ind = vp.count
 
-                    for i in range(vpoints[ispec].n_p):
-                        vind = vpoints[ispec].p_ind[i]
-                        vpoints[ispec].pvars[i][ind] = primary_variables[vind]
+                    for i in range(vp.n_p):
+                        vind = vp.p_ind[i]
+                        vp.pvars[i][ind] = primary_variables[vind]
                         
-                    for i in range(vpoints[ispec].n_s):
-                        vind = vpoints[ispec].s_ind[i]
-                        vpoints[ispec].svars[i][ind] = secondary_variables[vind]
+                    for i in range(vp.n_s):
+                        vind = vp.s_ind[i]
+                        vp.svars[i][ind] = secondary_variables[vind]
                         
-                    if vpoints[ispec].n_pid:
-                        vpoints[ispec].pid[ind] = pid
+                    if vp.n_pid:
+                        vp.pid[ind] = pid
+
+                    vp.count += 1
 
                 status = artio_particle_read_species_end( handle )
                 check_artio_status(status)


https://bitbucket.org/yt_analysis/yt-3.0/commits/023fdd1eab73/
Changeset:   023fdd1eab73
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-20 05:03:31
Summary:     Fix up a minor errors, including flipping accessed_species values.
Affected #:  1 file

diff -r 8c5066a5e107d90c4c83800bc925e2060d1e0247 -r 023fdd1eab73e8535d35202258932a56121e2c39 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -799,7 +799,7 @@
         npri_vars = params["num_primary_variables"]
         nsec_vars = params["num_secondary_variables"]
         primary_variables = <double *>malloc(sizeof(double) * max(npri_vars))
-        secondary_variables = <float *>malloc(sizeof(double) * max(nsec_vars))
+        secondary_variables = <float *>malloc(sizeof(float) * max(nsec_vars))
 
         cdef particle_var_pointers *vp
 
@@ -836,6 +836,7 @@
         #        self.sfc_start, self.sfc_end + 1, total_particles[ispec], ispec)
         data = {}
         for species, field in sorted(fields):
+            accessed_species[species] = 1
             pri_vars = params.get(
                 "species_%02u_primary_variable_labels" % (species,), [])
             sec_vars = params.get(
@@ -846,7 +847,7 @@
                 vp.n_mass = 1
                 npf32arr = data[(species, field)] = np.zeros(tp, dtype="float32")
                 # We fill this *now*
-                npf32arr += params["particle_species_mass"][ispec]
+                npf32arr += params["particle_species_mass"][species]
                 vp.mass = <np.float32_t*> npf32arr.data
             elif field == "PID":
                 vp.n_pid = 1


https://bitbucket.org/yt_analysis/yt-3.0/commits/ecc2c63f54cb/
Changeset:   ecc2c63f54cb
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-22 19:05:51
Summary:     Initial implementation of an Octree select_blocks method.
Affected #:  4 files

diff -r 023fdd1eab73e8535d35202258932a56121e2c39 -r ecc2c63f54cbd6b4087f3cc53445e219d45d4c5f yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -411,10 +411,12 @@
     def blocks(self):
         for io_chunk in self.chunks([], "io"):
             for i,chunk in enumerate(self.chunks([], "spatial", ngz = 0)):
-                g = self._current_chunk.objs[0]
-                mask = g._get_selector_mask(self.selector)
-                if mask is None: continue
-                yield g, mask
+                # For grids this will be a grid object, and for octrees it will
+                # be an OctreeSubset.  Note that we delegate to the sub-object.
+                o = self._current_chunk.objs[0]
+                for b, m in o.select_blocks(self.selector):
+                    if m is None: continue
+                    yield b, m
 
 class GenerationInProgress(Exception):
     def __init__(self, fields):

diff -r 023fdd1eab73e8535d35202258932a56121e2c39 -r ecc2c63f54cbd6b4087f3cc53445e219d45d4c5f yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -491,6 +491,10 @@
         vals = op.finalize()
         return vals.reshape(self.ActiveDimensions, order="C")
 
+    def select_blocks(self, selector):
+        mask = self._get_selector_mask(selector)
+        yield self, mask
+
     def _get_selector_mask(self, selector):
         if id(selector) == self._last_selector_id:
             mask = self._last_mask

diff -r 023fdd1eab73e8535d35202258932a56121e2c39 -r ecc2c63f54cbd6b4087f3cc53445e219d45d4c5f yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -95,12 +95,24 @@
         if len(arr.shape) == 4: return arr
         nz = self._num_zones + 2*self._num_ghost_zones
         n_oct = arr.shape[0] / (nz**3.0)
-        arr = arr.reshape((nz, nz, nz, n_oct), order="F")
+        if arr.size == nz*nz*nz*n_oct:
+            arr = arr.reshape((nz, nz, nz, n_oct), order="F")
+        elif arr.size == nz*nz*nz*n_oct * 3:
+            arr = arr.reshape((nz, nz, nz, n_oct, 3), order="F")
+        else:
+            raise RuntimeError
         arr = np.asfortranarray(arr)
         return arr
 
     _domain_ind = None
 
+    def select_blocks(self, selector):
+        mask = self.oct_handler.mask(selector)
+        mask = self._reshape_vals(mask)
+        slicer = OctreeSubsetBlockSlice(self)
+        for i, sl in slicer:
+            yield sl, mask[:,:,:,i]
+
     @property
     def domain_ind(self):
         if self._domain_ind is None:
@@ -116,9 +128,11 @@
         nvals = (2, 2, 2, (self.domain_ind >= 0).sum())
         op = cls(nvals) # We allocate number of zones, not number of octs
         op.initialize()
-        mylog.debug("Depositing %s particles into %s Octs",
-            positions.shape[0], nvals[-1])
-        op.process_octree(self.oct_handler, self.domain_ind, positions, fields,
+        mylog.debug("Depositing %s (%s^3) particles into %s Octs",
+            positions.shape[0], positions.shape[0]**0.3333333, nvals[-1])
+        pos = np.array(positions, dtype="float64")
+        f64 = [np.array(f, dtype="float64") for f in fields]
+        op.process_octree(self.oct_handler, self.domain_ind, pos, f64,
             self.domain_id, self._domain_offset)
         vals = op.finalize()
         return np.asfortranarray(vals)
@@ -202,3 +216,48 @@
         self.base_region = base_region
         self.base_selector = base_region.selector
 
+class OctreeSubsetBlockSlice(object):
+    def __init__(self, octree_subset):
+        self.ind = None
+        self.octree_subset = octree_subset
+        # Cache some attributes
+        self.ActiveDimensions = np.array([2,2,2], dtype="int64")
+        for attr in ["ires", "icoords", "fcoords", "fwidth"]:
+            v = getattr(octree_subset, attr)
+            setattr(self, "_%s" % attr, octree_subset._reshape_vals(v))
+
+    def __iter__(self):
+        for i in range(self._ires.shape[-1]):
+            self.ind = i
+            yield i, self
+
+    def clear_data(self):
+        pass
+
+    def __getitem__(self, key):
+        return self.octree_subset[key][:,:,:,self.ind]
+
+    def get_vertex_centered_data(self, *args, **kwargs):
+        raise NotImplementedError
+
+    @property
+    def id(self):
+        return np.random.randint(1)
+
+    @property
+    def Level(self):
+        return self._ires[0,0,0,self.ind]
+
+    @property
+    def LeftEdge(self):
+        LE = self._fcoords[0,0,0,self.ind,:] - self._fwidth[0,0,0,self.ind,:]*0.5
+        return LE
+
+    @property
+    def RightEdge(self):
+        RE = self._fcoords[1,1,1,self.ind,:] + self._fwidth[1,1,1,self.ind,:]*0.5
+        return RE
+
+    @property
+    def dds(self):
+        return self._fwidth[0,0,0,self.ind,:]

diff -r 023fdd1eab73e8535d35202258932a56121e2c39 -r ecc2c63f54cbd6b4087f3cc53445e219d45d4c5f yt/geometry/oct_container.pyx
--- a/yt/geometry/oct_container.pyx
+++ b/yt/geometry/oct_container.pyx
@@ -346,6 +346,22 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    def mask(self, SelectorObject selector, np.int64_t num_octs = -1,
+             int domain_id = -1):
+        if num_octs == -1:
+            num_octs = selector.count_octs(self, domain_id)
+        cdef np.ndarray[np.uint8_t, ndim=1] coords
+        coords = np.zeros((num_octs * 8), dtype="uint8")
+        cdef OctVisitorData data
+        data.array = <void *> coords.data
+        data.index = 0
+        data.domain = domain_id
+        self.visit_all_octs(selector, oct_visitors.mask_octs, &data)
+        return coords.astype("bool")
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     def icoords(self, SelectorObject selector, np.int64_t num_octs = -1,
                 int domain_id = -1):
         if num_octs == -1:


https://bitbucket.org/yt_analysis/yt-3.0/commits/7210b2cf9285/
Changeset:   7210b2cf9285
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-27 20:56:42
Summary:     First attempt at making fill_region work with periodicity.
Affected #:  3 files

diff -r 1c75bda6fe8c71e450a92684c7ca87afd1157c65 -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -497,10 +497,13 @@
     def _fill_fields(self, fields):
         output_fields = [np.zeros(self.ActiveDimensions, dtype="float64")
                          for field in fields]
+        domain_dims = self.pf.domain_dimensions.astype("int64") \
+                    * self.pf.refine_by**self.level
         for chunk in self._data_source.chunks(fields, "io"):
             input_fields = [chunk[field] for field in fields]
-            fill_region(input_fields, output_fields, self.level,
-                        self.global_startindex, chunk.icoords, chunk.ires)
+            tot += fill_region(input_fields, output_fields, self.level,
+                        self.global_startindex, chunk.icoords, chunk.ires,
+                        domain_dims, self.pf.refine_by)
         for name, v in zip(fields, output_fields):
             self[name] = v
 
@@ -654,12 +657,14 @@
         ls = self._initialize_level_state(fields)
         for level in range(self.level + 1):
             tot = 0
+            domain_dims = self.pf.domain_dimensions.astype("int64") \
+                        * self.pf.refine_by**level
             for chunk in ls.data_source.chunks(fields, "io"):
                 chunk[fields[0]]
                 input_fields = [chunk[field] for field in fields]
                 tot += fill_region(input_fields, ls.fields, ls.current_level,
-                            ls.global_startindex, chunk.icoords,
-                            chunk.ires)
+                                ls.global_startindex, chunk.icoords,
+                                chunk.ires, domain_dims, self.pf.refine_by)
             self._update_level_state(ls)
         for name, v in zip(fields, ls.fields):
             if self.level > 0: v = v[1:-1,1:-1,1:-1]

diff -r 1c75bda6fe8c71e450a92684c7ca87afd1157c65 -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae yt/data_objects/tests/test_fields.py
--- a/yt/data_objects/tests/test_fields.py
+++ b/yt/data_objects/tests/test_fields.py
@@ -24,6 +24,7 @@
 _base_fields = ["Density", "x-velocity", "y-velocity", "z-velocity"]
 
 def realistic_pf(fields, nprocs):
+    np.random.seed(int(0x4d3d3d3))
     pf = fake_random_pf(16, fields = fields, nprocs = nprocs)
     pf.parameters["HydroMethod"] = "streaming"
     pf.parameters["Gamma"] = 5.0/3.0
@@ -52,7 +53,7 @@
     def __call__(self):
         field = FieldInfo[self.field_name]
         deps = field.get_dependencies()
-        fields = deps.requested + _base_fields
+        fields = list(set(deps.requested + _base_fields))
         skip_grids = False
         needs_spatial = False
         for v in field.validators:
@@ -99,3 +100,8 @@
         if FieldInfo[field].particle_type: continue
         for nproc in [1, 4, 8]:
             yield TestFieldAccess(field, nproc)
+
+if __name__ == "__main__":
+    setup()
+    for t in test_all_fields():
+        t()

diff -r 1c75bda6fe8c71e450a92684c7ca87afd1157c65 -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae yt/utilities/lib/misc_utilities.pyx
--- a/yt/utilities/lib/misc_utilities.pyx
+++ b/yt/utilities/lib/misc_utilities.pyx
@@ -544,6 +544,7 @@
                 np.ndarray[np.int64_t, ndim=1] left_index,
                 np.ndarray[np.int64_t, ndim=2] ipos,
                 np.ndarray[np.int64_t, ndim=1] ires,
+                np.ndarray[np.int64_t] level_dims,
                 np.int64_t refine_by = 2
                 ):
     cdef int i, n
@@ -552,29 +553,51 @@
     cdef np.ndarray[np.float64_t, ndim=3] ofield
     cdef np.ndarray[np.float64_t, ndim=1] ifield
     nf = len(input_fields)
+    # The variable offsets governs for each dimension and each possible
+    # wrapping if we do it.  Then the wi, wj, wk indices check into each
+    # [dim][wrap] inside the loops.
+    cdef int offsets[3][3], wi, wj, wk
+    cdef np.int64_t off
     for i in range(3):
         dim[i] = output_fields[0].shape[i]
+        offsets[i][0] = offsets[i][2] = 0
+        offsets[i][1] = 1
+        if left_index[i] < 0:
+            offsets[i][0] = 1
+        if left_index[i] + dim[i] >= level_dims[i]:
+            offsets[i][2] = 1
     for n in range(nf):
         tot = 0
         ofield = output_fields[n]
         ifield = input_fields[n]
         for i in range(ipos.shape[0]):
             rf = refine_by**(output_level - ires[i]) 
-            for n in range(3):
-                iind[n] = ipos[i, n] * rf - left_index[n]
-            for oi in range(rf):
-                oind[0] = oi + iind[0]
-                if oind[0] < 0 or oind[0] >= dim[0]:
-                    continue
-                for oj in range(rf):
-                    oind[1] = oj + iind[1]
-                    if oind[1] < 0 or oind[1] >= dim[1]:
+            for wi in range(3):
+                if offsets[0][wi] == 0: continue
+                off = (left_index[0] + level_dims[0]*(wi-1))
+                iind[0] = ipos[i, 0] * rf - off
+                for oi in range(rf):
+                    # Now we need to apply our offset
+                    oind[0] = oi + iind[0]
+                    if oind[0] < 0 or oind[0] >= dim[0]:
                         continue
-                    for ok in range(rf):
-                        oind[2] = ok + iind[2]
-                        if oind[2] < 0 or oind[2] >= dim[2]:
-                            continue
-                        ofield[oind[0], oind[1], oind[2]] = \
-                            ifield[i]
-                        tot += 1
+                    for wj in range(3):
+                        if offsets[1][wj] == 0: continue
+                        off = (left_index[1] + level_dims[1]*(wj-1))
+                        iind[1] = ipos[i, 1] * rf - off
+                        for oj in range(rf):
+                            oind[1] = oj + iind[1]
+                            if oind[1] < 0 or oind[1] >= dim[1]:
+                                continue
+                            for wk in range(3):
+                                if offsets[2][wk] == 0: continue
+                                off = (left_index[2] + level_dims[2]*(wk-1))
+                                iind[2] = ipos[i, 2] * rf - off
+                                for ok in range(rf):
+                                    oind[2] = ok + iind[2]
+                                    if oind[2] < 0 or oind[2] >= dim[2]:
+                                        continue
+                                    ofield[oind[0], oind[1], oind[2]] = \
+                                        ifield[i]
+                                    tot += 1
     return tot


https://bitbucket.org/yt_analysis/yt-3.0/commits/00812df831c5/
Changeset:   00812df831c5
Branch:      yt-3.0
User:        drudd
Date:        2013-07-09 22:54:13
Summary:     First go at adding new SelectorObject functions
Affected #:  2 files

diff -r ce576a114f133a73ea16ae6cc7c705bf444f8833 -r 00812df831c5a43b4457c5ea62a454d6f0f14915 yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -31,6 +31,8 @@
     cdef public np.int32_t min_level
     cdef public np.int32_t max_level
     cdef int overlap_cells
+    cdef np.float64_t domain_width[3]
+    cdef bint periodicity[3]
 
     cdef void recursively_visit_octs(self, Oct *root,
                         np.float64_t pos[3], np.float64_t dds[3],
@@ -43,6 +45,15 @@
                                np.int32_t level, Oct *o = ?) nogil
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil
+
+	cdef int select_point(self, np.float64_t pos[3] ) nogil
+	cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+	cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil
+
+	# compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
+	cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
+
     cdef void set_bounds(self,
                          np.float64_t left_edge[3], np.float64_t right_edge[3],
                          np.float64_t dds[3], int ind[3][2], int *check)

diff -r ce576a114f133a73ea16ae6cc7c705bf444f8833 -r 00812df831c5a43b4457c5ea62a454d6f0f14915 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -122,6 +122,15 @@
         self.max_level = getattr(dobj, "max_level", 99)
         self.overlap_cells = 0
 
+        for i in range(3) :
+            if dob.pf.periodicity[i] and self.domain_left_edge[i] != 0.0 :
+                print "SelectorObject periodicity assumes left_edge == 0"
+                raise RuntimeError
+
+            self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
+                                   dobj.pf.domain_left_edge[i]
+            self.periodicity[i] = dobj.pf.periodicity[i]
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -256,6 +265,28 @@
                          int eterm[3]) nogil:
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        return 0
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        return 0
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil :
+        np.float64_t rel = x1 - x2
+        if self.periodicity[d] :
+            if rel > self.domain_width[d]/2.0 :
+                rel -= self.domain_width[d]
+            elif rel < -self.domain_width[d]/2.0
+                rel += self.domain_width[d]
+        return rel
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -389,15 +420,21 @@
                            np.float64_t radius = 0.0):
         cdef int count = 0
         cdef int i
-        cdef np.float64_t dds[3], pos[3]
-        dds[0] = dds[1] = dds[2] = radius
-        cdef int eterm[3]
-        with nogil:
-            for i in range(x.shape[0]):
-                pos[0] = x[i]
-                pos[1] = y[i]
-                pos[2] = z[i]
-                count += self.select_cell(pos, dds, eterm)
+        cdef np.float64_t pos[3]
+        if radius == 0.0 :
+            with nogil:
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    count += self.select_point(pos)
+        else :
+            with nogil:
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    count += self.select_sphere(pos, radius)
         return count
 
     @cython.boundscheck(False)
@@ -409,43 +446,87 @@
                             np.float64_t radius = 0.0):
         cdef int count = 0
         cdef int i
-        cdef np.float64_t dds[3], pos[3]
-        dds[0] = dds[1] = dds[2] = radius
-        cdef int eterm[3]
+        cdef np.float64_t pos[3]
         cdef np.ndarray[np.uint8_t, ndim=1] mask 
         mask = np.zeros(x.shape[0], dtype='uint8')
-        with nogil:
-            for i in range(x.shape[0]):
-                pos[0] = x[i]
-                pos[1] = y[i]
-                pos[2] = z[i]
-                mask[i] = self.select_cell(pos, dds, eterm)
-                count += mask[i]
+
+        if radius == 0.0 :
+            with nogil :
+                for i in range(x.shape[0]) :
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    mask[i] = self.select_point(pos)
+                    count += mask[i]
+        else :
+              with nogil:
+                    for i in range(x.shape[0]):
+                        pos[0] = x[i]
+                        pos[1] = y[i]
+                        pos[2] = z[i]
+                        mask[i] = self.select_sphere(pos, radius)
+                        count += mask[i]
         if count == 0: return None
         return mask.astype("bool")
 
 cdef class SphereSelector(SelectorObject):
+    cdef np.float64_t radius
     cdef np.float64_t radius2
     cdef np.float64_t center[3]
-    cdef np.float64_t domain_width[3]
-    cdef bint periodicity[3]
 
     def __init__(self, dobj):
         for i in range(3):
             self.center[i] = dobj.center[i]
+        self.radius = dobj.radius
         self.radius2 = dobj.radius * dobj.radius
 
-        for i in range(3) :
-            self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
-                                   dobj.pf.domain_left_edge[i]
-            self.periodicity[i] = dobj.pf.periodicity[i]
-        
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        return self.select_bbox(left_edge,right_edge)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        # sphere center either inside cell or center of cell lies inside sphere
+        if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
+            pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
+            pos[2] - 0.5*dds[2] <= self.center[2] <= pos[2]+0.5*dds[2]):
+            return 1
+        return self.select_point(pos)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil :
+        cdef int i
+        cdef np.float64_t dist2 = 0
+        for i in range(3):
+            dist2 += self.difference( pos[i], self.center[i], i )**2
+        if dist2 <= self.radius2: return 1
+        return 0
+   
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil :
+        cdef int i
+        cdef np.float64_t dist2 = 0
+        for i in range(3):
+            dist2 += self.difference( pos[i], self.center[i], i )**2
+        if dist2 <= (self.radius+radius)**2: return 1
+        return 0
+ 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
         cdef np.float64_t box_center, relcenter, closest, dist, edge
         cdef int i
         if (left_edge[0] <= self.center[0] <= right_edge[0] and
@@ -456,42 +537,13 @@
         dist = 0
         for i in range(3):
             box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.center[i] - box_center
-            if self.periodicity[i]:
-                if relcenter > self.domain_width[i]/2.0: 
-                    relcenter -= self.domain_width[i] 
-                elif relcenter < -self.domain_width[i]/2.0: 
-                    relcenter += self.domain_width[i] 
+            relcenter = self.difference( box_center, self.center[i], i )
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
             dist += closest * closest
         if dist <= self.radius2: return 1
         return 0
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t dist2, temp
-        cdef int i
-        if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
-            pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
-            pos[2] - 0.5*dds[2] <= self.center[2] <= pos[2]+0.5*dds[2]):
-            return 1
-        dist2 = 0
-        for i in range(3):
-            temp = self.center[i] - pos[i]
-            if self.periodicity[i]:
-                if temp > self.domain_width[i]/2.0:
-                    temp -= self.domain_width[i]
-                elif temp < -self.domain_width[i]/2.0:
-                    temp += self.domain_width[i]
-            #temp = temp - fclip(temp, -dds[i]/2.0, dds[i]/2.0)
-            dist2 += temp*temp
-        if dist2 <= self.radius2: return 1
-        return 0
-
 sphere_selector = SphereSelector
 
 cdef class RegionSelector(SelectorObject):
@@ -513,6 +565,14 @@
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
         if level < self.min_level or level > self.max_level: return 0
+        return self.select_bbox( left_edge, right_edge )
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        cdef int i
         for i in range(3):
             if left_edge[i] >= self.right_edge[i]: return 0
             if right_edge[i] <= self.left_edge[i]: return 0
@@ -523,6 +583,7 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
+        cdef int i
         cdef np.float64_t dxp
         for i in range(3):
             dxp = self.dx_pad * dds[i]
@@ -535,6 +596,18 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil :
+        # assume pos[3] is inside domain
+        cdef int i
+        for i in range(3) :
+            if pos[i] < self.left_edge[i] or \
+                    pos[i] >= self.right_edge[i] :
+                return 0
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef void set_bounds(self,
                          np.float64_t left_edge[3], np.float64_t right_edge[3],
                          np.float64_t dds[3], int ind[3][2], int *check):
@@ -564,8 +637,7 @@
 cdef class DiskSelector(SelectorObject):
     cdef np.float64_t norm_vec[3]
     cdef np.float64_t center[3]
-    cdef np.float64_t d
-    cdef np.float64_t radius2
+    cdef np.float64_t radius, radius2
     cdef np.float64_t height
 
     def __init__(self, dobj):
@@ -573,7 +645,7 @@
         for i in range(3):
             self.norm_vec[i] = dobj._norm_vec[i]
             self.center[i] = dobj.center[i]
-        self.d = dobj._d
+        self.radius = dobj._radius
         self.radius2 = dobj._radius * dobj._radius
         self.height = dobj._height
 
@@ -583,13 +655,72 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        return self.select_bbox( left_edge, right_edge )
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        self.select_point( pos ) 
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil :
+        cdef np.float64_t h, d, r2, temp
+        cdef int i
+        h = d = 0
+        for i in range(3):
+            temp = self.difference( pos[i], self.center[i], i )
+            h += temp * self.norm_vec[i]
+            d += temp*temp
+        r2 = (d - h*h)
+        if fabs(h) <= self.height and r2 <= self.radius2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil :
+        cdef np.float64_t h, d, r2, temp
+        cdef int i
+        h = d = 0
+        for i in range(3):
+            temp = self.difference( pos[i], self.center[i], i )
+            h += pos[i] * self.norm_vec[i]
+            d += temp*temp
+        r2 = (d - h*h)
+        if fabs(h) <= self.height+radius and r2 <= (self.radius+radius)**2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil :
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3], H, D, R2, temp
         cdef int i, j, k, n
+        cdef int all_under = 1
+        cdef int all_over = 1
+        cdef int any_radius = 0
+        # A moment of explanation (revised):
+        #    The disk and bounding box collide if any of the following are true:
+        #    1) the center of the disk is inside the bounding box
+        #    2) any corner of the box lies inside the disk
+        #    3) the box spans the plane (!all_under and !all_over) and at least
+        #       one corner is within the cylindrical radius
+`
+        # check if disk center lies inside bbox
+        if left_edge[0] <= self.center[0] <= right_edge[0] and \
+           left_edge[1] <= self.center[1] <= right_edge[1] and \
+           left_edge[2] <= self.center[2] <= right_edge[2] :
+            return 1
+        
+        # check all corners
         arr[0] = left_edge
         arr[1] = right_edge
-        cdef int cond[2]
-        cond[0] = cond[1] = 0
         for i in range(2):
             pos[0] = arr[i][0]
             for j in range(2):
@@ -598,39 +729,16 @@
                     pos[2] = arr[k][2]
                     H = D = 0
                     for n in range(3):
-                        H += (pos[n] * self.norm_vec[n])
-                        temp = (pos[n] - self.center[n])
+                        temp = self.difference( pos[n], self.center[n], n )
+                        H += (temp * self.norm_vec[n])
                         D += temp*temp
-                    H += self.d
                     R2 = (D - H*H)
-                    if fabs(H) < self.height: cond[0] = 1
-                    if R2 < self.radius2: cond[1] = 1
-        # A moment of explanation:
-        #    We want our height to be less than the height AND our radius2 to be
-        #    less than radius2, so we set cond[0] equal to 1 if any corners
-        #    match that criteria.
-        # Note that we OVERSELECT grids, as we are selecting anything within
-        # the height and within the radius, which is kind of a funny thing.
-        # Cell selection takes care of the rest.
-        if cond[0] == 1 and cond[1] == 1:
-            return 1
-        return 0
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t h, d, r2, temp
-        cdef int i
-        h = d = 0
-        for i in range(3):
-            h += pos[i] * self.norm_vec[i]
-            temp = pos[i] - self.center[i]
-            d += temp*temp
-        h += self.d
-        r2 = (d - h*h)
-        if fabs(h) <= self.height and r2 <= self.radius2: return 1
+                    if R2 < self.radius2 :
+                        any_radius = 1
+                        if fabs(H) < self.height: return 1
+                    if H < 0: all_over = 0
+                    if H > 0: all_under = 0
+        if !all_over and !all_under and any_radius: return 1
         return 0
 
 disk_selector = DiskSelector
@@ -651,6 +759,43 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        return self.select_bbox(left_edge,right_edge)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        cdef np.float64_t diag2, height
+        cdef int i
+        height = self.d
+        diag2 = 0
+        for i in range(3):
+            height += pos[i] * self.norm_vec[i]
+            diag2 += dds[i] * dds[i] * 0.25
+        if height * height <= diag2: return 1
+        return 0
+
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        cdef int i
+        cdef np.float64_t height = self.d
+        for i in range(3) :
+            height += pos[i] * self.norm_vec[i]
+        if height*height <= radius**2 : return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil :
         cdef int i, j, k, n
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3]
@@ -675,20 +820,6 @@
             return 0
         return 1
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t diag2, height
-        cdef int i
-        height = self.d
-        diag2 = 0
-        for i in range(3):
-            height += pos[i] * self.norm_vec[i]
-            diag2 += dds[i] * dds[i] * 0.25
-        if height * height <= diag2: return 1
-        return 0
 
 cutting_selector = CuttingPlaneSelector
 
@@ -719,11 +850,8 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        if right_edge[self.axis] > self.coord \
-           and left_edge[self.axis] <= self.coord:
-            return 1
-        return 0
-    
+        return self.select_bbox( left_edge, right_edge )
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -734,6 +862,27 @@
             return 1
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        if self.difference( pos[self.axis], self.coord, self.axis )**2 < radius**2 :
+            return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil :
+        if left_edge[self.axis] <= self.coord < right_edge[self.axis] :
+            return 1
+        return 0
+
 slice_selector = SliceSelector
 
 cdef class OrthoRaySelector(SelectorObject):
@@ -757,25 +906,42 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        if (    (self.px >= left_edge[self.px_ax])
-            and (self.px < right_edge[self.px_ax])
-            and (self.py >= left_edge[self.py_ax])
-            and (self.py < right_edge[self.py_ax])):
-            return 1
-        return 0
-    
+        return self.select_bbox(left_edge,right_edge)
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        if (    (self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax])
+        if (self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax])
             and (self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax])
             and (self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax])
             and (self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax])):
             return 1
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        if self.difference( pos[self.px_ax], self.px, self.px_ax )**2 + \
+           self.difference( pos[self.py_ax], self.py, self.py_ax )**2 < radius**2 :
+            return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil :
+        if left_edge[self.px_ax] <= self.px < right_edge[self.px_ax] and \
+           left_edge[self.py_ax] <= self.py < right_edge[self.py_ax] :
+            return 1
+        return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -836,46 +1002,7 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        cdef int i, ax
-        cdef int i1, i2
-        cdef np.float64_t vs[3], t, v[3]
-        for ax in range(3):
-            i1 = (ax+1) % 3
-            i2 = (ax+2) % 3
-            t = (left_edge[ax] - self.p1[ax])/self.vec[ax]
-            for i in range(3):
-                vs[i] = t * self.vec[i] + self.p1[i]
-            if left_edge[i1] <= vs[i1] and \
-               right_edge[i1] >= vs[i1] and \
-               left_edge[i2] <= vs[i2] and \
-               right_edge[i2] >= vs[i2] and \
-               0.0 <= t <= 1.0:
-                return 1
-            t = (right_edge[ax] - self.p1[ax])/self.vec[ax]
-            for i in range(3):
-                vs[i] = t * self.vec[i] + self.p1[i]
-            if left_edge[i1] <= vs[i1] and \
-               right_edge[i1] >= vs[i1] and \
-               left_edge[i2] <= vs[i2] and \
-               right_edge[i2] >= vs[i2] and\
-               0.0 <= t <= 1.0:
-                return 1
-        # if the point is fully enclosed, we count the grid
-        if left_edge[0] <= self.p1[0] and \
-           right_edge[0] >= self.p1[0] and \
-           left_edge[1] <= self.p1[1] and \
-           right_edge[1] >= self.p1[1] and \
-           left_edge[2] <= self.p1[2] and \
-           right_edge[2] >= self.p1[2]:
-            return 1
-        if left_edge[0] <= self.p2[0] and \
-           right_edge[0] >= self.p2[0] and \
-           left_edge[1] <= self.p2[1] and \
-           right_edge[1] >= self.p2[1] and \
-           left_edge[2] <= self.p2[2] and \
-           right_edge[2] >= self.p2[2]:
-            return 1
-        return 0
+        return self.select_bbox(left_edge,right_edge)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -951,7 +1078,49 @@
         if not (ni == ia.hits):
             print ni, ia.hits
         return dtr, tr
-    
+
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        # two 0-volume constructs don't intersect
+        return 0
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        raise RuntimeError
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        cdef int i, ax
+        cdef int i1, i2
+        cdef np.float64_t vs[3], t, v[3]
+
+        # if either point is fully enclosed, we select the bounding box
+        if left_edge[0] <= self.p1[0] <= right_edge[0] and \
+           left_edge[1] <= self.p1[1] <= right_edge[1] and \
+           left_edge[2] <= self.p1[2] <= right_edge[2] :
+            return 1
+        if left_edge[0] <= self.p2[0] <= right_edge[0] and \
+           left_edge[1] <= self.p2[1] <= right_edge[1] and \
+           left_edge[2] <= self.p2[2] <= right_edge[2] :
+            return 1
+
+        for ax in range(3):
+            i1 = (ax+1) % 3
+            i2 = (ax+2) % 3
+            t = (left_edge[ax] - self.p1[ax])/self.vec[ax]
+            if 0.0 <= t <= 1.0 :
+                for i in range(3):
+                    vs[i] = t * self.vec[i] + self.p1[i]
+                if left_edge[i1] <= vs[i1] <= right_edge[i1] and \
+                   left_edge[i2] <= vs[i2] <= right_edge[i2] :
+                    return 1
+            t = (right_edge[ax] - self.p1[ax])/self.vec[ax]
+            if 0.0 <= t <= 1.0 :
+                for i in range(3):
+                    vs[i] = t * self.vec[i] + self.p1[i]
+                if left_edge[i1] <= vs[i1] <= right_edge[i1] and \
+                   left_edge[i2] <= vs[i2] <= right_edge[i2] :
+                    return 1
+        return 0
+
 ray_selector = RaySelector
 
 cdef class DataCollectionSelector(SelectorObject):
@@ -984,8 +1153,6 @@
         cdef np.ndarray[np.int64_t, ndim=1] oids = self.obj_ids
         with nogil:
             for n in range(self.nids):
-                # Call our selector function
-                # Check if the sphere is inside the grid
                 gridi[oids[n]] = 1
         return gridi.astype("bool")
 
@@ -1003,6 +1170,16 @@
         mask = np.ones(gobj.ActiveDimensions, dtype='uint8')
         return mask.astype("bool")
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        raise RuntimeError
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        raise RuntimeError
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        raise RuntimeError
+
 data_collection_selector = DataCollectionSelector
 
 cdef class EllipsoidSelector(SelectorObject):
@@ -1027,9 +1204,53 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        self.select_bbox( left_edge, right_edge )
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        self.select_point(pos)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        cdef np.float64_t dot_evec[3]
+        cdef np.float64_t dist
+        cdef int i, j
+        dot_evec[0] = dot_evec[1] = dot_evec[2] = 0
+        # Calculate the rotated dot product
+        for i in range(3): # axis
+            dist = self.difference( pos[i], self.center[i], i )
+            for j in range(3):
+                dot_evec[j] += dist * self.vec[j][i]
+        dist = 0.0
+        for i in range(3):
+            dist += (dot_evec[i] * dot_evec[i])/(self.mag[i] * self.mag[i])
+        if dist <= 1.0: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil :
+        # this is the sphere selection
+        cdef int i
+        cdef np.float64_t dist2 = 0
+        for i in range(3):
+            dist2 += self.difference( pos[i], self.center[i], i )**2
+        if dist2 <= (self.mag[0]+radius)**2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
         # This is the sphere selection
         cdef np.float64_t radius2, box_center, relcenter, closest, dist, edge
-        return 1
         radius2 = self.mag[0] * self.mag[0]
         cdef int id
         if (left_edge[0] <= self.center[0] <= right_edge[0] and
@@ -1040,31 +1261,11 @@
         dist = 0
         for i in range(3):
             box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.center[i] - box_center
+            relcenter = self.difference( box_center, self.center[i], i )
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
             dist += closest * closest
-        if dist < radius2: return 1
-        return 0
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t dot_evec[3]
-        cdef np.float64_t dist
-        cdef int i, j
-        dot_evec[0] = dot_evec[1] = dot_evec[2] = 0
-        # Calculate the rotated dot product
-        for i in range(3): # axis
-            dist = pos[i] - self.center[i]
-            for j in range(3):
-                dot_evec[j] += dist * self.vec[j][i]
-        dist = 0.0
-        for i in range(3):
-            dist += (dot_evec[i] * dot_evec[i])/(self.mag[i] * self.mag[i])
-        if dist <= 1.0: return 1
+        if dist <= self.radius2: return 1
         return 0
 
 ellipsoid_selector = EllipsoidSelector
@@ -1115,6 +1316,15 @@
                          int eterm[3]) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        raise RuntimeError
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        raise RuntimeError
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        raise RuntimeError
 
 grid_selector = GridSelector
 
@@ -1165,6 +1375,16 @@
             return -1
         return res
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        raise RuntimeError
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        raise RuntimeError
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        raise RuntimeError
+
 octree_subset_selector = OctreeSubsetSelector
 
 cdef class ParticleOctreeSubsetSelector(SelectorObject):
@@ -1212,6 +1432,16 @@
         # checking this.
         return self.base_selector.select_grid(left_edge, right_edge, level, o)
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        raise RuntimeError
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        raise RuntimeError 
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        raise RuntimeError
+
 particle_octree_subset_selector = ParticleOctreeSubsetSelector
 
 cdef class AlwaysSelector(SelectorObject):
@@ -1251,4 +1481,14 @@
                          Oct *o = NULL) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+        return 1
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+        return 1
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil :
+        return 1
+
 always_selector = AlwaysSelector


https://bitbucket.org/yt_analysis/yt-3.0/commits/32551439af96/
Changeset:   32551439af96
Branch:      yt-3.0
User:        drudd
Date:        2013-07-10 00:02:27
Summary:     Compilation and gil fixes (removed exceptions)
Affected #:  2 files

diff -r 00812df831c5a43b4457c5ea62a454d6f0f14915 -r 32551439af9627f3b087eb50dd31ec658b480077 yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -46,13 +46,13 @@
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil
 
-	cdef int select_point(self, np.float64_t pos[3] ) nogil
-	cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
-	cdef int select_bbox(self, np.float64_t left_edge[3],
+    cdef int select_point(self, np.float64_t pos[3] ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil
 
 	# compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
-	cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
 
     cdef void set_bounds(self,
                          np.float64_t left_edge[3], np.float64_t right_edge[3],

diff -r 00812df831c5a43b4457c5ea62a454d6f0f14915 -r 32551439af9627f3b087eb50dd31ec658b480077 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -123,7 +123,7 @@
         self.overlap_cells = 0
 
         for i in range(3) :
-            if dob.pf.periodicity[i] and self.domain_left_edge[i] != 0.0 :
+            if dobj.pf.periodicity[i] and self.domain_left_edge[i] != 0.0 :
                 print "SelectorObject periodicity assumes left_edge == 0"
                 raise RuntimeError
 
@@ -265,25 +265,25 @@
                          int eterm[3]) nogil:
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
         return 0
 
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
         return 0
 
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
+                               np.float64_t right_edge[3]) nogil:
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil :
-        np.float64_t rel = x1 - x2
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil:
+        cdef np.float64_t rel = x1 - x2
         if self.periodicity[d] :
             if rel > self.domain_width[d]/2.0 :
                 rel -= self.domain_width[d]
-            elif rel < -self.domain_width[d]/2.0
+            elif rel < -self.domain_width[d]/2.0 :
                 rel += self.domain_width[d]
         return rel
 
@@ -451,7 +451,7 @@
         mask = np.zeros(x.shape[0], dtype='uint8')
 
         if radius == 0.0 :
-            with nogil :
+            with nogil:
                 for i in range(x.shape[0]) :
                     pos[0] = x[i]
                     pos[1] = y[i]
@@ -503,7 +503,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_point(self, np.float64_t pos[3]) nogil :
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         cdef int i
         cdef np.float64_t dist2 = 0
         for i in range(3):
@@ -514,7 +514,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil :
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         cdef int i
         cdef np.float64_t dist2 = 0
         for i in range(3):
@@ -571,7 +571,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
+                               np.float64_t right_edge[3]) nogil:
         cdef int i
         for i in range(3):
             if left_edge[i] >= self.right_edge[i]: return 0
@@ -596,7 +596,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_point(self, np.float64_t pos[3]) nogil :
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         # assume pos[3] is inside domain
         cdef int i
         for i in range(3) :
@@ -667,7 +667,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_point(self, np.float64_t pos[3]) nogil :
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         cdef np.float64_t h, d, r2, temp
         cdef int i
         h = d = 0
@@ -682,7 +682,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil :
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
         cdef np.float64_t h, d, r2, temp
         cdef int i
         h = d = 0
@@ -698,7 +698,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil :
+                               np.float64_t right_edge[3] ) nogil:
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3], H, D, R2, temp
         cdef int i, j, k, n
@@ -711,7 +711,7 @@
         #    2) any corner of the box lies inside the disk
         #    3) the box spans the plane (!all_under and !all_over) and at least
         #       one corner is within the cylindrical radius
-`
+
         # check if disk center lies inside bbox
         if left_edge[0] <= self.center[0] <= right_edge[0] and \
            left_edge[1] <= self.center[1] <= right_edge[1] and \
@@ -738,7 +738,7 @@
                         if fabs(H) < self.height: return 1
                     if H < 0: all_over = 0
                     if H > 0: all_under = 0
-        if !all_over and !all_under and any_radius: return 1
+        if all_over == 0 and all_under == 0 and any_radius == 1: return 1
         return 0
 
 disk_selector = DiskSelector
@@ -776,14 +776,14 @@
         if height * height <= diag2: return 1
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
         cdef int i
         cdef np.float64_t height = self.d
         for i in range(3) :
@@ -795,7 +795,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil :
+                               np.float64_t right_edge[3] ) nogil:
         cdef int i, j, k, n
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3]
@@ -862,14 +862,14 @@
             return 1
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
         if self.difference( pos[self.axis], self.coord, self.axis )**2 < radius**2 :
             return 1
         return 0
@@ -878,7 +878,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil :
+                               np.float64_t right_edge[3] ) nogil:
         if left_edge[self.axis] <= self.coord < right_edge[self.axis] :
             return 1
         return 0
@@ -913,21 +913,21 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        if (self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax])
-            and (self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax])
-            and (self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax])
-            and (self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax])):
+        if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
+           self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
+           self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax] and \
+           self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax]:
             return 1
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
         if self.difference( pos[self.px_ax], self.px, self.px_ax )**2 + \
            self.difference( pos[self.py_ax], self.py, self.py_ax )**2 < radius**2 :
             return 1
@@ -937,7 +937,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil :
+                               np.float64_t right_edge[3] ) nogil:
         if left_edge[self.px_ax] <= self.px < right_edge[self.px_ax] and \
            left_edge[self.py_ax] <= self.py < right_edge[self.py_ax] :
             return 1
@@ -1079,15 +1079,16 @@
             print ni, ia.hits
         return dtr, tr
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
-        raise RuntimeError
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        # not implemented
+        return 0        
 
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
+                               np.float64_t right_edge[3]) nogil:
         cdef int i, ax
         cdef int i1, i2
         cdef np.float64_t vs[3], t, v[3]
@@ -1170,16 +1171,6 @@
         mask = np.ones(gobj.ActiveDimensions, dtype='uint8')
         return mask.astype("bool")
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
-        raise RuntimeError
-
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
-        raise RuntimeError
-
-    cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
-        raise RuntimeError
-
 data_collection_selector = DataCollectionSelector
 
 cdef class EllipsoidSelector(SelectorObject):
@@ -1235,7 +1226,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil :
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         # this is the sphere selection
         cdef int i
         cdef np.float64_t dist2 = 0
@@ -1248,7 +1239,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
+                               np.float64_t right_edge[3]) nogil:
         # This is the sphere selection
         cdef np.float64_t radius2, box_center, relcenter, closest, dist, edge
         radius2 = self.mag[0] * self.mag[0]
@@ -1265,7 +1256,7 @@
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
             dist += closest * closest
-        if dist <= self.radius2: return 1
+        if dist <= radius2: return 1
         return 0
 
 ellipsoid_selector = EllipsoidSelector
@@ -1316,16 +1307,6 @@
                          int eterm[3]) nogil:
         return 1
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
-        raise RuntimeError
-
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
-        raise RuntimeError
-
-    cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
-        raise RuntimeError
-
 grid_selector = GridSelector
 
 cdef class OctreeSubsetSelector(SelectorObject):
@@ -1375,16 +1356,6 @@
             return -1
         return res
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
-        raise RuntimeError
-
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
-        raise RuntimeError
-
-    cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
-        raise RuntimeError
-
 octree_subset_selector = OctreeSubsetSelector
 
 cdef class ParticleOctreeSubsetSelector(SelectorObject):
@@ -1432,16 +1403,6 @@
         # checking this.
         return self.base_selector.select_grid(left_edge, right_edge, level, o)
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
-        raise RuntimeError
-
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
-        raise RuntimeError 
-
-    cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
-        raise RuntimeError
-
 particle_octree_subset_selector = ParticleOctreeSubsetSelector
 
 cdef class AlwaysSelector(SelectorObject):
@@ -1481,14 +1442,14 @@
                          Oct *o = NULL) nogil:
         return 1
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil :
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
         return 1
 
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
         return 1
 
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3]) nogil :
+                               np.float64_t right_edge[3]) nogil:
         return 1
 
 always_selector = AlwaysSelector


https://bitbucket.org/yt_analysis/yt-3.0/commits/d65a8e539460/
Changeset:   d65a8e539460
Branch:      yt-3.0
User:        drudd
Date:        2013-07-10 00:07:31
Summary:     Fix in SelectorObject __cinit__
Affected #:  1 file

diff -r 32551439af9627f3b087eb50dd31ec658b480077 -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -123,7 +123,7 @@
         self.overlap_cells = 0
 
         for i in range(3) :
-            if dobj.pf.periodicity[i] and self.domain_left_edge[i] != 0.0 :
+            if dobj.pf.periodicity[i] and self.pf.domain_left_edge[i] != 0.0 :
                 print "SelectorObject periodicity assumes left_edge == 0"
                 raise RuntimeError
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/28f491c2cabd/
Changeset:   28f491c2cabd
Branch:      yt-3.0
User:        drudd
Date:        2013-07-12 21:38:36
Summary:     Merged yt_analysis/yt-3.0 into yt-3.0
Affected #:  44 files

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 setup.py
--- a/setup.py
+++ b/setup.py
@@ -6,8 +6,11 @@
 import subprocess
 import shutil
 import glob
-import distribute_setup
-distribute_setup.use_setuptools()
+import setuptools
+from distutils.version import StrictVersion
+if StrictVersion(setuptools.__version__) < StrictVersion('0.7.0'):
+    import distribute_setup
+    distribute_setup.use_setuptools()
 
 from distutils.command.build_py import build_py
 from numpy.distutils.misc_util import appendpath
@@ -153,8 +156,6 @@
 # End snippet
 ######
 
-import setuptools
-
 VERSION = "3.0dev"
 
 if os.path.exists('MANIFEST'):

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -83,3 +83,26 @@
 """
 
 __version__ = "3.0-dev"
+
+def run_nose(verbose=False, run_answer_tests=False, answer_big_data=False):
+    import nose, os, sys
+    from yt.config import ytcfg
+    nose_argv = sys.argv
+    nose_argv += ['--exclude=answer_testing','--detailed-errors']
+    if verbose:
+        nose_argv.append('-v')
+    if run_answer_tests:
+        nose_argv.append('--with-answer-testing')
+    if answer_big_data:
+        nose_argv.append('--answer-big-data')
+    log_suppress = ytcfg.getboolean("yt","suppressStreamLogging")
+    ytcfg["yt","suppressStreamLogging"] = 'True'
+    initial_dir = os.getcwd()
+    yt_file = os.path.abspath(__file__)
+    yt_dir = os.path.dirname(yt_file)
+    os.chdir(yt_dir)
+    try:
+        nose.run(argv=nose_argv)
+    finally:
+        os.chdir(initial_dir)
+        ytcfg["yt","suppressStreamLogging"] = log_suppress

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/analysis_modules/radmc3d_export/RadMC3DInterface.py
--- a/yt/analysis_modules/radmc3d_export/RadMC3DInterface.py
+++ b/yt/analysis_modules/radmc3d_export/RadMC3DInterface.py
@@ -158,7 +158,8 @@
         self.layers.append(base_layer)
         self.cell_count += np.product(pf.domain_dimensions)
 
-        for grid in pf.h.grids:
+        sorted_grids = sorted(pf.h.grids, key=lambda x: x.Level)
+        for grid in sorted_grids:
             if grid.Level <= self.max_level:
                 self._add_grid_to_layers(grid)
 
@@ -232,11 +233,11 @@
             if p == 0:
                 ind = (layer.LeftEdge - LE) / (2.0*dds) + 1
             else:
-                LE = np.zeros(3)
+                parent_LE = np.zeros(3)
                 for potential_parent in self.layers:
                     if potential_parent.id == p:
-                        LE = potential_parent.LeftEdge
-                ind = (layer.LeftEdge - LE) / (2.0*dds) + 1
+                        parent_LE = potential_parent.LeftEdge
+                ind = (layer.LeftEdge - parent_LE) / (2.0*dds) + 1
             ix  = int(ind[0]+0.5)
             iy  = int(ind[1]+0.5)
             iz  = int(ind[2]+0.5)

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -409,7 +409,8 @@
         self.left_edge = np.array(left_edge)
         self.level = level
         rdx = self.pf.domain_dimensions*self.pf.refine_by**level
-        self.dds = self.pf.domain_width/rdx.astype("float64")
+        rdx[np.where(dims - 2 * num_ghost_zones <= 1)] = 1   # issue 602
+        self.dds = self.pf.domain_width / rdx.astype("float64")
         self.ActiveDimensions = np.array(dims, dtype='int32')
         self.right_edge = self.left_edge + self.ActiveDimensions*self.dds
         self._num_ghost_zones = num_ghost_zones

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -467,7 +467,21 @@
         if self._current_chunk is None:
             self.hierarchy._identify_base_chunk(self)
         if fields is None: return
-        fields = self._determine_fields(fields)
+        nfields = []
+        apply_fields = defaultdict(list)
+        for field in self._determine_fields(fields):
+            if field[0] in self.pf.h.filtered_particle_types:
+                f = self.pf.known_filters[field[0]]
+                apply_fields[field[0]].append(
+                    (f.filtered_type, field[1]))
+            else:
+                nfields.append(field)
+        for filter_type in apply_fields:
+            f = self.pf.known_filters[filter_type]
+            with f.apply(self):
+                self.get_data(apply_fields[filter_type])
+        fields = nfields
+        if len(fields) == 0: return
         # Now we collect all our fields
         # Here is where we need to perform a validation step, so that if we
         # have a field requested that we actually *can't* yet get, we put it
@@ -1166,6 +1180,7 @@
 
 class YTValueCutExtractionBase(YTSelectionContainer3D):
     _type_name = "cut_region"
+    _con_args = ("_base_region", "_field_cuts")
     """
     In-line extracted regions accept a base region and a set of field_cuts to
     determine which points in a grid should be included.

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -67,6 +67,7 @@
         self._child_mask = self._child_indices = self._child_index_mask = None
         self.start_index = None
         self._last_mask = None
+        self._last_count = -1
         self._last_selector_id = None
         self._current_particle_type = 'all'
         self._current_fluid_type = self.pf.default_fluid_type
@@ -447,14 +448,14 @@
     def select_icoords(self, dobj):
         mask = self._get_selector_mask(dobj.selector)
         if mask is None: return np.empty((0,3), dtype='int64')
-        coords = convert_mask_to_indices(mask, mask.sum())
+        coords = convert_mask_to_indices(mask, self._last_count)
         coords += self.get_global_startindex()[None, :]
         return coords
 
     def select_fcoords(self, dobj):
         mask = self._get_selector_mask(dobj.selector)
         if mask is None: return np.empty((0,3), dtype='float64')
-        coords = convert_mask_to_indices(mask, mask.sum()).astype("float64")
+        coords = convert_mask_to_indices(mask, self._last_count).astype("float64")
         coords += 0.5
         coords *= self.dds[None, :]
         coords += self.LeftEdge[None, :]
@@ -471,7 +472,7 @@
     def select_ires(self, dobj):
         mask = self._get_selector_mask(dobj.selector)
         if mask is None: return np.empty(0, dtype='int64')
-        coords = np.empty(mask.sum(), dtype='int64')
+        coords = np.empty(self._last_count, dtype='int64')
         coords[:] = self.Level
         return coords
 
@@ -496,6 +497,10 @@
         else:
             self._last_mask = mask = selector.fill_mask(self)
             self._last_selector_id = id(selector)
+            if mask is None:
+                self._last_count = 0
+            else:
+                self._last_count = mask.sum()
         return mask
 
     def select(self, selector, source, dest, offset):
@@ -508,7 +513,7 @@
     def count(self, selector):
         mask = self._get_selector_mask(selector)
         if mask is None: return 0
-        return mask.sum()
+        return self._last_count
 
     def count_particles(self, selector, x, y, z):
         # We don't cache the selector results

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/particle_fields.py
--- a/yt/data_objects/particle_fields.py
+++ b/yt/data_objects/particle_fields.py
@@ -42,6 +42,7 @@
     mh
 
 def particle_deposition_functions(ptype, coord_name, mass_name, registry):
+    orig = set(registry.keys())
     def particle_count(field, data):
         pos = data[ptype, coord_name]
         d = data.deposit(pos, method = "count")
@@ -112,6 +113,9 @@
             particle_type = True,
             units = r"\mathrm{M}_\odot")
 
+    return list(set(registry.keys()).difference(orig))
+
+
 def particle_scalar_functions(ptype, coord_name, vel_name, registry):
 
     # Now we have to set up the various velocity and coordinate things.  In the
@@ -119,6 +123,8 @@
     # elsewhere, and stop using these.
     
     # Note that we pass in _ptype here so that it's defined inside the closure.
+    orig = set(registry.keys())
+
     def _get_coord_funcs(axi, _ptype):
         def _particle_velocity(field, data):
             return data[_ptype, vel_name][:,axi]
@@ -132,9 +138,12 @@
         registry.add_field((ptype, "particle_position_%s" % ax),
             particle_type = True, function = p)
 
+    return list(set(registry.keys()).difference(orig))
+
 def particle_vector_functions(ptype, coord_names, vel_names, registry):
 
     # This will column_stack a set of scalars to create vector fields.
+    orig = set(registry.keys())
 
     def _get_vec_func(_ptype, names):
         def particle_vectors(field, data):
@@ -147,3 +156,4 @@
                        function=_get_vec_func(ptype, vel_names),
                        particle_type=True)
 
+    return list(set(registry.keys()).difference(orig))

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/particle_filters.py
--- /dev/null
+++ b/yt/data_objects/particle_filters.py
@@ -0,0 +1,95 @@
+"""
+This is a library for defining and using particle filters.
+
+Author: Matthew Turk <matthewturk at gmail.com>
+Affiliation: Columbia University
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2013 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 numpy as np
+import copy
+from contextlib import contextmanager
+
+from yt.data_objects.field_info_container import \
+    NullFunc, TranslationFunc
+from yt.utilities.exceptions import YTIllDefinedFilter
+from yt.funcs import *
+
+# One to many mapping
+filter_registry = defaultdict(list)
+
+class DummyFieldInfo(object):
+    particle_type = True
+dfi = DummyFieldInfo()
+
+class ParticleFilter(object):
+    def __init__(self, name, function, requires, filtered_type):
+        self.name = name
+        self.function = function
+        self.requires = requires[:]
+        self.filtered_type = filtered_type
+
+    @contextmanager
+    def apply(self, dobj):
+        with dobj._chunked_read(dobj._current_chunk):
+            with dobj._field_type_state(self.filtered_type, dfi):
+                # We won't be storing the field data from the whole read, so we
+                # start by filtering now.
+                filter = self.function(self, dobj)
+                yield
+                # Retain a reference here, and we'll filter all appropriate fields
+                # later.
+                fd = dobj.field_data
+        for f, tr in fd.items():
+            if f[0] != self.filtered_type: continue
+            if tr.shape != filter.shape and tr.shape[0] != filter.shape[0]:
+                raise YTIllDefinedFilter(self, tr.shape, filter.shape)
+            elif filter.size == 0:
+                # Filtering empty set.  This keeps our dimensions correct.
+                # Otherwise we end up with out-of-axis and shape problems.
+                d = tr.copy() 
+            elif len(tr.shape) > len(filter.shape):
+                # Filter must always be 1D
+                d = tr[filter,:]
+            else:
+                d = tr[filter]
+            dobj.field_data[self.name, f[1]] = d
+
+    def available(self, field_list):
+        # Note that this assumes that all the fields in field_list have the
+        # same form as the 'requires' attributes.  This won't be true if the
+        # fields are implicitly "all" or something.
+        return all((self.filtered_type, field) in field_list for field in self.requires)
+
+    def wrap_func(self, field_name, old_fi):
+        new_fi = copy.copy(old_fi)
+        new_fi.name = (self.filtered_type, field_name[1])
+        return new_fi
+
+def add_particle_filter(name, function, requires = None, filtered_type = "all"):
+    if requires is None: requires = []
+    filter = ParticleFilter(name, function, requires, filtered_type)
+    filter_registry[name].append(filter)
+
+def particle_filter(name, requires = None, filtered_type = "all"):
+    def _pfilter(func):
+        add_particle_filter(name, func, requires, filtered_type)
+        return func
+    return _pfilter

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -9,5 +9,6 @@
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
     config.make_config_py()  # installs __config__.py
+    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -37,6 +37,8 @@
     output_type_registry
 from yt.data_objects.field_info_container import \
     FieldInfoContainer, NullFunc
+from yt.data_objects.particle_filters import \
+    filter_registry
 from yt.utilities.minimal_representation import \
     MinimalStaticOutput
 
@@ -61,6 +63,8 @@
     coordinates = None
     max_level = 99
     storage_filename = None
+    _particle_mass_name = None
+    _particle_coordinates_name = None
 
     class __metaclass__(type):
         def __init__(cls, name, b, d):
@@ -71,7 +75,12 @@
     def __new__(cls, filename=None, *args, **kwargs):
         if not isinstance(filename, types.StringTypes):
             obj = object.__new__(cls)
-            obj.__init__(filename, *args, **kwargs)
+            # The Stream frontend uses a StreamHandler object to pass metadata
+            # to __init__.
+            is_stream = (hasattr(filename, 'get_fields') and
+                         hasattr(filename, 'get_particle_type'))
+            if not is_stream:
+                obj.__init__(filename, *args, **kwargs)
             return obj
         apath = os.path.abspath(filename)
         if not os.path.exists(apath): raise IOError(filename)
@@ -89,6 +98,7 @@
         self.file_style = file_style
         self.conversion_factors = {}
         self.parameters = {}
+        self.known_filters = {}
 
         # path stuff
         self.parameter_filename = str(filename)
@@ -250,6 +260,21 @@
         else:
             raise YTGeometryNotSupported(self.geometry)
 
+    def add_particle_filter(self, filter):
+        if isinstance(filter, types.StringTypes):
+            used = False
+            for f in filter_registry[filter]:
+                used = self.h._setup_filtered_type(f)
+                if used:
+                    filter = f
+                    break
+        else:
+            used = self.h._setup_filtered_type(filter)
+        if not used:
+            return False
+        self.known_filters[filter.name] = filter
+        return True
+
     _last_freq = (None, None)
     _last_finfo = None
     def _get_field_info(self, ftype, fname):

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -1087,7 +1087,7 @@
 
     return get_sph_r_component(Bfields, theta, phi, normal)
 
-add_field("BRadial", function=_BPoloidal,
+add_field("BRadial", function=_BRadial,
           units=r"\rm{Gauss}",
           validators=[ValidateParameter("normal")])
 
@@ -1420,7 +1420,7 @@
     domegax_dt = data["VorticityX"] / data["VorticityGrowthX"]
     domegay_dt = data["VorticityY"] / data["VorticityGrowthY"]
     domegaz_dt = data["VorticityZ"] / data["VorticityGrowthZ"]
-    return np.sqrt(domegax_dt**2 + domegay_dt**2 + domegaz_dt)
+    return np.sqrt(domegax_dt**2 + domegay_dt**2 + domegaz_dt**2)
 add_field("VorticityGrowthTimescale", function=_VorticityGrowthTimescale,
           validators=[ValidateSpatial(1, 
                       ["x-velocity", "y-velocity", "z-velocity"])],

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/castro/data_structures.py
--- a/yt/frontends/castro/data_structures.py
+++ b/yt/frontends/castro/data_structures.py
@@ -608,7 +608,7 @@
         self.parameters["TopGridRank"] = len(self.parameters["TopGridDimensions"])
         self.dimensionality = self.parameters["TopGridRank"]
         self.periodicity = ensure_tuple(self.fparameters['castro.lo_bc'] == 0)
-        self.domain_dimensions = self.parameters["TopGridDimensions"]
+        self.domain_dimensions = np.array(self.parameters["TopGridDimensions"])
         self.refine_by = self.parameters.get("RefineBy", 2)
 
         if (self.parameters.has_key("ComovingCoordinates") and

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/enzo/data_structures.py
--- a/yt/frontends/enzo/data_structures.py
+++ b/yt/frontends/enzo/data_structures.py
@@ -706,6 +706,9 @@
     _hierarchy_class = EnzoHierarchy
     _fieldinfo_fallback = EnzoFieldInfo
     _fieldinfo_known = KnownEnzoFields
+    _particle_mass_name = "ParticleMass"
+    _particle_coordinates_name = "Coordinates"
+
     def __init__(self, filename, data_style=None,
                  file_style = None,
                  parameter_override = None,

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/enzo/io.py
--- a/yt/frontends/enzo/io.py
+++ b/yt/frontends/enzo/io.py
@@ -36,7 +36,9 @@
 import numpy as np
 from yt.funcs import *
 
-_convert_mass = ("particle_mass",)
+_convert_mass = ("particle_mass","mass")
+
+_particle_position_names = {}
 
 class IOHandlerPackedHDF5(BaseIOHandler):
 
@@ -56,7 +58,8 @@
         ptypes = list(set([ftype for ftype, fname in fields]))
         fields = list(set(fields))
         if len(ptypes) > 1: raise NotImplementedError
-        pfields = [(ptypes[0], "particle_position_%s" % ax) for ax in 'xyz']
+        pn = _particle_position_names.get(ptypes[0], r"particle_position_%s")
+        pfields = [(ptypes[0], pn % ax) for ax in 'xyz']
         size = 0
         for chunk in chunks:
             data = self._read_chunk_data(chunk, pfields, 'active', 
@@ -83,7 +86,7 @@
                 for field in set(fields):
                     ftype, fname = field
                     gdata = data[g.id].pop(fname)[mask]
-                    if fname == "particle_mass":
+                    if fname in _convert_mass:
                         gdata *= g.dds.prod()
                     rv[field][ind:ind+gdata.size] = gdata
                 ind += gdata.size
@@ -134,7 +137,7 @@
                 for field in set(fields):
                     ftype, fname = field
                     gdata = data[g.id].pop(fname)[mask]
-                    if fname == "particle_mass":
+                    if fname in _convert_mass:
                         gdata *= g.dds.prod()
                     rv[field][ind:ind+gdata.size] = gdata
                 ind += gdata.size

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/flash/data_structures.py
--- a/yt/frontends/flash/data_structures.py
+++ b/yt/frontends/flash/data_structures.py
@@ -465,7 +465,7 @@
         try: 
             self.parameters["usecosmology"]
             self.cosmological_simulation = 1
-            self.current_redshift = self.parameters['redshift']
+            self.current_redshift = 1.0/self.parameters['scalefactor'] - 1.0
             self.omega_lambda = self.parameters['cosmologicalconstant']
             self.omega_matter = self.parameters['omegamatter']
             self.hubble_constant = self.parameters['hubbleconstant']

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/gdf/data_structures.py
--- a/yt/frontends/gdf/data_structures.py
+++ b/yt/frontends/gdf/data_structures.py
@@ -76,8 +76,9 @@
             LE, RE = self.hierarchy.grid_left_edge[id,:], \
                      self.hierarchy.grid_right_edge[id,:]
             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
+        if self.pf.data_software != "piernik":
+            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
 
     @property
@@ -235,6 +236,11 @@
 
     def _parse_parameter_file(self):
         self._handle = h5py.File(self.parameter_filename, "r")
+        if 'data_software' in self._handle['gridded_data_format'].attrs:
+            self.data_software = \
+                self._handle['gridded_data_format'].attrs['data_software']
+        else:
+            self.data_software = "unknown"
         sp = self._handle["/simulation_parameters"].attrs
         self.domain_left_edge = sp["domain_left_edge"][:]
         self.domain_right_edge = sp["domain_right_edge"][:]

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/ramses/data_structures.py
--- a/yt/frontends/ramses/data_structures.py
+++ b/yt/frontends/ramses/data_structures.py
@@ -357,6 +357,8 @@
     _hierarchy_class = RAMSESGeometryHandler
     _fieldinfo_fallback = RAMSESFieldInfo
     _fieldinfo_known = KnownRAMSESFields
+    _particle_mass_name = "ParticleMass"
+    _particle_coordinates_name = "Coordinates"
     
     def __init__(self, filename, data_style='ramses',
                  fields = None,

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/setup.py
--- a/yt/frontends/setup.py
+++ b/yt/frontends/setup.py
@@ -24,4 +24,9 @@
     config.add_subpackage("sph")
     config.add_subpackage("stream")
     config.add_subpackage("tiger")
+    config.add_subpackage("flash/tests")
+    config.add_subpackage("enzo/tests")
+    config.add_subpackage("orion/tests")
+    config.add_subpackage("stream/tests")
+    config.add_subpackage("chombo/tests")
     return config

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/sph/data_structures.py
--- a/yt/frontends/sph/data_structures.py
+++ b/yt/frontends/sph/data_structures.py
@@ -129,6 +129,8 @@
     _file_class = GadgetBinaryFile
     _fieldinfo_fallback = GadgetFieldInfo
     _fieldinfo_known = KnownGadgetFields
+    _particle_mass_name = "Mass"
+    _particle_coordinates_name = "Coordinates"
     _header_spec = (('Npart', 6, 'i'),
                     ('Massarr', 6, 'd'),
                     ('Time', 1, 'd'),
@@ -258,6 +260,8 @@
     _file_class = ParticleFile
     _fieldinfo_fallback = OWLSFieldInfo # For now we have separate from Gadget
     _fieldinfo_known = KnownOWLSFields
+    _particle_mass_name = "Mass"
+    _particle_coordinates_name = "Coordinates"
     _header_spec = None # Override so that there's no confusion
 
     def __init__(self, filename, data_style="OWLS"):
@@ -337,6 +341,8 @@
     _file_class = TipsyFile
     _fieldinfo_fallback = TipsyFieldInfo
     _fieldinfo_known = KnownTipsyFields
+    _particle_mass_name = "Mass"
+    _particle_coordinates_name = "Coordinates"
     _header_spec = (('time',    'd'),
                     ('nbodies', 'i'),
                     ('ndim',    'i'),

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/frontends/sph/fields.py
--- a/yt/frontends/sph/fields.py
+++ b/yt/frontends/sph/fields.py
@@ -72,7 +72,9 @@
     def _AllFields(field, data):
         v = []
         for ptype in data.pf.particle_types:
-            if ptype == "all": continue
+            if ptype == "all" or \
+                ptype in data.pf.known_filters:
+                  continue
             v.append(data[ptype, fname].copy())
         rv = np.concatenate(v, axis=0)
         return rv
@@ -82,7 +84,9 @@
     def _AllFields(field, data):
         v = []
         for ptype in data.pf.particle_types:
-            if ptype == "all": continue
+            if ptype == "all" or \
+                ptype in data.pf.known_filters:
+                  continue
             v.append(data[ptype, fname][:,axi])
         rv = np.concatenate(v, axis=0)
         return rv

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/geometry/geometry_handler.py
--- a/yt/geometry/geometry_handler.py
+++ b/yt/geometry/geometry_handler.py
@@ -39,6 +39,8 @@
     data_object_registry
 from yt.data_objects.field_info_container import \
     NullFunc
+from yt.data_objects.particle_fields import \
+    particle_deposition_functions
 from yt.utilities.io_handler import io_registry
 from yt.utilities.logger import ytLogger as mylog
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
@@ -162,8 +164,43 @@
                 self.parameter_file.field_info[field] = known_fields[field]
 
     def _setup_derived_fields(self):
+        self.derived_field_list = []
+        self.filtered_particle_types = []
+        fc, fac = self._derived_fields_to_check()
+        self._derived_fields_add(fc, fac)
+
+    def _setup_filtered_type(self, filter):
+        if not filter.available(self.derived_field_list):
+            return False
         fi = self.parameter_file.field_info
-        self.derived_field_list = []
+        fd = self.parameter_file.field_dependencies
+        available = False
+        for fn in self.derived_field_list:
+            if fn[0] == filter.filtered_type:
+                # Now we can add this
+                available = True
+                self.derived_field_list.append(
+                    (filter.name, fn[1]))
+                fi[filter.name, fn[1]] = filter.wrap_func(fn, fi[fn])
+                # Now we append the dependencies
+                fd[filter.name, fn[1]] = fd[fn]
+        if available:
+            self.parameter_file.particle_types += (filter.name,)
+            self.filtered_particle_types.append(filter.name)
+            self._setup_particle_fields(filter.name, True)
+        return available
+
+    def _setup_particle_fields(self, ptype, filtered = False):
+        pf = self.parameter_file
+        pmass = self.parameter_file._particle_mass_name
+        pcoord = self.parameter_file._particle_coordinates_name
+        if pmass is None or pcoord is None: return
+        df = particle_deposition_functions(ptype,
+            pcoord, pmass, self.parameter_file.field_info)
+        self._derived_fields_add(df)
+
+    def _derived_fields_to_check(self):
+        fi = self.parameter_file.field_info
         # First we construct our list of fields to check
         fields_to_check = []
         fields_to_allcheck = []
@@ -187,6 +224,15 @@
                 new_fields.append(new_fi.name)
             fields_to_check += new_fields
             fields_to_allcheck.append(field)
+        return fields_to_check, fields_to_allcheck
+
+    def _derived_fields_add(self, fields_to_check = None,
+                            fields_to_allcheck = None):
+        if fields_to_check is None:
+            fields_to_check = []
+        if fields_to_allcheck is None:
+            fields_to_allcheck = []
+        fi = self.parameter_file.field_info
         for field in fields_to_check:
             try:
                 fd = fi[field].get_dependencies(pf = self.parameter_file)

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/startup_tasks.py
--- a/yt/startup_tasks.py
+++ b/yt/startup_tasks.py
@@ -98,7 +98,17 @@
         if param == "loglevel": # special case
             mylog.setLevel(int(val))
 
-parser = argparse.ArgumentParser(description = 'yt command line arguments')
+class YTParser(argparse.ArgumentParser):
+    def error(self, message):
+        """error(message: string)
+
+        Prints a help message that is more detailed than the argparse default
+        and then exits.
+        """
+        self.print_help(sys.stderr)
+        self.exit(2, '%s: error: %s\n' % (self.prog, message))
+
+parser = YTParser(description = 'yt command line arguments')
 parser.add_argument("--config", action=SetConfigOption,
     help = "Set configuration option, in the form param=value")
 parser.add_argument("--paste", action=SetExceptionHandling,

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/utilities/amr_kdtree/amr_kdtools.py
--- a/yt/utilities/amr_kdtree/amr_kdtools.py
+++ b/yt/utilities/amr_kdtree/amr_kdtools.py
@@ -1,5 +1,5 @@
 """
-AMR kD-Tree Tools 
+AMR kD-Tree Tools
 
 Authors: Samuel Skillman <samskillman at gmail.com>
 Affiliation: University of Colorado at Boulder
@@ -25,435 +25,10 @@
 """
 import numpy as np
 from yt.funcs import *
-from yt.utilities.lib import kdtree_get_choices
-
-def _lchild_id(node_id): return (node_id<<1)
-def _rchild_id(node_id): return (node_id<<1) + 1
-def _parent_id(node_id): return (node_id-1) >> 1
-
-class Node(object):
-    def __init__(self, parent, left, right,
-            left_edge, right_edge, grid_id, node_id):
-        self.left = left
-        self.right = right
-        self.left_edge = left_edge
-        self.right_edge = right_edge
-        self.grid = grid_id
-        self.parent = parent
-        self.id = node_id
-        self.data = None
-        self.split = None
-
-class Split(object):
-    def __init__(self, dim, pos):
-        self.dim = dim
-        self.pos = pos
-
-def should_i_build(node, rank, size):
-    if (node.id < size) or (node.id >= 2*size):
-        return True
-    elif node.id - size == rank:
-        return True
-    else:
-        return False
-
-
-def add_grid(node, gle, gre, gid, rank, size):
-    if not should_i_build(node, rank, size):
-        return
-
-    if kd_is_leaf(node):
-        insert_grid(node, gle, gre, gid, rank, size)
-    else:
-        less_id = gle[node.split.dim] < node.split.pos
-        if less_id:
-            add_grid(node.left, gle, gre,
-                     gid, rank, size)
-
-        greater_id = gre[node.split.dim] > node.split.pos
-        if greater_id:
-            add_grid(node.right, gle, gre,
-                     gid, rank, size)
-
-
-def insert_grid(node, gle, gre, grid_id, rank, size):
-    if not should_i_build(node, rank, size):
-        return
-
-    # If we should continue to split based on parallelism, do so!
-    if should_i_split(node, rank, size):
-        geo_split(node, gle, gre, grid_id, rank, size)
-        return
-
-    if np.all(gle <= node.left_edge) and \
-            np.all(gre >= node.right_edge):
-        node.grid = grid_id
-        assert(node.grid is not None)
-        return
-
-    # Split the grid
-    check = split_grid(node, gle, gre, grid_id, rank, size)
-    # If check is -1, then we have found a place where there are no choices.
-    # Exit out and set the node to None.
-    if check == -1:
-        node.grid = None
-    return
-
-
-def add_grids(node, gles, gres, gids, rank, size):
-    if not should_i_build(node, rank, size):
-        return
-
-    if kd_is_leaf(node):
-        insert_grids(node, gles, gres, gids, rank, size)
-    else:
-        less_ids = gles[:,node.split.dim] < node.split.pos
-        if len(less_ids) > 0:
-            add_grids(node.left, gles[less_ids], gres[less_ids],
-                      gids[less_ids], rank, size)
-
-        greater_ids = gres[:,node.split.dim] > node.split.pos
-        if len(greater_ids) > 0:
-            add_grids(node.right, gles[greater_ids], gres[greater_ids],
-                      gids[greater_ids], rank, size)
-
-
-def should_i_split(node, rank, size):
-    return node.id < size
-
-
-def geo_split_grid(node, gle, gre, grid_id, rank, size):
-    big_dim = np.argmax(gre-gle)
-    new_pos = (gre[big_dim] + gle[big_dim])/2.
-    old_gre = gre.copy()
-    new_gle = gle.copy()
-    new_gle[big_dim] = new_pos
-    gre[big_dim] = new_pos
-
-    split = Split(big_dim, new_pos)
-
-    # Create a Split
-    divide(node, split)
-
-    # Populate Left Node
-    #print 'Inserting left node', node.left_edge, node.right_edge
-    insert_grid(node.left, gle, gre,
-                grid_id, rank, size)
-
-    # Populate Right Node
-    #print 'Inserting right node', node.left_edge, node.right_edge
-    insert_grid(node.right, new_gle, old_gre,
-                grid_id, rank, size)
-    return
-
-
-def geo_split(node, gles, gres, grid_ids, rank, size):
-    big_dim = np.argmax(gres[0]-gles[0])
-    new_pos = (gres[0][big_dim] + gles[0][big_dim])/2.
-    old_gre = gres[0].copy()
-    new_gle = gles[0].copy()
-    new_gle[big_dim] = new_pos
-    gres[0][big_dim] = new_pos
-    gles = np.append(gles, np.array([new_gle]), axis=0)
-    gres = np.append(gres, np.array([old_gre]), axis=0)
-    grid_ids = np.append(grid_ids, grid_ids, axis=0)
-
-    split = Split(big_dim, new_pos)
-
-    # Create a Split
-    divide(node, split)
-
-    # Populate Left Node
-    #print 'Inserting left node', node.left_edge, node.right_edge
-    insert_grids(node.left, gles[:1], gres[:1],
-            grid_ids[:1], rank, size)
-
-    # Populate Right Node
-    #print 'Inserting right node', node.left_edge, node.right_edge
-    insert_grids(node.right, gles[1:], gres[1:],
-            grid_ids[1:], rank, size)
-    return
-
-def insert_grids(node, gles, gres, grid_ids, rank, size):
-    if not should_i_build(node, rank, size) or grid_ids.size == 0:
-        return
-
-    if len(grid_ids) == 1:
-        # If we should continue to split based on parallelism, do so!
-        if should_i_split(node, rank, size):
-            geo_split(node, gles, gres, grid_ids, rank, size)
-            return
-
-        if np.all(gles[0] <= node.left_edge) and \
-                np.all(gres[0] >= node.right_edge):
-            node.grid = grid_ids[0]
-            assert(node.grid is not None)
-            return
-
-    # Split the grids
-    check = split_grids(node, gles, gres, grid_ids, rank, size)
-    # If check is -1, then we have found a place where there are no choices.
-    # Exit out and set the node to None.
-    if check == -1:
-        node.grid = None
-    return
-
-def split_grid(node, gle, gre, grid_id, rank, size):
-    # Find a Split
-    data = np.array([(gle[:], gre[:])],  copy=False)
-    best_dim, split_pos, less_id, greater_id = \
-        kdtree_get_choices(data, node.left_edge, node.right_edge)
-
-    # If best_dim is -1, then we have found a place where there are no choices.
-    # Exit out and set the node to None.
-    if best_dim == -1:
-        return -1
-
-    split = Split(best_dim, split_pos)
-
-    del data, best_dim, split_pos
-
-    # Create a Split
-    divide(node, split)
-
-    # Populate Left Node
-    #print 'Inserting left node', node.left_edge, node.right_edge
-    if less_id:
-        insert_grid(node.left, gle, gre,
-                     grid_id, rank, size)
-
-    # Populate Right Node
-    #print 'Inserting right node', node.left_edge, node.right_edge
-    if greater_id:
-        insert_grid(node.right, gle, gre,
-                     grid_id, rank, size)
-
-    return
-
-
-def split_grids(node, gles, gres, grid_ids, rank, size):
-    # Find a Split
-    data = np.array([(gles[i,:], gres[i,:]) for i in
-        xrange(grid_ids.shape[0])], copy=False)
-    best_dim, split_pos, less_ids, greater_ids = \
-        kdtree_get_choices(data, node.left_edge, node.right_edge)
-
-    # If best_dim is -1, then we have found a place where there are no choices.
-    # Exit out and set the node to None.
-    if best_dim == -1:
-        return -1
-
-    split = Split(best_dim, split_pos)
-
-    del data, best_dim, split_pos
-
-    # Create a Split
-    divide(node, split)
-
-    # Populate Left Node
-    #print 'Inserting left node', node.left_edge, node.right_edge
-    insert_grids(node.left, gles[less_ids], gres[less_ids],
-                 grid_ids[less_ids], rank, size)
-
-    # Populate Right Node
-    #print 'Inserting right node', node.left_edge, node.right_edge
-    insert_grids(node.right, gles[greater_ids], gres[greater_ids],
-                 grid_ids[greater_ids], rank, size)
-
-    return
-
-def new_right(Node, split):
-    new_right = Node.right_edge.copy()
-    new_right[split.dim] = split.pos
-    return new_right
-
-def new_left(Node, split):
-    new_left = Node.left_edge.copy()
-    new_left[split.dim] = split.pos
-    return new_left
-
-def divide(node, split):
-    # Create a Split
-    node.split = split
-    node.left = Node(node, None, None,
-            node.left_edge, new_right(node, split), node.grid,
-                     _lchild_id(node.id))
-    node.right = Node(node, None, None,
-            new_left(node, split), node.right_edge, node.grid,
-                      _rchild_id(node.id))
-    return
-
-def kd_sum_volume(node):
-    if (node.left is None) and (node.right is None):
-        if node.grid is None:
-            return 0.0
-        return np.prod(node.right_edge - node.left_edge)
-    else:
-        return kd_sum_volume(node.left) + kd_sum_volume(node.right)
-
-def kd_sum_cells(node):
-    if (node.left is None) and (node.right is None):
-        if node.grid is None:
-            return 0.0
-        return np.prod(node.right_edge - node.left_edge)
-    else:
-        return kd_sum_volume(node.left) + kd_sum_volume(node.right)
-
-
-def kd_node_check(node):
-    assert (node.left is None) == (node.right is None)
-    if (node.left is None) and (node.right is None):
-        if node.grid is not None:
-            return np.prod(node.right_edge - node.left_edge)
-        else: return 0.0
-    else:
-        return kd_node_check(node.left)+kd_node_check(node.right)
-
-def kd_is_leaf(node):
-    no_l_child = node.left is None
-    no_r_child = node.right is None
-    assert no_l_child == no_r_child
-    return no_l_child
-
-def step_depth(current, previous):
-    '''
-    Takes a single step in the depth-first traversal
-    '''
-    if kd_is_leaf(current): # At a leaf, move back up
-        previous = current
-        current = current.parent
-
-    elif current.parent is previous: # Moving down, go left first
-        previous = current
-        if current.left is not None:
-            current = current.left
-        elif current.right is not None:
-            current = current.right
-        else:
-            current = current.parent
-
-    elif current.left is previous: # Moving up from left, go right 
-        previous = current
-        if current.right is not None:
-            current = current.right
-        else:
-            current = current.parent
-
-    elif current.right is previous: # Moving up from right child, move up
-        previous = current
-        current = current.parent
-
-    return current, previous
-
-def depth_traverse(tree, max_node=None):
-    '''
-    Yields a depth-first traversal of the kd tree always going to
-    the left child before the right.
-    '''
-    current = tree.trunk
-    previous = None
-    if max_node is None:
-        max_node = np.inf
-    while current is not None:
-        yield current
-        current, previous = step_depth(current, previous)
-        if current is None: break
-        if current.id >= max_node:
-            current = current.parent
-            previous = current.right
-
-def depth_first_touch(tree, max_node=None):
-    '''
-    Yields a depth-first traversal of the kd tree always going to
-    the left child before the right.
-    '''
-    current = tree.trunk
-    previous = None
-    if max_node is None:
-        max_node = np.inf
-    while current is not None:
-        if previous is None or previous.parent != current:
-            yield current
-        current, previous = step_depth(current, previous)
-        if current is None: break
-        if current.id >= max_node:
-            current = current.parent
-            previous = current.right
-
-def breadth_traverse(tree):
-    '''
-    Yields a breadth-first traversal of the kd tree always going to
-    the left child before the right.
-    '''
-    current = tree.trunk
-    previous = None
-    while current is not None:
-        yield current
-        current, previous = step_depth(current, previous)
-
-
-def viewpoint_traverse(tree, viewpoint):
-    '''
-    Yields a viewpoint dependent traversal of the kd-tree.  Starts
-    with nodes furthest away from viewpoint.
-    '''
-
-    current = tree.trunk
-    previous = None
-    while current is not None:
-        yield current
-        current, previous = step_viewpoint(current, previous, viewpoint)
-
-def step_viewpoint(current, previous, viewpoint):
-    '''
-    Takes a single step in the viewpoint based traversal.  Always
-    goes to the node furthest away from viewpoint first.
-    '''
-    if kd_is_leaf(current): # At a leaf, move back up
-        previous = current
-        current = current.parent
-    elif current.split.dim is None: # This is a dead node
-        previous = current
-        current = current.parent
-
-    elif current.parent is previous: # Moving down
-        previous = current
-        if viewpoint[current.split.dim] <= current.split.pos:
-            if current.right is not None:
-                current = current.right
-            else:
-                previous = current.right
-        else:
-            if current.left is not None:
-                current = current.left
-            else:
-                previous = current.left
-
-    elif current.right is previous: # Moving up from right 
-        previous = current
-        if viewpoint[current.split.dim] <= current.split.pos:
-            if current.left is not None:
-                current = current.left
-            else:
-                current = current.parent
-        else:
-            current = current.parent
-
-    elif current.left is previous: # Moving up from left child
-        previous = current
-        if viewpoint[current.split.dim] > current.split.pos:
-            if current.right is not None:
-                current = current.right
-            else:
-                current = current.parent
-        else:
-            current = current.parent
-
-    return current, previous
 
 
 def receive_and_reduce(comm, incoming_rank, image, add_to_front):
-    mylog.debug( 'Receiving image from %04i' % incoming_rank)
+    mylog.debug('Receiving image from %04i' % incoming_rank)
     #mylog.debug( '%04i receiving image from %04i'%(self.comm.rank,back.owner))
     arr2 = comm.recv_array(incoming_rank, incoming_rank).reshape(
         (image.shape[0], image.shape[1], image.shape[2]))
@@ -470,36 +45,24 @@
         np.add(image, front, image)
         return image
 
-    ta = 1.0 - front[:,:,3]
+    ta = 1.0 - front[:, :, 3]
     np.maximum(ta, 0.0, ta)
     # This now does the following calculation, but in a memory
     # conservative fashion
     # image[:,:,i  ] = front[:,:,i] + ta*back[:,:,i]
     image = back.copy()
     for i in range(4):
-        np.multiply(image[:,:,i], ta, image[:,:,i])
+        np.multiply(image[:, :, i], ta, image[:, :, i])
     np.add(image, front, image)
     return image
 
+
 def send_to_parent(comm, outgoing_rank, image):
-    mylog.debug( 'Sending image to %04i' % outgoing_rank)
+    mylog.debug('Sending image to %04i' % outgoing_rank)
     comm.send_array(image, outgoing_rank, tag=comm.rank)
 
+
 def scatter_image(comm, root, image):
-    mylog.debug( 'Scattering from %04i' % root)
+    mylog.debug('Scattering from %04i' % root)
     image = comm.mpi_bcast(image, root=root)
     return image
-
-def find_node(node, pos):
-    """
-    Find the AMRKDTree node enclosing a position
-    """
-    assert(np.all(node.left_edge <= pos))
-    assert(np.all(node.right_edge > pos))
-    while not kd_is_leaf(node):
-        if pos[node.split.dim] < node.split.pos:
-            node = node.left
-        else:
-            node = node.right
-    return node
-

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -26,10 +26,13 @@
 from yt.funcs import *
 import numpy as np
 import h5py
-from amr_kdtools import Node, Split, kd_is_leaf, kd_sum_volume, kd_node_check, \
-        depth_traverse, viewpoint_traverse, add_grids, \
-        receive_and_reduce, send_to_parent, scatter_image, find_node, \
-        depth_first_touch
+from amr_kdtools import \
+        receive_and_reduce, send_to_parent, scatter_image
+
+from yt.utilities.lib.amr_kdtools import Node, add_pygrids, find_node, \
+        kd_is_leaf, depth_traverse, depth_first_touch, viewpoint_traverse, \
+        kd_traverse, \
+        get_left_edge, get_right_edge, kd_sum_volume, kd_node_check
 from yt.utilities.parallel_tools.parallel_analysis_interface \
     import ParallelAnalysisInterface 
 from yt.utilities.lib.grid_traversal import PartitionedGrid
@@ -49,82 +52,61 @@
                   [ 1,  0, -1], [ 1,  0,  0], [ 1,  0,  1],
                   [ 1,  1, -1], [ 1,  1,  0], [ 1,  1,  1] ])
 
+class Tree(object):
+    def __init__(self, pf, comm_rank=0, comm_size=1, left=None, right=None, 
+        min_level=None, max_level=None, source=None):
 
-def make_vcd(data, log=False):
-    new_field = np.zeros(np.array(data.shape) + 1, dtype='float64')
-    of = data
-    new_field[:-1, :-1, :-1] += of
-    new_field[:-1, :-1, 1:] += of
-    new_field[:-1, 1:, :-1] += of
-    new_field[:-1, 1:, 1:] += of
-    new_field[1:, :-1, :-1] += of
-    new_field[1:, :-1, 1:] += of
-    new_field[1:, 1:, :-1] += of
-    new_field[1:, 1:, 1:] += of
-    np.multiply(new_field, 0.125, new_field)
-    if log:
-        new_field = np.log10(new_field)
+        self.pf = pf
+        self._id_offset = self.pf.h.grids[0]._id_offset
 
-    new_field[:, :, -1] = 2.0*new_field[:, :, -2] - new_field[:, :, -3]
-    new_field[:, :, 0] = 2.0*new_field[:, :, 1] - new_field[:, :, 2]
-    new_field[:, -1, :] = 2.0*new_field[:, -2, :] - new_field[:, -3, :]
-    new_field[:, 0, :] = 2.0*new_field[:, 1, :] - new_field[:, 2, :]
-    new_field[-1, :, :] = 2.0*new_field[-2, :, :] - new_field[-3, :, :]
-    new_field[0, :, :] = 2.0*new_field[1, :, :] - new_field[2, :, :]
+        if source is None:
+            source = pf.h.all_data()
+        self.source = source
+        if left is None:
+            left = np.array([-np.inf]*3)
+        if right is None:
+            right = np.array([np.inf]*3)
 
-    if log: 
-        np.power(10.0, new_field, new_field)
-    return new_field
-
-class Tree(object):
-    def __init__(self, pf, comm_rank=0, comm_size=1,
-            min_level=None, max_level=None, data_source=None):
-        
-        self.pf = pf
-        if data_source is None:
-            data_source = pf.h.all_data()
-        self.data_source = data_source
-        self._id_offset = self.pf.h.grids[0]._id_offset
         if min_level is None: min_level = 0
         if max_level is None: max_level = pf.h.max_level
         self.min_level = min_level
         self.max_level = max_level
         self.comm_rank = comm_rank
         self.comm_size = comm_size
-        left_edge = np.array([-np.inf]*3)
-        right_edge = np.array([np.inf]*3)
-        self.trunk = Node(None, None, None,
-                left_edge, right_edge, None, 1)
+        self.trunk = Node(None, None, None, left, right, -1, 1)
         self.build()
 
     def add_grids(self, grids):
         gles = np.array([g.LeftEdge for g in grids])
         gres = np.array([g.RightEdge for g in grids])
         gids = np.array([g.id for g in grids])
-        add_grids(self.trunk, gles, gres, gids, self.comm_rank, self.comm_size)
+        add_pygrids(self.trunk, gids.size, gles, gres, gids,
+                    self.comm_rank, self.comm_size)
         del gles, gres, gids, grids
 
     def build(self):
         lvl_range = range(self.min_level, self.max_level+1)
         for lvl in lvl_range:
-            #grids = self.data_source.select_grids(lvl)
-            grids = np.array([b for b, mask in self.data_source.blocks if b.Level == lvl])
-            if len(grids) == 0: continue 
+            #grids = self.source.select_grids(lvl)
+            grids = np.array([b for b, mask in self.source.blocks if b.Level == lvl])
+            if len(grids) == 0: continue
             self.add_grids(grids)
 
     def check_tree(self):
-        for node in depth_traverse(self):
-            if node.grid is None:
+        for node in depth_traverse(self.trunk):
+            if node.grid == -1:
                 continue
             grid = self.pf.h.grids[node.grid - self._id_offset]
             dds = grid.dds
             gle = grid.LeftEdge
             gre = grid.RightEdge
-            li = np.rint((node.left_edge-gle)/dds).astype('int32')
-            ri = np.rint((node.right_edge-gle)/dds).astype('int32')
+            nle = get_left_edge(node)
+            nre = get_right_edge(node)
+            li = np.rint((nle-gle)/dds).astype('int32')
+            ri = np.rint((nre-gle)/dds).astype('int32')
             dims = (ri - li).astype('int32')
-            assert(np.all(grid.LeftEdge <= node.left_edge))
-            assert(np.all(grid.RightEdge >= node.right_edge))
+            assert(np.all(grid.LeftEdge <= nle))
+            assert(np.all(grid.RightEdge >= nre))
             assert(np.all(dims > 0))
             # print grid, dims, li, ri
 
@@ -133,27 +115,33 @@
         mylog.debug('AMRKDTree volume = %e' % vol)
         kd_node_check(self.trunk)
 
-    def sum_cells(self):
+    def sum_cells(self, all_cells=False):
         cells = 0
-        for node in depth_traverse(self):
-            if node.grid is None:
+        for node in depth_traverse(self.trunk):
+            if node.grid == -1:
+                continue
+            if not all_cells and not kd_is_leaf(node):
                 continue
             grid = self.pf.h.grids[node.grid - self._id_offset]
             dds = grid.dds
             gle = grid.LeftEdge
-            gre = grid.RightEdge
-            li = np.rint((node.left_edge-gle)/dds).astype('int32')
-            ri = np.rint((node.right_edge-gle)/dds).astype('int32')
+            nle = get_left_edge(node)
+            nre = get_right_edge(node)
+            li = np.rint((nle-gle)/dds).astype('int32')
+            ri = np.rint((nre-gle)/dds).astype('int32')
             dims = (ri - li).astype('int32')
             cells += np.prod(dims)
-
         return cells
 
+
 class AMRKDTree(ParallelAnalysisInterface):
+
     fields = None
     log_fields = None
     no_ghost = True
-    def __init__(self, pf, min_level=None, max_level=None, data_source=None):
+
+    def __init__(self, pf, min_level=None, max_level=None,
+                 source=None):
 
         ParallelAnalysisInterface.__init__(self)
 
@@ -163,21 +151,21 @@
         self.bricks = []
         self.brick_dimensions = []
         self.sdx = pf.h.get_smallest_dx()
+
         self._initialized = False
-        try: 
+        try:
             self._id_offset = pf.h.grids[0]._id_offset
-        except:
+        except AttributeError:
             self._id_offset = 0
 
-        #self.add_mask_field()
-        if data_source is None:
-            data_source = pf.h.all_data()
-        self.data_source = data_source
-    
+        if source is None:
+            source = self.pf.h.all_data()
+        self.source = source
+
         mylog.debug('Building AMRKDTree')
         self.tree = Tree(pf, self.comm.rank, self.comm.size,
-                         min_level=min_level,
-                         max_level=max_level, data_source=data_source)
+                         min_level=min_level, max_level=max_level,
+                         source=source)
 
     def set_fields(self, fields, log_fields, no_ghost):
         self.fields = fields
@@ -190,28 +178,23 @@
             bricks.append(b)
         self.bricks = np.array(bricks)
         self.brick_dimensions = np.array(self.brick_dimensions)
-    
+        self._initialized = True
+
     def initialize_source(self, fields, log_fields, no_ghost):
         if fields == self.fields and log_fields == self.log_fields and \
-            no_ghost == self.no_ghost:
+                no_ghost == self.no_ghost:
             return
         self.set_fields(fields, log_fields, no_ghost)
 
     def traverse(self, viewpoint=None):
-        if viewpoint is None:
-            for node in depth_traverse(self.tree):
-                if kd_is_leaf(node) and node.grid is not None:
-                    yield self.get_brick_data(node)
-        else:
-            for node in viewpoint_traverse(self.tree, viewpoint):
-                if kd_is_leaf(node) and node.grid is not None:
-                    yield self.get_brick_data(node)
+        for node in kd_traverse(self.tree.trunk, viewpoint=viewpoint):
+            yield self.get_brick_data(node)
 
     def get_node(self, nodeid):
         path = np.binary_repr(nodeid)
         depth = 1
         temp = self.tree.trunk
-        for depth in range(1,len(path)):
+        for depth in range(1, len(path)):
             if path[depth] == '0':
                 temp = temp.left
             else:
@@ -226,13 +209,13 @@
         owners = {}
         for bottom_id in range(self.comm.size, 2*self.comm.size):
             temp = self.get_node(bottom_id)
-            owners[temp.id] = temp.id - self.comm.size
+            owners[temp.node_id] = temp.node_id - self.comm.size
             while temp is not None:
                 if temp.parent is None: break
                 if temp == temp.parent.right:
                     break
                 temp = temp.parent
-                owners[temp.id] = owners[temp.left.id]
+                owners[temp.node_id] = owners[temp.left.node_id]
         return owners
 
     def reduce_tree_images(self, image, viewpoint):
@@ -242,44 +225,39 @@
         owners = self.get_reduce_owners()
         node = self.get_node(nprocs + myrank)
 
-        while True:
-            if owners[node.parent.id] == myrank:
-                split = node.parent.split
-                left_in_front = viewpoint[split.dim] < node.parent.split.pos
-                #add_to_front = (left_in_front == (node == node.parent.right))
-                add_to_front = not left_in_front
-                image = receive_and_reduce(self.comm, owners[node.parent.right.id],
-                                  image, add_to_front)
-                if node.parent.id == 1: break
-                else: node = node.parent
-            else:
-                send_to_parent(self.comm, owners[node.parent.id], image)
-                break
-        image = scatter_image(self.comm, owners[1], image)
-        return image
+        while owners[node.parent.node_id] == myrank:
+            split_dim = node.parent.get_split_dim()
+            split_pos = node.parent.get_split_pos()
+            add_to_front = viewpoint[split_dim] >= split_pos
+            image = receive_and_reduce(self.comm,
+                                       owners[node.parent.right.node_id],
+                                       image, add_to_front)
+            if node.parent.node_id == 1: break
+            else: node = node.parent
+        else:
+            send_to_parent(self.comm, owners[node.parent.node_id], image)
+
+        return scatter_image(self.comm, owners[1], image)
 
     def get_brick_data(self, node):
         if node.data is not None: return node.data
         grid = self.pf.h.grids[node.grid - self._id_offset]
         dds = grid.dds
         gle = grid.LeftEdge
-        gre = grid.RightEdge
-        li = np.rint((node.left_edge-gle)/dds).astype('int32')
-        ri = np.rint((node.right_edge-gle)/dds).astype('int32')
+        nle = get_left_edge(node)
+        nre = get_right_edge(node)
+        li = np.rint((nle-gle)/dds).astype('int32')
+        ri = np.rint((nre-gle)/dds).astype('int32')
         dims = (ri - li).astype('int32')
-        assert(np.all(grid.LeftEdge <= node.left_edge))
-        assert(np.all(grid.RightEdge >= node.right_edge))
+        assert(np.all(grid.LeftEdge <= nle))
+        assert(np.all(grid.RightEdge >= nre))
 
         if grid in self.current_saved_grids:
             dds = self.current_vcds[self.current_saved_grids.index(grid)]
         else:
             dds = []
-            mask = make_vcd(grid.child_mask)
-            mask = np.clip(mask, 0.0, 1.0)
-            mask[mask<0.5] = np.inf
-            for i,field in enumerate(self.fields):
-                vcd = make_vcd(grid[field], log=self.log_fields[i])
-                vcd *= mask
+            for i, field in enumerate(self.fields):
+                vcd = grid.get_vertex_centered_data(field, smoothed=True,no_ghost=self.no_ghost).astype('float64')
                 if self.log_fields[i]: vcd = np.log10(vcd)
                 dds.append(vcd)
                 self.current_saved_grids.append(grid)
@@ -290,11 +268,11 @@
                   li[2]:ri[2]+1].copy() for d in dds]
 
         brick = PartitionedGrid(grid.id, data,
-                                node.left_edge.copy(),
-                                node.right_edge.copy(),
+                                nle.copy(),
+                                nre.copy(),
                                 dims.astype('int64'))
         node.data = brick
-        if not self._initialized: 
+        if not self._initialized:
             self.brick_dimensions.append(dims)
         return brick
 
@@ -303,12 +281,12 @@
         Alias of AMRKDTree.locate_node, to preserve backwards
         compatibility.
         """
-        return self.locate_node(position) 
+        return self.locate_node(position)
 
     def locate_neighbors(self, grid, ci):
-        r"""Given a grid and cell index, finds the 26 neighbor grids 
+        r"""Given a grid and cell index, finds the 26 neighbor grids
         and cell indices.
-        
+
         Parameters
         ----------
         grid: Grid Object
@@ -352,7 +330,8 @@
 
         if (in_grid != True).sum()>0:
             grids[in_grid != True] = \
-                [self.pf.h.grids[self.locate_brick(new_positions[i]).grid] 
+                [self.pf.h.grids[self.locate_brick(new_positions[i]).grid -
+                                 self._id_offset]
                  for i in get_them]
             cis[in_grid != True] = \
                 [(new_positions[i]-grids[i].LeftEdge)/
@@ -389,7 +368,8 @@
         
         """
         position = np.array(position)
-        grid = self.pf.h.grids[self.locate_brick(position).grid]
+        grid = self.pf.h.grids[self.locate_brick(position).grid -
+                               self._id_offset]
         ci = ((position-grid.LeftEdge)/grid.dds).astype('int64')
         return self.locate_neighbors(grid,ci)
 
@@ -402,7 +382,7 @@
             self.comm.recv_array(self.comm.rank-1, tag=self.comm.rank-1)
         f = h5py.File(fn,'w')
         for node in depth_traverse(self.tree):
-            i = node.id
+            i = node.node_id
             if node.data is not None:
                 for fi,field in enumerate(self.fields):
                     try:
@@ -423,8 +403,8 @@
         try:
             f = h5py.File(fn,"a")
             for node in depth_traverse(self.tree):
-                i = node.id
-                if node.grid is not None:
+                i = node.node_id
+                if node.grid != -1:
                     data = [f["brick_%s_%s" %
                               (hex(i), field)][:].astype('float64') for field in self.fields]
                     node.data = PartitionedGrid(node.grid.id, data,
@@ -473,32 +453,28 @@
         gridids = []
         splitdims = []
         splitposs = []
-        for node in depth_first_touch(self.tree):
-            nids.append(node.id) 
-            les.append(node.left_edge) 
-            res.append(node.right_edge) 
+        for node in depth_first_touch(self.tree.trunk):
+            nids.append(node.node_id) 
+            les.append(node.get_left_edge()) 
+            res.append(node.get_right_edge()) 
             if node.left is None:
                 leftids.append(-1) 
             else:
-                leftids.append(node.left.id) 
+                leftids.append(node.left.node_id) 
             if node.right is None:
                 rightids.append(-1) 
             else:
-                rightids.append(node.right.id) 
+                rightids.append(node.right.node_id) 
             if node.parent is None:
                 parentids.append(-1) 
             else:
-                parentids.append(node.parent.id) 
+                parentids.append(node.parent.node_id) 
             if node.grid is None:
                 gridids.append(-1) 
             else:
                 gridids.append(node.grid) 
-            if node.split is None:
-                splitdims.append(-1)
-                splitposs.append(np.nan)
-            else:
-                splitdims.append(node.split.dim)
-                splitposs.append(node.split.pos)
+            splitdims.append(node.get_split_dim())
+            splitposs.append(node.get_split_pos())
 
         return nids, parentids, leftids, rightids, les, res, gridids,\
                 splitdims, splitposs
@@ -515,19 +491,23 @@
         N = nids.shape[0]
         for i in xrange(N):
             n = self.get_node(nids[i])
-            n.left_edge = les[i]
-            n.right_edge = res[i]
+            n.set_left_edge(les[i])
+            n.set_right_edge(res[i])
             if lids[i] != -1 and n.left is None:
-                n.left = Node(n, None, None, None,  
-                                      None, None, lids[i])
+                n.left = Node(n, None, None, 
+                              np.zeros(3, dtype='float64'),  
+                              np.zeros(3, dtype='float64'),  
+                              -1, lids[i])
             if rids[i] != -1 and n.right is None:
-                n.right = Node(n, None, None, None, 
-                                      None, None, rids[i])
+                n.right = Node(n, None, None, 
+                               np.zeros(3, dtype='float64'),  
+                               np.zeros(3, dtype='float64'),  
+                               -1, rids[i])
             if gids[i] != -1:
                 n.grid = gids[i]
 
             if splitdims[i] != -1:
-                n.split = Split(splitdims[i], splitposs[i])
+                n.create_split(splitdims[i], splitposs[i])
 
         mylog.info('AMRKDTree rebuilt, Final Volume: %e' % kd_sum_volume(self.tree.trunk))
         return self.tree.trunk

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1401,7 +1401,7 @@
         tf = ColorTransferFunction((mi-2, ma+2))
         tf.add_layers(n_contours,w=contour_width,col_bounds = (mi,ma), colormap=cmap)
 
-        cam = pf.h.camera(center, L, width, (N,N), transfer_function=tf)
+        cam = pf.h.camera(center, L, width, (N,N), transfer_function=tf, fields=[field])
         image = cam.snapshot()
 
         if args.enhance:

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/utilities/exceptions.py
--- a/yt/utilities/exceptions.py
+++ b/yt/utilities/exceptions.py
@@ -277,3 +277,13 @@
     def __str__(self):
         return "Particle bounds %s and %s exceed domain bounds %s and %s" % (
             self.mi, self.ma, self.dle, self.dre)
+
+class YTIllDefinedFilter(YTException):
+    def __init__(self, filter, s1, s2):
+        self.filter = filter
+        self.s1 = s1
+        self.s2 = s2
+
+    def __str__(self):
+        return "Filter '%s' ill-defined.  Applied to shape %s but is shape %s." % (
+            self.filter, self.s1, self.s2)

diff -r d65a8e539460e73a5ed81a926bf82c1efcb319b0 -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 yt/utilities/grid_data_format/setup.py
--- a/yt/utilities/grid_data_format/setup.py
+++ b/yt/utilities/grid_data_format/setup.py
@@ -9,6 +9,7 @@
     from numpy.distutils.misc_util import Configuration
     config = Configuration('grid_data_format', parent_package, top_path)
     config.add_subpackage("conversion")
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
     #config.make_svn_version_py()
     return config

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

https://bitbucket.org/yt_analysis/yt-3.0/commits/d32d4b0bd847/
Changeset:   d32d4b0bd847
Branch:      yt-3.0
User:        drudd
Date:        2013-07-17 00:53:00
Summary:     Merged yt_analysis/yt-3.0 into yt-3.0
Affected #:  8 files

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/data_objects/derived_quantities.py
--- a/yt/data_objects/derived_quantities.py
+++ b/yt/data_objects/derived_quantities.py
@@ -40,7 +40,7 @@
     gravitational_constant_cgs, \
     mass_sun_cgs, \
     HUGE
-
+from yt.utilities.math_utils import prec_accum
 
 __CUDA_BLOCK_SIZE = 256
 
@@ -119,12 +119,15 @@
     This function takes no arguments and returns the sum of cell masses and
     particle masses in the object.
     """
-    baryon_mass = data["CellMassMsun"].sum()
     try:
-        particle_mass = data["ParticleMassMsun"].sum()
-        total_mass = baryon_mass + particle_mass
+        cell_mass = _TotalQuantity(data,["CellMassMsun"])
     except KeyError:
-        total_mass = baryon_mass
+        cell_mass = 0.0
+    try:
+        particle_mass = _TotalQuantity(data,["ParticleMassMsun"])
+    except KeyError:
+        particle_mass = 0.0
+    total_mass = cell_mass + particle_mass
     return [total_mass]
 def _combTotalMass(data, total_mass):
     return total_mass.sum()
@@ -146,15 +149,15 @@
     """
     x = y = z = den = 0
     if use_cells: 
-        x += (data["x"] * data["CellMassMsun"]).sum()
-        y += (data["y"] * data["CellMassMsun"]).sum()
-        z += (data["z"] * data["CellMassMsun"]).sum()
-        den += data["CellMassMsun"].sum()
+        x += (data["x"] * data["CellMassMsun"]).sum(dtype=np.float64)
+        y += (data["y"] * data["CellMassMsun"]).sum(dtype=np.float64)
+        z += (data["z"] * data["CellMassMsun"]).sum(dtype=np.float64)
+        den += data["CellMassMsun"].sum(dtype=np.float64)
     if use_particles:
-        x += (data["particle_position_x"] * data["ParticleMassMsun"]).sum()
-        y += (data["particle_position_y"] * data["ParticleMassMsun"]).sum()
-        z += (data["particle_position_z"] * data["ParticleMassMsun"]).sum()
-        den += data["ParticleMassMsun"].sum()
+        x += (data["particle_position_x"] * data["ParticleMassMsun"]).sum(dtype=np.float64)
+        y += (data["particle_position_y"] * data["ParticleMassMsun"]).sum(dtype=np.float64)
+        z += (data["particle_position_z"] * data["ParticleMassMsun"]).sum(dtype=np.float64)
+        den += data["ParticleMassMsun"].sum(dtype=np.float64)
 
     return x,y,z, den
 def _combCenterOfMass(data, x,y,z, den):
@@ -169,8 +172,8 @@
     :param field: The field to average
     :param weight: The field to weight by
     """
-    num = (data[field] * data[weight]).sum()
-    den = data[weight].sum()
+    num = (data[field] * data[weight]).sum(dtype=np.float64)
+    den = data[weight].sum(dtype=np.float64)
     return num, den
 def _combWeightedAverageQuantity(data, field, weight):
     return field.sum()/weight.sum()
@@ -186,11 +189,11 @@
 
     Returns the weighted variance and the weighted mean.
     """
-    my_weight = data[weight].sum()
+    my_weight = data[weight].sum(dtype=np.float64)
     if my_weight == 0:
         return 0.0, 0.0, 0.0
-    my_mean = (data[field] * data[weight]).sum() / my_weight
-    my_var2 = (data[weight] * (data[field] - my_mean)**2).sum() / my_weight
+    my_mean = (data[field] * data[weight]).sum(dtype=np.float64) / my_weight
+    my_var2 = (data[weight] * (data[field] - my_mean)**2).sum(dtype=np.float64) / my_weight
     return my_weight, my_mean, my_var2
 def _combWeightedVariance(data, my_weight, my_mean, my_var2):
     all_weight = my_weight.sum()
@@ -204,10 +207,10 @@
     """
     This function returns the mass-weighted average velocity in the object.
     """
-    xv = (data["x-velocity"] * data["CellMassMsun"]).sum()
-    yv = (data["y-velocity"] * data["CellMassMsun"]).sum()
-    zv = (data["z-velocity"] * data["CellMassMsun"]).sum()
-    w = data["CellMassMsun"].sum()
+    xv = (data["x-velocity"] * data["CellMassMsun"]).sum(dtype=np.float64)
+    yv = (data["y-velocity"] * data["CellMassMsun"]).sum(dtype=np.float64)
+    zv = (data["z-velocity"] * data["CellMassMsun"]).sum(dtype=np.float64)
+    w = data["CellMassMsun"].sum(dtype=np.float64)
     return xv, yv, zv, w
 def _combBulkVelocity(data, xv, yv, zv, w):
     w = w.sum()
@@ -225,7 +228,7 @@
     amx = data["SpecificAngularMomentumX"]*data["CellMassMsun"]
     amy = data["SpecificAngularMomentumY"]*data["CellMassMsun"]
     amz = data["SpecificAngularMomentumZ"]*data["CellMassMsun"]
-    j_mag = [amx.sum(), amy.sum(), amz.sum()]
+    j_mag = [amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)]
     return [j_mag]
 
 def _StarAngularMomentumVector(data):
@@ -241,13 +244,13 @@
     amx = sLx * star_mass
     amy = sLy * star_mass
     amz = sLz * star_mass
-    j_mag = [amx.sum(), amy.sum(), amz.sum()]
+    j_mag = [amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)]
     return [j_mag]
 
 def _combAngularMomentumVector(data, j_mag):
     if len(j_mag.shape) < 2: j_mag = np.expand_dims(j_mag, 0)
-    L_vec = j_mag.sum(axis=0)
-    L_vec_norm = L_vec / np.sqrt((L_vec**2.0).sum())
+    L_vec = j_mag.sum(axis=0,dtype=np.float64)
+    L_vec_norm = L_vec / np.sqrt((L_vec**2.0).sum(dtype=np.float64))
     return L_vec_norm
 add_quantity("AngularMomentumVector", function=_AngularMomentumVector,
              combine_function=_combAngularMomentumVector, n_ret=1)
@@ -260,13 +263,13 @@
     This function returns the spin parameter for the baryons, but it uses
     the particles in calculating enclosed mass.
     """
-    m_enc = data["CellMassMsun"].sum() + data["ParticleMassMsun"].sum()
+    m_enc = _TotalMass(data)
     amx = data["SpecificAngularMomentumX"]*data["CellMassMsun"]
     amy = data["SpecificAngularMomentumY"]*data["CellMassMsun"]
     amz = data["SpecificAngularMomentumZ"]*data["CellMassMsun"]
-    j_mag = np.array([amx.sum(), amy.sum(), amz.sum()])
-    e_term_pre = np.sum(data["CellMassMsun"]*data["VelocityMagnitude"]**2.0)
-    weight=data["CellMassMsun"].sum()
+    j_mag = np.array([amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)])
+    e_term_pre = np.sum(data["CellMassMsun"]*data["VelocityMagnitude"]**2.0,dtype=np.float64)
+    weight=data["CellMassMsun"].sum(dtype=np.float64)
     return j_mag, m_enc, e_term_pre, weight
 def _combBaryonSpinParameter(data, j_mag, m_enc, e_term_pre, weight):
     # Because it's a vector field, we have to ensure we have enough dimensions
@@ -285,15 +288,15 @@
     This function returns the spin parameter for the baryons, but it uses
     the particles in calculating enclosed mass.
     """
-    m_enc = data["CellMassMsun"].sum() + data["ParticleMassMsun"].sum()
+    m_enc = _TotalMass(data)
     amx = data["ParticleSpecificAngularMomentumX"]*data["ParticleMassMsun"]
-    if amx.size == 0: return (np.zeros((3,), dtype='float64'), m_enc, 0, 0)
+    if amx.size == 0: return (np.zeros((3,), dtype=np.float64), m_enc, 0, 0)
     amy = data["ParticleSpecificAngularMomentumY"]*data["ParticleMassMsun"]
     amz = data["ParticleSpecificAngularMomentumZ"]*data["ParticleMassMsun"]
-    j_mag = np.array([amx.sum(), amy.sum(), amz.sum()])
+    j_mag = np.array([amx.sum(dtype=np.float64), amy.sum(dtype=np.float64), amz.sum(dtype=np.float64)])
     e_term_pre = np.sum(data["ParticleMassMsun"]
-                       *data["ParticleVelocityMagnitude"]**2.0)
-    weight=data["ParticleMassMsun"].sum()
+                       *data["ParticleVelocityMagnitude"]**2.0,dtype=np.float64)
+    weight=data["ParticleMassMsun"].sum(dtype=np.float64)
     return j_mag, m_enc, e_term_pre, weight
 add_quantity("ParticleSpinParameter", function=_ParticleSpinParameter,
              combine_function=_combBaryonSpinParameter, n_ret=4)
@@ -340,19 +343,19 @@
     kinetic = 0.5 * (data["CellMass"] * 
                      ((data["x-velocity"] - bv_x)**2 + 
                       (data["y-velocity"] - bv_y)**2 +
-                      (data["z-velocity"] - bv_z)**2)).sum()
+                      (data["z-velocity"] - bv_z)**2)).sum(dtype=np.float64)
 
     if (include_particles):
-	mass_to_use = data["TotalMass"]
+        mass_to_use = data["TotalMass"]
         kinetic += 0.5 * (data["Dark_Matter_Mass"] *
                           ((data["cic_particle_velocity_x"] - bv_x)**2 +
                            (data["cic_particle_velocity_y"] - bv_y)**2 +
-                           (data["cic_particle_velocity_z"] - bv_z)**2)).sum()
+                           (data["cic_particle_velocity_z"] - bv_z)**2)).sum(dtype=np.float64)
     else:
-	mass_to_use = data["CellMass"]
+        mass_to_use = data["CellMass"]
     # Add thermal energy to kinetic energy
     if (include_thermal_energy):
-        thermal = (data["ThermalEnergy"] * mass_to_use).sum()
+        thermal = (data["ThermalEnergy"] * mass_to_use).sum(dtype=np.float64)
         kinetic += thermal
     if periodic_test:
         kinetic = np.ones_like(kinetic)
@@ -679,9 +682,9 @@
     totals = []
     for field in fields:
         if data[field].size < 1:
-            totals.append(0.0)
+            totals.append(np.zeros(1,dtype=prec_accum[data[field].dtype])[0])
             continue
-        totals.append(data[field].sum())
+        totals.append(data[field].sum(dtype=prec_accum[data[field].dtype]))
     return len(fields), totals
 def _combTotalQuantity(data, n_fields, totals):
     totals = np.atleast_2d(totals)
@@ -698,7 +701,7 @@
     pos = [data[(particle_type,"particle_position_%s"%ax)] for ax in "xyz"]
     pos = np.array(pos).T
     mas = data[(particle_type,"particle_mass")]
-    calc_radius= lambda x,y:np.sqrt(np.sum((x-y)**2.0,axis=1))
+    calc_radius= lambda x,y:np.sqrt(np.sum((x-y)**2.0,axis=1,dtype=np.float64))
     density = 0
     if pos.shape[0]==0:
         return -1.0,[-1.,-1.,-1.]
@@ -715,7 +718,7 @@
         center = 0.5*(le+re)
         idx = calc_radius(pos,center)<bin_size
         pos, mas = pos[idx],mas[idx]
-        density = max(density,mas.sum()/bin_size**3.0)
+        density = max(density,mas.sum(dtype=np.float64)/bin_size**3.0)
     return density, center
 def _combParticleDensityCenter(data,densities,centers):
     i = np.argmax(densities)

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -341,7 +341,7 @@
                             if selected_mass[ispec] :
                                 count = len(data[selected_mass[ispec]])
                                 data[selected_mass[ispec]].resize(count+1)
-                                data[selected_mass[ispec]][count] = self.parameters["particle_species_mass"][0]
+                                data[selected_mass[ispec]][count] = self.parameters["particle_species_mass"][ispec]
                         
                     status = artio_particle_read_species_end( self.handle )
                     check_artio_status(status)

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -288,6 +288,15 @@
         for unit in mpc_conversion.keys():
             self.units[unit] = self.parameters['unit_l']\
                 * mpc_conversion[unit] / mpc_conversion["cm"]
+        if self.cosmological_simulation:
+            for unit in mpc_conversion:
+                self.units["%sh" % unit] = self.units[unit] * \
+                    self.hubble_constant
+                self.units["%shcm" % unit] = \
+                    (self.units["%sh" % unit] /
+                        (1 + self.current_redshift))
+                self.units["%scm" % unit] = \
+                    self.units[unit] / (1 + self.current_redshift)
 
         for unit in sec_conversion.keys():
             self.time_units[unit] = self.parameters['unit_t']\

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/frontends/artio/fields.py
--- a/yt/frontends/artio/fields.py
+++ b/yt/frontends/artio/fields.py
@@ -34,6 +34,9 @@
     ValidateSpatial, \
     ValidateGridType
 import yt.data_objects.universal_fields
+from yt.data_objects.particle_fields import \
+    particle_deposition_functions, \
+    particle_vector_functions
 import numpy as np
 
 KnownARTIOFields = FieldInfoContainer()
@@ -247,51 +250,20 @@
     pf = "particle_velocity_%s" % ax
     add_artio_field(pf, function=NullFunc,
                     particle_type=True)
-add_artio_field("particle_mass", function=NullFunc, particle_type=True)
-add_artio_field("particle_index", function=NullFunc, particle_type=True)
 
 for ax in 'xyz':
     pf = "particle_position_%s" % ax
     add_artio_field(pf, function=NullFunc,
                     particle_type=True)
 
-
-def ParticleMass(field, data):
-    return data['particle_mass']
-
-
-def _convertParticleMass(field, data):
-    return data.convert('particle_mass')
-add_field("ParticleMass",
-          function=ParticleMass,
+def _convertParticleMass(data):
+    return np.float64(data.convert('particle_mass'))
+add_field("particle_mass",
+          function=NullFunc,
           convert_function=_convertParticleMass,
           units=r"\rm{g}",
           particle_type=True)
-
-
-def ParticleMassMsunAll(field, data):
-    return data['all', 'particle_mass'] * \
-        data.pf.conversion_factors['particle_mass_msun']
-add_field(('all', "ParticleMassMsun"),
-          function=ParticleMassMsunAll,
-          units=r"\rm{M\odot}", particle_type=True)
-
-
-def ParticleMassMsunStars(field, data):
-    return data['stars', 'particle_mass'] * \
-        data.pf.conversion_factors['particle_mass_msun']
-add_field(('stars', "ParticleMassMsun"),
-          function=ParticleMassMsunStars,
-          units=r"\rm{M\odot}", particle_type=True)
-
-
-def ParticleMassMsunNbody(field, data):
-    return data['nbody', 'particle_mass'] * \
-        data.pf.conversion_factors['particle_mass_msun']
-add_field(('nbody', "ParticleMassMsun"),
-          function=ParticleMassMsunNbody,
-          units=r"\rm{M\odot}", particle_type=True)
-
+add_artio_field("particle_index", function=NullFunc, particle_type=True)
 
 #add_artio_field("creation_time", function=NullFunc, particle_type=True)
 def _particle_age(field, data):
@@ -303,6 +275,15 @@
 add_field(("stars","particle_age"), function=_particle_age, units=r"\rm{s}",
           particle_type=True)
 
+# We can now set up particle vector and particle deposition fields.
+
+for ptype in ("all", "nbody", "stars"):
+    particle_vector_functions(ptype,
+        ["particle_position_%s" % ax for ax in 'xyz'],
+        ["particle_velocity_%s" % ax for ax in 'xyz'],
+        ARTIOFieldInfo)
+    particle_deposition_functions(ptype, "Coordinates", "particle_mass",
+        ARTIOFieldInfo)
 
 def mass_dm(field, data):
     tr = np.ones(data.ActiveDimensions, dtype='float32')

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -49,4 +49,7 @@
         for onechunk in chunks:
             for artchunk in onechunk.objs:
                 artchunk.fill_particles(tr, fields)
+        for ftype, fname in tr.keys():
+            if fname == "particle_mass":
+                tr[ftype, fname] = tr[ftype, fname].astype("float64")
         return tr

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/frontends/ramses/data_structures.py
--- a/yt/frontends/ramses/data_structures.py
+++ b/yt/frontends/ramses/data_structures.py
@@ -395,11 +395,15 @@
         self.conversion_factors["y-velocity"] = vel_u
         self.conversion_factors["z-velocity"] = vel_u
         # Necessary to get the length units in, which are needed for Mass
+        # We also have to multiply by the boxlength here to scale into our
+        # domain.
         self.conversion_factors['mass'] = rho_u * self.parameters['unit_l']**3
 
     def _setup_nounits_units(self):
         # Note that unit_l *already* converts to proper!
-        unit_l = self.parameters['unit_l']
+        # Also note that unit_l must be multiplied by the boxlen parameter to
+        # ensure we are correctly set up for the current domain.
+        unit_l = self.parameters['unit_l'] * self.parameters['boxlen']
         for unit in mpc_conversion.keys():
             self.units[unit] = unit_l * mpc_conversion[unit] / mpc_conversion["cm"]
             self.units['%sh' % unit] = self.units[unit] * self.hubble_constant

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/frontends/ramses/io.py
--- a/yt/frontends/ramses/io.py
+++ b/yt/frontends/ramses/io.py
@@ -98,9 +98,13 @@
         f = open(subset.domain.part_fn, "rb")
         foffsets = subset.domain.particle_field_offsets
         tr = {}
-        #for field in sorted(fields, key=lambda a:foffsets[a]):
+        # We do *all* conversion into boxlen here.
+        # This means that no other conversions need to be applied to convert
+        # positions into the same domain as the octs themselves.
         for field in fields:
             f.seek(foffsets[field])
             dt = subset.domain.particle_field_types[field]
             tr[field] = fpu.read_vector(f, dt)
+            if field[1].startswith("particle_position"):
+                np.divide(tr[field], subset.domain.pf["boxlen"], tr[field])
         return tr

diff -r 28f491c2cabdf0489ff982446629ffa0cbed57c9 -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b yt/utilities/math_utils.py
--- a/yt/utilities/math_utils.py
+++ b/yt/utilities/math_utils.py
@@ -30,6 +30,41 @@
 import numpy as np
 import math
 
+prec_accum = {
+    np.int:                 np.int64,
+    np.int8:                np.int64,
+    np.int16:               np.int64,
+    np.int32:               np.int64,
+    np.int64:               np.int64,
+    np.uint8:               np.uint64,
+    np.uint16:              np.uint64,
+    np.uint32:              np.uint64,
+    np.uint64:              np.uint64,
+    np.float:               np.float64,
+    np.float16:             np.float64,
+    np.float32:             np.float64,
+    np.float64:             np.float64,
+    np.complex:             np.complex128,
+    np.complex64:           np.complex128,
+    np.complex128:          np.complex128,
+    np.dtype('int'):        np.int64,
+    np.dtype('int8'):       np.int64,
+    np.dtype('int16'):      np.int64,
+    np.dtype('int32'):      np.int64,
+    np.dtype('int64'):      np.int64,
+    np.dtype('uint8'):      np.uint64,
+    np.dtype('uint16'):     np.uint64,
+    np.dtype('uint32'):     np.uint64,
+    np.dtype('uint64'):     np.uint64,
+    np.dtype('float'):      np.float64,
+    np.dtype('float16'):    np.float64,
+    np.dtype('float32'):    np.float64,
+    np.dtype('float64'):    np.float64,
+    np.dtype('complex'):    np.complex128,
+    np.dtype('complex64'):  np.complex128,
+    np.dtype('complex128'): np.complex128,
+}
+
 def periodic_position(pos, pf):
     r"""Assuming periodicity, find the periodic position within the domain.
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/58ba5995ff6b/
Changeset:   58ba5995ff6b
Branch:      yt-3.0
User:        drudd
Date:        2013-07-17 01:03:03
Summary:     Fixed typo in sphereselector
Affected #:  1 file

diff -r d32d4b0bd8474bbecd0290c576dd4415c19f5b2b -r 58ba5995ff6b5087d342435e2030db4d7b90b80f yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -123,7 +123,7 @@
         self.overlap_cells = 0
 
         for i in range(3) :
-            if dobj.pf.periodicity[i] and self.pf.domain_left_edge[i] != 0.0 :
+            if dobj.pf.periodicity[i] and dobj.pf.domain_left_edge[i] != 0.0 :
                 print "SelectorObject periodicity assumes left_edge == 0"
                 raise RuntimeError
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/dd017e44c21a/
Changeset:   dd017e44c21a
Branch:      yt-3.0
User:        drudd
Date:        2013-07-17 01:11:46
Summary:     Updated with lost fixes to artio_caller.pyx
Affected #:  1 file

diff -r 58ba5995ff6b5087d342435e2030db4d7b90b80f -r dd017e44c21a0977d49b576bf31d50df4e51b04b yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -258,9 +258,6 @@
 
         cdef int num_fields = len(fields)
         cdef np.float64_t pos[3]
-        cdef np.float64_t dds[3]
-        cdef int eterm[3]
-        for i in range(3) : dds[i] = 0
 
         data = {}
         accessed_species = np.zeros( self.num_species, dtype="int")
@@ -306,7 +303,7 @@
 
             for ispec in range(self.num_species) : 
                 if accessed_species[ispec] :
-                    status = artio_particle_read_species_begin(self.handle, ispec);
+                    status = artio_particle_read_species_begin(self.handle, ispec)
                     check_artio_status(status)
  
                     for particle in range( self.num_particles_per_species[ispec] ) :
@@ -316,9 +313,9 @@
                         check_artio_status(status)
 
                         for i in range(3) :
-                            pos[i] = self.primary_variables[self.particle_position_index[3*ispec+i]] 
+                            pos[i] = self.primary_variables[self.particle_position_index[3*ispec+i]]
 
-                        if selector.select_cell(pos,dds,eterm) :
+                        if selector.select_point(pos) :
                             # loop over primary variables
                             for i,field in selected_primary[ispec] :
                                 count = len(data[field])
@@ -363,9 +360,10 @@
         cdef int64_t count
         cdef int64_t max_octs
         cdef double dpos[3]
-        cdef np.float64_t pos[3]
+        cdef np.float64_t left[3]
+        cdef np.float64_t right[3]
         cdef np.float64_t dds[3]
-        cdef int eterm[3]
+
         cdef int *field_order
         cdef int num_fields  = len(fields)
         field_order = <int*>malloc(sizeof(int)*num_fields)
@@ -427,12 +425,13 @@
                     for child in range(8) :
                         if not refined[child] :
                             for i in range(3) :
-                                pos[i] = dpos[i] + dds[i]*(0.5 if (child & (1<<i)) else -0.5)
+                                left[i] = (dpos[i]-dds[i]) if (child & (i<<1)) else dpos[i]
+                                right[i] = left[i] + dds[i]
 
-                            if selector.select_cell( pos, dds, eterm ) :
+                            if selector.select_bbox(left,right) :
                                 fcoords.resize((count+1, 3))
                                 for i in range(3) :
-                                    fcoords[count][i] = pos[i]
+                                    fcoords[count][i] = left[i]+0.5*dds[i]
                                 ires.resize(count+1)
                                 ires[count] = level
                                 for i in range(num_fields) :
@@ -474,26 +473,28 @@
         cdef int max_range_size = 1024
         cdef int coords[3]
         cdef int64_t sfc_start, sfc_end
-        cdef np.float64_t pos[3]
+        cdef np.float64_t left[3]
+        cdef np.float64_t right[3]
         cdef np.float64_t dds[3]
-        cdef int eterm[3]
         cdef artio_selection *selection
         cdef int i, j, k
-        for i in range(3): dds[i] = 1.0
 
         sfc_ranges=[]
         selection = artio_selection_allocate(self.handle)
         for i in range(self.num_grid) :
             # stupid cython
             coords[0] = i
-            pos[0] = coords[0] + 0.5
+            left[0] = coords[0]
+            right[0] = left[0] + 1.0
             for j in range(self.num_grid) :
                 coords[1] = j
-                pos[1] = coords[1] + 0.5
+                left[1] = coords[1]
+                right[1] = left[1] + 1.0
                 for k in range(self.num_grid) :
                     coords[2] = k 
-                    pos[2] = coords[2] + 0.5
-                    if selector.select_cell(pos, dds, eterm) :
+                    left[2] = coords[2] 
+                    right[2] = left[2] + 1.0
+                    if selector.select_bbox(left,right) :
                         status = artio_selection_add_root_cell(selection, coords)
                         check_artio_status(status)
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/bfdb13e1b225/
Changeset:   bfdb13e1b225
Branch:      yt-3.0
User:        drudd
Date:        2013-07-17 02:11:20
Summary:     Added select_point to GridSelector so particle selection works
Affected #:  1 file

diff -r dd017e44c21a0977d49b576bf31d50df4e51b04b -r bfdb13e1b2250b75275577852deb2584c22a9e45 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -450,6 +450,11 @@
         cdef np.ndarray[np.uint8_t, ndim=1] mask 
         mask = np.zeros(x.shape[0], dtype='uint8')
 
+        # this is to allow selectors to optimize the point vs
+        # 0-radius sphere case.  These two may have different 
+        # effects for 0-volume selectors, however (collision 
+        # between a ray and a point is null, while ray and a
+        # sphere is allowed)
         if radius == 0.0 :
             with nogil:
                 for i in range(x.shape[0]) :
@@ -459,13 +464,13 @@
                     mask[i] = self.select_point(pos)
                     count += mask[i]
         else :
-              with nogil:
-                    for i in range(x.shape[0]):
-                        pos[0] = x[i]
-                        pos[1] = y[i]
-                        pos[2] = z[i]
-                        mask[i] = self.select_sphere(pos, radius)
-                        count += mask[i]
+            with nogil:
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    mask[i] = self.select_sphere(pos, radius)
+                    count += mask[i]
         if count == 0: return None
         return mask.astype("bool")
 
@@ -1307,6 +1312,10 @@
                          int eterm[3]) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        # we apparently don't check if the point actually lies in the grid..
+        return 1
+
 grid_selector = GridSelector
 
 cdef class OctreeSubsetSelector(SelectorObject):


https://bitbucket.org/yt_analysis/yt-3.0/commits/96f7e51bd57c/
Changeset:   96f7e51bd57c
Branch:      yt-3.0
User:        drudd
Date:        2013-07-17 16:59:41
Summary:     Added cython decorators to fix compilation problem
Affected #:  1 file

diff -r bfdb13e1b2250b75275577852deb2584c22a9e45 -r 96f7e51bd57c55c6fbacadff5ce524b1f1033a33 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -1092,6 +1092,9 @@
         # not implemented
         return 0        
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil:
         cdef int i, ax


https://bitbucket.org/yt_analysis/yt-3.0/commits/778e0cb9b010/
Changeset:   778e0cb9b010
Branch:      yt-3.0
User:        drudd
Date:        2013-07-18 02:39:21
Summary:     Fixed several missing return calls which broke Ellipsoid and Disk selectors, Added ellipsoid tests to utilities/tests/test_selectors.py, minor formatting changes
Affected #:  2 files

diff -r 96f7e51bd57c55c6fbacadff5ce524b1f1033a33 -r 778e0cb9b010b54ca73400d94dee68f5aa211d38 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -667,7 +667,7 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        self.select_point( pos ) 
+        return self.select_point( pos ) 
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -875,7 +875,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
-        if self.difference( pos[self.axis], self.coord, self.axis )**2 < radius**2 :
+        if self.difference( pos[self.axis], self.coord, self.axis )**2 < radius**2:
             return 1
         return 0
 
@@ -884,7 +884,7 @@
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3] ) nogil:
-        if left_edge[self.axis] <= self.coord < right_edge[self.axis] :
+        if left_edge[self.axis] <= self.coord < right_edge[self.axis]:
             return 1
         return 0
 
@@ -1104,11 +1104,11 @@
         # if either point is fully enclosed, we select the bounding box
         if left_edge[0] <= self.p1[0] <= right_edge[0] and \
            left_edge[1] <= self.p1[1] <= right_edge[1] and \
-           left_edge[2] <= self.p1[2] <= right_edge[2] :
+           left_edge[2] <= self.p1[2] <= right_edge[2]:
             return 1
         if left_edge[0] <= self.p2[0] <= right_edge[0] and \
            left_edge[1] <= self.p2[1] <= right_edge[1] and \
-           left_edge[2] <= self.p2[2] <= right_edge[2] :
+           left_edge[2] <= self.p2[2] <= right_edge[2]:
             return 1
 
         for ax in range(3):
@@ -1203,14 +1203,14 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        self.select_bbox( left_edge, right_edge )
+        return self.select_bbox(left_edge, right_edge)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        self.select_point(pos)
+        return self.select_point(pos)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -1222,7 +1222,7 @@
         dot_evec[0] = dot_evec[1] = dot_evec[2] = 0
         # Calculate the rotated dot product
         for i in range(3): # axis
-            dist = self.difference( pos[i], self.center[i], i )
+            dist = self.difference(pos[i], self.center[i], i)
             for j in range(3):
                 dot_evec[j] += dist * self.vec[j][i]
         dist = 0.0
@@ -1249,22 +1249,21 @@
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil:
         # This is the sphere selection
-        cdef np.float64_t radius2, box_center, relcenter, closest, dist, edge
-        radius2 = self.mag[0] * self.mag[0]
-        cdef int id
-        if (left_edge[0] <= self.center[0] <= right_edge[0] and
-            left_edge[1] <= self.center[1] <= right_edge[1] and
-            left_edge[2] <= self.center[2] <= right_edge[2]):
+        cdef int i
+        cdef np.float64_t box_center, relcenter, closest, dist, edge
+        if left_edge[0] <= self.center[0] <= right_edge[0] and \
+           left_edge[1] <= self.center[1] <= right_edge[1] and \
+           left_edge[2] <= self.center[2] <= right_edge[2]:
             return 1
         # http://www.gamedev.net/topic/335465-is-this-the-simplest-sphere-aabb-collision-test/
         dist = 0
         for i in range(3):
             box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.difference( box_center, self.center[i], i )
+            relcenter = self.difference(box_center, self.center[i], i)
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
             dist += closest * closest
-        if dist <= radius2: return 1
+        if dist <= self.mag[0]**2: return 1
         return 0
 
 ellipsoid_selector = EllipsoidSelector

diff -r 96f7e51bd57c55c6fbacadff5ce524b1f1033a33 -r 778e0cb9b010b54ca73400d94dee68f5aa211d38 yt/utilities/tests/test_selectors.py
--- a/yt/utilities/tests/test_selectors.py
+++ b/yt/utilities/tests/test_selectors.py
@@ -1,34 +1,103 @@
-from yt.testing import *
+import numpy as np
+from yt.testing import fake_random_pf, assert_equal, assert_array_less
 from yt.utilities.math_utils import periodic_dist
 
+
 def setup():
     from yt.config import ytcfg
-    ytcfg["yt","__withintesting"] = "True"
+    ytcfg["yt", "__withintesting"] = "True"
 
 def test_sphere_selector():
     # generate fake data with a number of non-cubical grids
-    pf = fake_random_pf(64,nprocs=51)
+    pf = fake_random_pf(64, nprocs=51)
     assert(all(pf.periodicity))
 
     # aligned tests
-    spheres = [ [0.0,0.0,0.0],
-                [0.5,0.5,0.5],
-                [1.0,1.0,1.0],
-                [0.25,0.75,0.25] ]
+    spheres = [ [0.0, 0.0, 0.0],
+                [0.5, 0.5, 0.5],
+                [1.0, 1.0, 1.0],
+                [0.25, 0.75, 0.25] ]
 
-    for center in spheres :
+    for center in spheres:
         data = pf.h.sphere(center, 0.25)
         data.get_data()
         # WARNING: this value has not be externally verified
         dd = pf.h.all_data()
         dd.set_field_parameter("center", center)
         n_outside = (dd["RadiusCode"] >= 0.25).sum()
-        assert_equal( data.size + n_outside, dd.size)
+        assert_equal(data.size + n_outside, dd.size)
 
         positions = np.array([data[ax] for ax in 'xyz'])
-        centers = np.tile( data.center, data.shape[0] ).reshape(data.shape[0],3).transpose()
+        centers = np.tile(data.center, 
+                          data.shape[0]).reshape(data.shape[0], 3).transpose()
         dist = periodic_dist(positions, centers,
-                         pf.domain_right_edge-pf.domain_left_edge,
-                         pf.periodicity)
+                             pf.domain_right_edge-pf.domain_left_edge,
+                             pf.periodicity)
         # WARNING: this value has not been externally verified
         yield assert_array_less, dist, 0.25
+
+def test_ellipsoid_selector():
+    # generate fake data with a number of non-cubical grids
+    pf = fake_random_pf(64, nprocs=51)
+    assert(all(pf.periodicity))
+
+    ellipsoids = [ [0.0, 0.0, 0.0],
+                   [0.5, 0.5, 0.5],
+                   [1.0, 1.0, 1.0],
+                   [0.25, 0.75, 0.25] ]
+
+    # spherical ellipsoid tests
+    ratios = 3*[0.25]
+    for center in ellipsoids:
+        data = pf.h.ellipsoid(center, ratios[0], ratios[1], ratios[2], 
+                              np.array([1., 0., 0.]), 0.)
+        data.get_data()
+
+        dd = pf.h.all_data()
+        dd.set_field_parameter("center", center)
+        n_outside = (dd["RadiusCode"] >= ratios[0]).sum()
+        assert_equal(data.size + n_outside, dd.size)
+
+        positions = np.array([data[ax] for ax in 'xyz'])
+        centers = np.tile(data.center, 
+                          data.shape[0]).reshape(data.shape[0], 3).transpose()
+        dist = periodic_dist(positions, centers,
+                             pf.domain_right_edge-pf.domain_left_edge,
+                             pf.periodicity)
+        # WARNING: this value has not been externally verified
+        yield assert_array_less, dist, ratios[0]
+
+    # aligned ellipsoid tests
+    ratios = [0.25, 0.1, 0.1]
+    for center in ellipsoids: 
+        data = pf.h.ellipsoid(center, ratios[0], ratios[1], ratios[2], 
+                              np.array([1., 0., 0.]), 0.)
+        data.get_data()
+        
+        # hack to compute elliptic distance
+        dist2 = np.zeros(data.shape[0])
+        for i,ax in enumerate('xyz'):
+            positions = np.zeros((3,data.shape[0]))
+            positions[i,:] = data[ax]
+            centers = np.zeros((3,data.shape[0]))
+            centers[i,:] = center[i]
+            dist = periodic_dist(positions, centers,
+                                   pf.domain_right_edge-pf.domain_left_edge,
+                                   pf.periodicity)
+            dist2 += (periodic_dist(positions, centers,
+                                   pf.domain_right_edge-pf.domain_left_edge,
+                                   pf.periodicity)/ratios[i])**2
+        # WARNING: this value has not been externally verified
+        yield assert_array_less, dist2, 1.0
+
+#def test_region_selector():
+#
+#def test_disk_selector():
+#
+#def test_cutting_plane_selector():
+#
+#def test_slice_selector():
+#
+#def test_orthoray_selector():
+#
+#def test_ray_selector():


https://bitbucket.org/yt_analysis/yt-3.0/commits/4a5925a84232/
Changeset:   4a5925a84232
Branch:      yt-3.0
User:        drudd
Date:        2013-07-23 05:16:39
Summary:     Removed **2 and addressed Matt's comments
Affected #:  1 file

diff -r 778e0cb9b010b54ca73400d94dee68f5aa211d38 -r 4a5925a8423234b67d70fce0a7b6eaa361fed81d yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -421,15 +421,14 @@
         cdef int count = 0
         cdef int i
         cdef np.float64_t pos[3]
-        if radius == 0.0 :
-            with nogil:
+        with nogil:
+            if radius == 0.0 :
                 for i in range(x.shape[0]):
                     pos[0] = x[i]
                     pos[1] = y[i]
                     pos[2] = z[i]
                     count += self.select_point(pos)
-        else :
-            with nogil:
+            else :
                 for i in range(x.shape[0]):
                     pos[0] = x[i]
                     pos[1] = y[i]
@@ -455,16 +454,15 @@
         # effects for 0-volume selectors, however (collision 
         # between a ray and a point is null, while ray and a
         # sphere is allowed)
-        if radius == 0.0 :
-            with nogil:
+        with nogil:
+            if radius == 0.0 :
                 for i in range(x.shape[0]) :
                     pos[0] = x[i]
                     pos[1] = y[i]
                     pos[2] = z[i]
                     mask[i] = self.select_point(pos)
                     count += mask[i]
-        else :
-            with nogil:
+            else :
                 for i in range(x.shape[0]):
                     pos[0] = x[i]
                     pos[1] = y[i]
@@ -510,9 +508,10 @@
     @cython.cdivision(True)
     cdef int select_point(self, np.float64_t pos[3]) nogil:
         cdef int i
-        cdef np.float64_t dist2 = 0
+        cdef np.float64_t dist, dist2 = 0
         for i in range(3):
-            dist2 += self.difference( pos[i], self.center[i], i )**2
+            dist = self.difference( pos[i], self.center[i], i )
+            dist2 += dist*dist
         if dist2 <= self.radius2: return 1
         return 0
    
@@ -521,10 +520,12 @@
     @cython.cdivision(True)
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         cdef int i
-        cdef np.float64_t dist2 = 0
+        cdef np.float64_t dist, dist2 = 0
         for i in range(3):
-            dist2 += self.difference( pos[i], self.center[i], i )**2
-        if dist2 <= (self.radius+radius)**2: return 1
+            dist = self.difference( pos[i], self.center[i], i ) 
+            dist2 += dist*dist
+        dist = self.radius+radius
+        if dist2 <= dist*dist: return 1
         return 0
  
     @cython.boundscheck(False)
@@ -545,7 +546,7 @@
             relcenter = self.difference( box_center, self.center[i], i )
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
-            dist += closest * closest
+            dist += closest*closest
         if dist <= self.radius2: return 1
         return 0
 
@@ -696,7 +697,8 @@
             h += pos[i] * self.norm_vec[i]
             d += temp*temp
         r2 = (d - h*h)
-        if fabs(h) <= self.height+radius and r2 <= (self.radius+radius)**2: return 1
+        d = self.radius+radius
+        if fabs(h) <= self.height+radius and r2 <= d*d: return 1
         return 0
 
     @cython.boundscheck(False)
@@ -793,7 +795,7 @@
         cdef np.float64_t height = self.d
         for i in range(3) :
             height += pos[i] * self.norm_vec[i]
-        if height*height <= radius**2 : return 1
+        if height*height <= radius*radius : return 1
         return 0
 
     @cython.boundscheck(False)
@@ -875,7 +877,8 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
-        if self.difference( pos[self.axis], self.coord, self.axis )**2 < radius**2:
+        cdef np.float64_t dist = self.difference( pos[self.axis], self.coord, self.axis )
+        if dist*dist < radius*radius:
             return 1
         return 0
 
@@ -933,8 +936,9 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
-        if self.difference( pos[self.px_ax], self.px, self.px_ax )**2 + \
-           self.difference( pos[self.py_ax], self.py, self.py_ax )**2 < radius**2 :
+        cdef np.float64_t dx = self.difference( pos[self.px_ax], self.px, self.px_ax )
+        cdef np.float64_t dy = self.difference( pos[self.py_ax], self.py, self.py_ax )
+        if dx*dx + dy*dy < radius*radius:
             return 1
         return 0
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/d5dcab54f8f0/
Changeset:   d5dcab54f8f0
Branch:      yt-3.0
User:        drudd
Date:        2013-07-24 00:35:16
Summary:     Added test functions for slice and cutting plane
Changed select_cell in cutting plane to use bbox
Removed reslice from YTSliceBase
Added test in Orientation for flawed normal that will cause an SVD error
Affected #:  4 files

diff -r 4a5925a8423234b67d70fce0a7b6eaa361fed81d -r d5dcab54f8f06a104ef931b259dfd79940a1a085 yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -248,33 +248,6 @@
         self._set_center(center)
         self.coord = coord
 
-    def reslice(self, coord):
-        """
-        Change the entire dataset, clearing out the current data and slicing at
-        a new location.  Not terribly useful except for in-place plot changes.
-        """
-        mylog.debug("Setting coordinate to %0.5e" % coord)
-        self.coord = coord
-        self.field_data.clear()
-
-    def shift(self, val):
-        """
-        Moves the slice coordinate up by either a floating point value, or an
-        integer number of indices of the finest grid.
-        """
-        if isinstance(val, types.FloatType):
-            # We add the dx
-            self.coord += val
-        elif isinstance(val, types.IntType):
-            # Here we assume that the grid is the max level
-            level = self.hierarchy.max_level
-            self.coord
-            dx = self.hierarchy.select_grids(level)[0].dds[self.axis]
-            self.coord += dx * val
-        else:
-            raise ValueError(val)
-        self.field_data.clear()
-
     def _generate_container_field(self, field):
         if self._current_chunk is None:
             self.hierarchy._identify_base_chunk(self)
@@ -375,7 +348,6 @@
         self._d = -1.0 * np.dot(self._norm_vec, self.center)
         self._x_vec = self.orienter.unit_vectors[0]
         self._y_vec = self.orienter.unit_vectors[1]
-        self._d = -1.0 * np.dot(self._norm_vec, self.center)
         # First we try all three, see which has the best result:
         vecs = np.identity(3)
         self._rot_mat = np.array([self._x_vec,self._y_vec,self._norm_vec])

diff -r 4a5925a8423234b67d70fce0a7b6eaa361fed81d -r d5dcab54f8f06a104ef931b259dfd79940a1a085 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -773,15 +773,13 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        cdef np.float64_t diag2, height
+        cdef np.float64_t left_edge[3]
+        cdef np.float64_t right_edge[3]
         cdef int i
-        height = self.d
-        diag2 = 0
         for i in range(3):
-            height += pos[i] * self.norm_vec[i]
-            diag2 += dds[i] * dds[i] * 0.25
-        if height * height <= diag2: return 1
-        return 0
+            left_edge[i] = pos[i] - 0.5*dds[i]
+            right_edge[i] = pos[i] + 0.5*dds[i]
+        return self.select_bbox(left_edge, right_edge)
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil:
         # two 0-volume constructs don't intersect
@@ -821,13 +819,18 @@
                     gd = self.d
                     for n in range(3):
                         gd += pos[n] * self.norm_vec[n]
-                    if gd < 0: all_over = 0
-                    if gd > 0: all_under = 0
+                    # this allows corners and faces on the low-end to
+                    # collide, while not selecting cells on the high-side 
+                    if i == 0 and j == 0 and k == 0 :
+                        if gd <= 0: all_over = 0
+                        if gd >= 0: all_under = 0
+                    else :
+                        if gd < 0: all_over = 0
+                        if gd > 0: all_under = 0
         if all_over == 1 or all_under == 1:
             return 0
         return 1
 
-
 cutting_selector = CuttingPlaneSelector
 
 cdef class SliceSelector(SelectorObject):

diff -r 4a5925a8423234b67d70fce0a7b6eaa361fed81d -r d5dcab54f8f06a104ef931b259dfd79940a1a085 yt/utilities/orientation.py
--- a/yt/utilities/orientation.py
+++ b/yt/utilities/orientation.py
@@ -52,6 +52,8 @@
            
         """
         self.steady_north = steady_north
+        if not np.dot(normal_vector, normal_vector) > 0:
+            mylog.error("Normal vector is null")
         if np.all(north_vector == normal_vector):
             mylog.error("North vector and normal vector are the same.  Disregarding north vector.")
             north_vector = None

diff -r 4a5925a8423234b67d70fce0a7b6eaa361fed81d -r d5dcab54f8f06a104ef931b259dfd79940a1a085 yt/utilities/tests/test_selectors.py
--- a/yt/utilities/tests/test_selectors.py
+++ b/yt/utilities/tests/test_selectors.py
@@ -81,23 +81,54 @@
             positions[i,:] = data[ax]
             centers = np.zeros((3,data.shape[0]))
             centers[i,:] = center[i]
-            dist = periodic_dist(positions, centers,
-                                   pf.domain_right_edge-pf.domain_left_edge,
-                                   pf.periodicity)
             dist2 += (periodic_dist(positions, centers,
                                    pf.domain_right_edge-pf.domain_left_edge,
                                    pf.periodicity)/ratios[i])**2
         # WARNING: this value has not been externally verified
         yield assert_array_less, dist2, 1.0
 
+def test_slice_selector():
+    # generate fake data with a number of non-cubical grids
+    pf = fake_random_pf(64, nprocs=51)
+    assert(all(pf.periodicity))
+
+    for i,d in enumerate('xyz'):
+        for coord in np.arange(0,1.0,0.1):
+            data = pf.h.slice(i, coord)
+            data.get_data()
+            assert(data.shape[0] == 64**2)
+            yield assert_array_less, np.abs(data[d] - coord), 1./128.+1e-6
+
+def test_cutting_plane_selector():
+    # generate fake data with a number of non-cubical grids
+    pf = fake_random_pf(64, nprocs=51)
+    assert(all(pf.periodicity))
+
+    # test cutting plane against orthogonal plane
+    for i,d in enumerate('xyz'):
+        norm = np.zeros(3)
+        norm[i] = 1.0
+
+        for coord in np.arange(0, 1.0, 0.1):
+            center = np.zeros(3)
+            center[i] = coord
+
+            data = pf.h.slice(i, coord)
+            data.get_data()
+            data2 = pf.h.cutting(norm, center)
+            data2.get_data()
+
+            assert(data.shape[0] == data2.shape[0])
+
+            cells1 = np.lexsort((data['x'],data['y'],data['z']))
+            cells2 = np.lexsort((data2['x'],data2['y'],data2['z']))
+            for d2 in 'xyz':
+                yield assert_equal, data[d2][cells1], data2[d2][cells2]
+
 #def test_region_selector():
 #
 #def test_disk_selector():
 #
-#def test_cutting_plane_selector():
-#
-#def test_slice_selector():
-#
 #def test_orthoray_selector():
 #
 #def test_ray_selector():


https://bitbucket.org/yt_analysis/yt-3.0/commits/89a30ef604fe/
Changeset:   89a30ef604fe
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-27 20:57:26
Summary:     Merging with Doug's selector changes.
Affected #:  6 files

diff -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae -r 89a30ef604fe503f45f975b301fa3ca44f4295fc yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -248,33 +248,6 @@
         self._set_center(center)
         self.coord = coord
 
-    def reslice(self, coord):
-        """
-        Change the entire dataset, clearing out the current data and slicing at
-        a new location.  Not terribly useful except for in-place plot changes.
-        """
-        mylog.debug("Setting coordinate to %0.5e" % coord)
-        self.coord = coord
-        self.field_data.clear()
-
-    def shift(self, val):
-        """
-        Moves the slice coordinate up by either a floating point value, or an
-        integer number of indices of the finest grid.
-        """
-        if isinstance(val, types.FloatType):
-            # We add the dx
-            self.coord += val
-        elif isinstance(val, types.IntType):
-            # Here we assume that the grid is the max level
-            level = self.hierarchy.max_level
-            self.coord
-            dx = self.hierarchy.select_grids(level)[0].dds[self.axis]
-            self.coord += dx * val
-        else:
-            raise ValueError(val)
-        self.field_data.clear()
-
     def _generate_container_field(self, field):
         if self._current_chunk is None:
             self.hierarchy._identify_base_chunk(self)
@@ -375,7 +348,6 @@
         self._d = -1.0 * np.dot(self._norm_vec, self.center)
         self._x_vec = self.orienter.unit_vectors[0]
         self._y_vec = self.orienter.unit_vectors[1]
-        self._d = -1.0 * np.dot(self._norm_vec, self.center)
         # First we try all three, see which has the best result:
         vecs = np.identity(3)
         self._rot_mat = np.array([self._x_vec,self._y_vec,self._norm_vec])

diff -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae -r 89a30ef604fe503f45f975b301fa3ca44f4295fc yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -258,9 +258,6 @@
 
         cdef int num_fields = len(fields)
         cdef np.float64_t pos[3]
-        cdef np.float64_t dds[3]
-        cdef int eterm[3]
-        for i in range(3) : dds[i] = 0
 
         data = {}
         accessed_species = np.zeros( self.num_species, dtype="int")
@@ -306,7 +303,7 @@
 
             for ispec in range(self.num_species) : 
                 if accessed_species[ispec] :
-                    status = artio_particle_read_species_begin(self.handle, ispec);
+                    status = artio_particle_read_species_begin(self.handle, ispec)
                     check_artio_status(status)
  
                     for particle in range( self.num_particles_per_species[ispec] ) :
@@ -316,9 +313,9 @@
                         check_artio_status(status)
 
                         for i in range(3) :
-                            pos[i] = self.primary_variables[self.particle_position_index[3*ispec+i]] 
+                            pos[i] = self.primary_variables[self.particle_position_index[3*ispec+i]]
 
-                        if selector.select_cell(pos,dds,eterm) :
+                        if selector.select_point(pos) :
                             # loop over primary variables
                             for i,field in selected_primary[ispec] :
                                 count = len(data[field])
@@ -363,9 +360,10 @@
         cdef int64_t count
         cdef int64_t max_octs
         cdef double dpos[3]
-        cdef np.float64_t pos[3]
+        cdef np.float64_t left[3]
+        cdef np.float64_t right[3]
         cdef np.float64_t dds[3]
-        cdef int eterm[3]
+
         cdef int *field_order
         cdef int num_fields  = len(fields)
         field_order = <int*>malloc(sizeof(int)*num_fields)
@@ -427,12 +425,13 @@
                     for child in range(8) :
                         if not refined[child] :
                             for i in range(3) :
-                                pos[i] = dpos[i] + dds[i]*(0.5 if (child & (1<<i)) else -0.5)
+                                left[i] = (dpos[i]-dds[i]) if (child & (i<<1)) else dpos[i]
+                                right[i] = left[i] + dds[i]
 
-                            if selector.select_cell( pos, dds, eterm ) :
+                            if selector.select_bbox(left,right) :
                                 fcoords.resize((count+1, 3))
                                 for i in range(3) :
-                                    fcoords[count][i] = pos[i]
+                                    fcoords[count][i] = left[i]+0.5*dds[i]
                                 ires.resize(count+1)
                                 ires[count] = level
                                 for i in range(num_fields) :
@@ -474,26 +473,28 @@
         cdef int max_range_size = 1024
         cdef int coords[3]
         cdef int64_t sfc_start, sfc_end
-        cdef np.float64_t pos[3]
+        cdef np.float64_t left[3]
+        cdef np.float64_t right[3]
         cdef np.float64_t dds[3]
-        cdef int eterm[3]
         cdef artio_selection *selection
         cdef int i, j, k
-        for i in range(3): dds[i] = 1.0
 
         sfc_ranges=[]
         selection = artio_selection_allocate(self.handle)
         for i in range(self.num_grid) :
             # stupid cython
             coords[0] = i
-            pos[0] = coords[0] + 0.5
+            left[0] = coords[0]
+            right[0] = left[0] + 1.0
             for j in range(self.num_grid) :
                 coords[1] = j
-                pos[1] = coords[1] + 0.5
+                left[1] = coords[1]
+                right[1] = left[1] + 1.0
                 for k in range(self.num_grid) :
                     coords[2] = k 
-                    pos[2] = coords[2] + 0.5
-                    if selector.select_cell(pos, dds, eterm) :
+                    left[2] = coords[2] 
+                    right[2] = left[2] + 1.0
+                    if selector.select_bbox(left,right) :
                         status = artio_selection_add_root_cell(selection, coords)
                         check_artio_status(status)
 

diff -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae -r 89a30ef604fe503f45f975b301fa3ca44f4295fc yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -31,6 +31,8 @@
     cdef public np.int32_t min_level
     cdef public np.int32_t max_level
     cdef int overlap_cells
+    cdef np.float64_t domain_width[3]
+    cdef bint periodicity[3]
 
     cdef void recursively_visit_octs(self, Oct *root,
                         np.float64_t pos[3], np.float64_t dds[3],
@@ -43,6 +45,15 @@
                                np.int32_t level, Oct *o = ?) nogil
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil
+
+    cdef int select_point(self, np.float64_t pos[3] ) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil
+
+	# compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
+
     cdef void set_bounds(self,
                          np.float64_t left_edge[3], np.float64_t right_edge[3],
                          np.float64_t dds[3], int ind[3][2], int *check)

diff -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae -r 89a30ef604fe503f45f975b301fa3ca44f4295fc yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -122,6 +122,15 @@
         self.max_level = getattr(dobj, "max_level", 99)
         self.overlap_cells = 0
 
+        for i in range(3) :
+            if dobj.pf.periodicity[i] and dobj.pf.domain_left_edge[i] != 0.0 :
+                print "SelectorObject periodicity assumes left_edge == 0"
+                raise RuntimeError
+
+            self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
+                                   dobj.pf.domain_left_edge[i]
+            self.periodicity[i] = dobj.pf.periodicity[i]
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -256,6 +265,28 @@
                          int eterm[3]) nogil:
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        return 0
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        return 0
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil:
+        cdef np.float64_t rel = x1 - x2
+        if self.periodicity[d] :
+            if rel > self.domain_width[d]/2.0 :
+                rel -= self.domain_width[d]
+            elif rel < -self.domain_width[d]/2.0 :
+                rel += self.domain_width[d]
+        return rel
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -389,15 +420,20 @@
                            np.float64_t radius = 0.0):
         cdef int count = 0
         cdef int i
-        cdef np.float64_t dds[3], pos[3]
-        dds[0] = dds[1] = dds[2] = radius
-        cdef int eterm[3]
+        cdef np.float64_t pos[3]
         with nogil:
-            for i in range(x.shape[0]):
-                pos[0] = x[i]
-                pos[1] = y[i]
-                pos[2] = z[i]
-                count += self.select_cell(pos, dds, eterm)
+            if radius == 0.0 :
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    count += self.select_point(pos)
+            else :
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    count += self.select_sphere(pos, radius)
         return count
 
     @cython.boundscheck(False)
@@ -409,43 +445,94 @@
                             np.float64_t radius = 0.0):
         cdef int count = 0
         cdef int i
-        cdef np.float64_t dds[3], pos[3]
-        dds[0] = dds[1] = dds[2] = radius
-        cdef int eterm[3]
+        cdef np.float64_t pos[3]
         cdef np.ndarray[np.uint8_t, ndim=1] mask 
         mask = np.zeros(x.shape[0], dtype='uint8')
+
+        # this is to allow selectors to optimize the point vs
+        # 0-radius sphere case.  These two may have different 
+        # effects for 0-volume selectors, however (collision 
+        # between a ray and a point is null, while ray and a
+        # sphere is allowed)
         with nogil:
-            for i in range(x.shape[0]):
-                pos[0] = x[i]
-                pos[1] = y[i]
-                pos[2] = z[i]
-                mask[i] = self.select_cell(pos, dds, eterm)
-                count += mask[i]
+            if radius == 0.0 :
+                for i in range(x.shape[0]) :
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    mask[i] = self.select_point(pos)
+                    count += mask[i]
+            else :
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    mask[i] = self.select_sphere(pos, radius)
+                    count += mask[i]
         if count == 0: return None
         return mask.astype("bool")
 
 cdef class SphereSelector(SelectorObject):
+    cdef np.float64_t radius
     cdef np.float64_t radius2
     cdef np.float64_t center[3]
-    cdef np.float64_t domain_width[3]
-    cdef bint periodicity[3]
 
     def __init__(self, dobj):
         for i in range(3):
             self.center[i] = dobj.center[i]
+        self.radius = dobj.radius
         self.radius2 = dobj.radius * dobj.radius
 
-        for i in range(3) :
-            self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
-                                   dobj.pf.domain_left_edge[i]
-            self.periodicity[i] = dobj.pf.periodicity[i]
-        
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        return self.select_bbox(left_edge,right_edge)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        # sphere center either inside cell or center of cell lies inside sphere
+        if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
+            pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
+            pos[2] - 0.5*dds[2] <= self.center[2] <= pos[2]+0.5*dds[2]):
+            return 1
+        return self.select_point(pos)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        cdef int i
+        cdef np.float64_t dist, dist2 = 0
+        for i in range(3):
+            dist = self.difference( pos[i], self.center[i], i )
+            dist2 += dist*dist
+        if dist2 <= self.radius2: return 1
+        return 0
+   
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        cdef int i
+        cdef np.float64_t dist, dist2 = 0
+        for i in range(3):
+            dist = self.difference( pos[i], self.center[i], i ) 
+            dist2 += dist*dist
+        dist = self.radius+radius
+        if dist2 <= dist*dist: return 1
+        return 0
+ 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
         cdef np.float64_t box_center, relcenter, closest, dist, edge
         cdef int i
         if (left_edge[0] <= self.center[0] <= right_edge[0] and
@@ -456,42 +543,13 @@
         dist = 0
         for i in range(3):
             box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.center[i] - box_center
-            if self.periodicity[i]:
-                if relcenter > self.domain_width[i]/2.0: 
-                    relcenter -= self.domain_width[i] 
-                elif relcenter < -self.domain_width[i]/2.0: 
-                    relcenter += self.domain_width[i] 
+            relcenter = self.difference( box_center, self.center[i], i )
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
-            dist += closest * closest
+            dist += closest*closest
         if dist <= self.radius2: return 1
         return 0
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t dist2, temp
-        cdef int i
-        if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
-            pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
-            pos[2] - 0.5*dds[2] <= self.center[2] <= pos[2]+0.5*dds[2]):
-            return 1
-        dist2 = 0
-        for i in range(3):
-            temp = self.center[i] - pos[i]
-            if self.periodicity[i]:
-                if temp > self.domain_width[i]/2.0:
-                    temp -= self.domain_width[i]
-                elif temp < -self.domain_width[i]/2.0:
-                    temp += self.domain_width[i]
-            #temp = temp - fclip(temp, -dds[i]/2.0, dds[i]/2.0)
-            dist2 += temp*temp
-        if dist2 <= self.radius2: return 1
-        return 0
-
 sphere_selector = SphereSelector
 
 cdef class RegionSelector(SelectorObject):
@@ -513,6 +571,14 @@
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
         if level < self.min_level or level > self.max_level: return 0
+        return self.select_bbox( left_edge, right_edge )
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        cdef int i
         for i in range(3):
             if left_edge[i] >= self.right_edge[i]: return 0
             if right_edge[i] <= self.left_edge[i]: return 0
@@ -523,6 +589,7 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
+        cdef int i
         cdef np.float64_t dxp
         for i in range(3):
             dxp = self.dx_pad * dds[i]
@@ -535,6 +602,18 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        # assume pos[3] is inside domain
+        cdef int i
+        for i in range(3) :
+            if pos[i] < self.left_edge[i] or \
+                    pos[i] >= self.right_edge[i] :
+                return 0
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef void set_bounds(self,
                          np.float64_t left_edge[3], np.float64_t right_edge[3],
                          np.float64_t dds[3], int ind[3][2], int *check):
@@ -564,8 +643,7 @@
 cdef class DiskSelector(SelectorObject):
     cdef np.float64_t norm_vec[3]
     cdef np.float64_t center[3]
-    cdef np.float64_t d
-    cdef np.float64_t radius2
+    cdef np.float64_t radius, radius2
     cdef np.float64_t height
 
     def __init__(self, dobj):
@@ -573,7 +651,7 @@
         for i in range(3):
             self.norm_vec[i] = dobj._norm_vec[i]
             self.center[i] = dobj.center[i]
-        self.d = dobj._d
+        self.radius = dobj._radius
         self.radius2 = dobj._radius * dobj._radius
         self.height = dobj._height
 
@@ -583,13 +661,73 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        return self.select_bbox( left_edge, right_edge )
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        return self.select_point( pos ) 
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        cdef np.float64_t h, d, r2, temp
+        cdef int i
+        h = d = 0
+        for i in range(3):
+            temp = self.difference( pos[i], self.center[i], i )
+            h += temp * self.norm_vec[i]
+            d += temp*temp
+        r2 = (d - h*h)
+        if fabs(h) <= self.height and r2 <= self.radius2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        cdef np.float64_t h, d, r2, temp
+        cdef int i
+        h = d = 0
+        for i in range(3):
+            temp = self.difference( pos[i], self.center[i], i )
+            h += pos[i] * self.norm_vec[i]
+            d += temp*temp
+        r2 = (d - h*h)
+        d = self.radius+radius
+        if fabs(h) <= self.height+radius and r2 <= d*d: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil:
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3], H, D, R2, temp
         cdef int i, j, k, n
+        cdef int all_under = 1
+        cdef int all_over = 1
+        cdef int any_radius = 0
+        # A moment of explanation (revised):
+        #    The disk and bounding box collide if any of the following are true:
+        #    1) the center of the disk is inside the bounding box
+        #    2) any corner of the box lies inside the disk
+        #    3) the box spans the plane (!all_under and !all_over) and at least
+        #       one corner is within the cylindrical radius
+
+        # check if disk center lies inside bbox
+        if left_edge[0] <= self.center[0] <= right_edge[0] and \
+           left_edge[1] <= self.center[1] <= right_edge[1] and \
+           left_edge[2] <= self.center[2] <= right_edge[2] :
+            return 1
+        
+        # check all corners
         arr[0] = left_edge
         arr[1] = right_edge
-        cdef int cond[2]
-        cond[0] = cond[1] = 0
         for i in range(2):
             pos[0] = arr[i][0]
             for j in range(2):
@@ -598,39 +736,16 @@
                     pos[2] = arr[k][2]
                     H = D = 0
                     for n in range(3):
-                        H += (pos[n] * self.norm_vec[n])
-                        temp = (pos[n] - self.center[n])
+                        temp = self.difference( pos[n], self.center[n], n )
+                        H += (temp * self.norm_vec[n])
                         D += temp*temp
-                    H += self.d
                     R2 = (D - H*H)
-                    if fabs(H) < self.height: cond[0] = 1
-                    if R2 < self.radius2: cond[1] = 1
-        # A moment of explanation:
-        #    We want our height to be less than the height AND our radius2 to be
-        #    less than radius2, so we set cond[0] equal to 1 if any corners
-        #    match that criteria.
-        # Note that we OVERSELECT grids, as we are selecting anything within
-        # the height and within the radius, which is kind of a funny thing.
-        # Cell selection takes care of the rest.
-        if cond[0] == 1 and cond[1] == 1:
-            return 1
-        return 0
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t h, d, r2, temp
-        cdef int i
-        h = d = 0
-        for i in range(3):
-            h += pos[i] * self.norm_vec[i]
-            temp = pos[i] - self.center[i]
-            d += temp*temp
-        h += self.d
-        r2 = (d - h*h)
-        if fabs(h) <= self.height and r2 <= self.radius2: return 1
+                    if R2 < self.radius2 :
+                        any_radius = 1
+                        if fabs(H) < self.height: return 1
+                    if H < 0: all_over = 0
+                    if H > 0: all_under = 0
+        if all_over == 0 and all_under == 0 and any_radius == 1: return 1
         return 0
 
 disk_selector = DiskSelector
@@ -651,6 +766,41 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        return self.select_bbox(left_edge,right_edge)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        cdef np.float64_t left_edge[3]
+        cdef np.float64_t right_edge[3]
+        cdef int i
+        for i in range(3):
+            left_edge[i] = pos[i] - 0.5*dds[i]
+            right_edge[i] = pos[i] + 0.5*dds[i]
+        return self.select_bbox(left_edge, right_edge)
+
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        cdef int i
+        cdef np.float64_t height = self.d
+        for i in range(3) :
+            height += pos[i] * self.norm_vec[i]
+        if height*height <= radius*radius : return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil:
         cdef int i, j, k, n
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3]
@@ -669,27 +819,18 @@
                     gd = self.d
                     for n in range(3):
                         gd += pos[n] * self.norm_vec[n]
-                    if gd < 0: all_over = 0
-                    if gd > 0: all_under = 0
+                    # this allows corners and faces on the low-end to
+                    # collide, while not selecting cells on the high-side 
+                    if i == 0 and j == 0 and k == 0 :
+                        if gd <= 0: all_over = 0
+                        if gd >= 0: all_under = 0
+                    else :
+                        if gd < 0: all_over = 0
+                        if gd > 0: all_under = 0
         if all_over == 1 or all_under == 1:
             return 0
         return 1
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t diag2, height
-        cdef int i
-        height = self.d
-        diag2 = 0
-        for i in range(3):
-            height += pos[i] * self.norm_vec[i]
-            diag2 += dds[i] * dds[i] * 0.25
-        if height * height <= diag2: return 1
-        return 0
-
 cutting_selector = CuttingPlaneSelector
 
 cdef class SliceSelector(SelectorObject):
@@ -719,11 +860,8 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        if right_edge[self.axis] > self.coord \
-           and left_edge[self.axis] <= self.coord:
-            return 1
-        return 0
-    
+        return self.select_bbox( left_edge, right_edge )
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -734,6 +872,28 @@
             return 1
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        cdef np.float64_t dist = self.difference( pos[self.axis], self.coord, self.axis )
+        if dist*dist < radius*radius:
+            return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil:
+        if left_edge[self.axis] <= self.coord < right_edge[self.axis]:
+            return 1
+        return 0
+
 slice_selector = SliceSelector
 
 cdef class OrthoRaySelector(SelectorObject):
@@ -757,25 +917,43 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        if (    (self.px >= left_edge[self.px_ax])
-            and (self.px < right_edge[self.px_ax])
-            and (self.py >= left_edge[self.py_ax])
-            and (self.py < right_edge[self.py_ax])):
-            return 1
-        return 0
-    
+        return self.select_bbox(left_edge,right_edge)
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        if (    (self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax])
-            and (self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax])
-            and (self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax])
-            and (self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax])):
+        if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
+           self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
+           self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax] and \
+           self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax]:
             return 1
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        cdef np.float64_t dx = self.difference( pos[self.px_ax], self.px, self.px_ax )
+        cdef np.float64_t dy = self.difference( pos[self.py_ax], self.py, self.py_ax )
+        if dx*dx + dy*dy < radius*radius:
+            return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3] ) nogil:
+        if left_edge[self.px_ax] <= self.px < right_edge[self.px_ax] and \
+           left_edge[self.py_ax] <= self.py < right_edge[self.py_ax] :
+            return 1
+        return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -836,46 +1014,7 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        cdef int i, ax
-        cdef int i1, i2
-        cdef np.float64_t vs[3], t, v[3]
-        for ax in range(3):
-            i1 = (ax+1) % 3
-            i2 = (ax+2) % 3
-            t = (left_edge[ax] - self.p1[ax])/self.vec[ax]
-            for i in range(3):
-                vs[i] = t * self.vec[i] + self.p1[i]
-            if left_edge[i1] <= vs[i1] and \
-               right_edge[i1] >= vs[i1] and \
-               left_edge[i2] <= vs[i2] and \
-               right_edge[i2] >= vs[i2] and \
-               0.0 <= t <= 1.0:
-                return 1
-            t = (right_edge[ax] - self.p1[ax])/self.vec[ax]
-            for i in range(3):
-                vs[i] = t * self.vec[i] + self.p1[i]
-            if left_edge[i1] <= vs[i1] and \
-               right_edge[i1] >= vs[i1] and \
-               left_edge[i2] <= vs[i2] and \
-               right_edge[i2] >= vs[i2] and\
-               0.0 <= t <= 1.0:
-                return 1
-        # if the point is fully enclosed, we count the grid
-        if left_edge[0] <= self.p1[0] and \
-           right_edge[0] >= self.p1[0] and \
-           left_edge[1] <= self.p1[1] and \
-           right_edge[1] >= self.p1[1] and \
-           left_edge[2] <= self.p1[2] and \
-           right_edge[2] >= self.p1[2]:
-            return 1
-        if left_edge[0] <= self.p2[0] and \
-           right_edge[0] >= self.p2[0] and \
-           left_edge[1] <= self.p2[1] and \
-           right_edge[1] >= self.p2[1] and \
-           left_edge[2] <= self.p2[2] and \
-           right_edge[2] >= self.p2[2]:
-            return 1
-        return 0
+        return self.select_bbox(left_edge,right_edge)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -951,7 +1090,53 @@
         if not (ni == ia.hits):
             print ni, ia.hits
         return dtr, tr
-    
+
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        # not implemented
+        return 0        
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        cdef int i, ax
+        cdef int i1, i2
+        cdef np.float64_t vs[3], t, v[3]
+
+        # if either point is fully enclosed, we select the bounding box
+        if left_edge[0] <= self.p1[0] <= right_edge[0] and \
+           left_edge[1] <= self.p1[1] <= right_edge[1] and \
+           left_edge[2] <= self.p1[2] <= right_edge[2]:
+            return 1
+        if left_edge[0] <= self.p2[0] <= right_edge[0] and \
+           left_edge[1] <= self.p2[1] <= right_edge[1] and \
+           left_edge[2] <= self.p2[2] <= right_edge[2]:
+            return 1
+
+        for ax in range(3):
+            i1 = (ax+1) % 3
+            i2 = (ax+2) % 3
+            t = (left_edge[ax] - self.p1[ax])/self.vec[ax]
+            if 0.0 <= t <= 1.0 :
+                for i in range(3):
+                    vs[i] = t * self.vec[i] + self.p1[i]
+                if left_edge[i1] <= vs[i1] <= right_edge[i1] and \
+                   left_edge[i2] <= vs[i2] <= right_edge[i2] :
+                    return 1
+            t = (right_edge[ax] - self.p1[ax])/self.vec[ax]
+            if 0.0 <= t <= 1.0 :
+                for i in range(3):
+                    vs[i] = t * self.vec[i] + self.p1[i]
+                if left_edge[i1] <= vs[i1] <= right_edge[i1] and \
+                   left_edge[i2] <= vs[i2] <= right_edge[i2] :
+                    return 1
+        return 0
+
 ray_selector = RaySelector
 
 cdef class DataCollectionSelector(SelectorObject):
@@ -984,8 +1169,6 @@
         cdef np.ndarray[np.int64_t, ndim=1] oids = self.obj_ids
         with nogil:
             for n in range(self.nids):
-                # Call our selector function
-                # Check if the sphere is inside the grid
                 gridi[oids[n]] = 1
         return gridi.astype("bool")
 
@@ -1027,38 +1210,26 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        # This is the sphere selection
-        cdef np.float64_t radius2, box_center, relcenter, closest, dist, edge
-        return 1
-        radius2 = self.mag[0] * self.mag[0]
-        cdef int id
-        if (left_edge[0] <= self.center[0] <= right_edge[0] and
-            left_edge[1] <= self.center[1] <= right_edge[1] and
-            left_edge[2] <= self.center[2] <= right_edge[2]):
-            return 1
-        # http://www.gamedev.net/topic/335465-is-this-the-simplest-sphere-aabb-collision-test/
-        dist = 0
-        for i in range(3):
-            box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.center[i] - box_center
-            edge = right_edge[i] - left_edge[i]
-            closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
-            dist += closest * closest
-        if dist < radius2: return 1
-        return 0
+        return self.select_bbox(left_edge, right_edge)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
+        return self.select_point(pos)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         cdef np.float64_t dot_evec[3]
         cdef np.float64_t dist
         cdef int i, j
         dot_evec[0] = dot_evec[1] = dot_evec[2] = 0
         # Calculate the rotated dot product
         for i in range(3): # axis
-            dist = pos[i] - self.center[i]
+            dist = self.difference(pos[i], self.center[i], i)
             for j in range(3):
                 dot_evec[j] += dist * self.vec[j][i]
         dist = 0.0
@@ -1067,6 +1238,41 @@
         if dist <= 1.0: return 1
         return 0
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        # this is the sphere selection
+        cdef int i
+        cdef np.float64_t dist2 = 0
+        for i in range(3):
+            dist2 += self.difference( pos[i], self.center[i], i )**2
+        if dist2 <= (self.mag[0]+radius)**2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        # This is the sphere selection
+        cdef int i
+        cdef np.float64_t box_center, relcenter, closest, dist, edge
+        if left_edge[0] <= self.center[0] <= right_edge[0] and \
+           left_edge[1] <= self.center[1] <= right_edge[1] and \
+           left_edge[2] <= self.center[2] <= right_edge[2]:
+            return 1
+        # http://www.gamedev.net/topic/335465-is-this-the-simplest-sphere-aabb-collision-test/
+        dist = 0
+        for i in range(3):
+            box_center = (right_edge[i] + left_edge[i])/2.0
+            relcenter = self.difference(box_center, self.center[i], i)
+            edge = right_edge[i] - left_edge[i]
+            closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
+            dist += closest * closest
+        if dist <= self.mag[0]**2: return 1
+        return 0
+
 ellipsoid_selector = EllipsoidSelector
 
 cdef class GridSelector(SelectorObject):
@@ -1115,6 +1321,9 @@
                          int eterm[3]) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        # we apparently don't check if the point actually lies in the grid..
+        return 1
 
 grid_selector = GridSelector
 
@@ -1251,4 +1460,14 @@
                          Oct *o = NULL) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+        return 1
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        return 1
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return 1
+
 always_selector = AlwaysSelector

diff -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae -r 89a30ef604fe503f45f975b301fa3ca44f4295fc yt/utilities/orientation.py
--- a/yt/utilities/orientation.py
+++ b/yt/utilities/orientation.py
@@ -52,6 +52,8 @@
            
         """
         self.steady_north = steady_north
+        if not np.dot(normal_vector, normal_vector) > 0:
+            mylog.error("Normal vector is null")
         if np.all(north_vector == normal_vector):
             mylog.error("North vector and normal vector are the same.  Disregarding north vector.")
             north_vector = None

diff -r 7210b2cf9285ad81f33d0d65a76fab8044c9cdae -r 89a30ef604fe503f45f975b301fa3ca44f4295fc yt/utilities/tests/test_selectors.py
--- a/yt/utilities/tests/test_selectors.py
+++ b/yt/utilities/tests/test_selectors.py
@@ -1,34 +1,134 @@
-from yt.testing import *
+import numpy as np
+from yt.testing import fake_random_pf, assert_equal, assert_array_less
 from yt.utilities.math_utils import periodic_dist
 
+
 def setup():
     from yt.config import ytcfg
-    ytcfg["yt","__withintesting"] = "True"
+    ytcfg["yt", "__withintesting"] = "True"
 
 def test_sphere_selector():
     # generate fake data with a number of non-cubical grids
-    pf = fake_random_pf(64,nprocs=51)
+    pf = fake_random_pf(64, nprocs=51)
     assert(all(pf.periodicity))
 
     # aligned tests
-    spheres = [ [0.0,0.0,0.0],
-                [0.5,0.5,0.5],
-                [1.0,1.0,1.0],
-                [0.25,0.75,0.25] ]
+    spheres = [ [0.0, 0.0, 0.0],
+                [0.5, 0.5, 0.5],
+                [1.0, 1.0, 1.0],
+                [0.25, 0.75, 0.25] ]
 
-    for center in spheres :
+    for center in spheres:
         data = pf.h.sphere(center, 0.25)
         data.get_data()
         # WARNING: this value has not be externally verified
         dd = pf.h.all_data()
         dd.set_field_parameter("center", center)
         n_outside = (dd["RadiusCode"] >= 0.25).sum()
-        assert_equal( data.size + n_outside, dd.size)
+        assert_equal(data.size + n_outside, dd.size)
 
         positions = np.array([data[ax] for ax in 'xyz'])
-        centers = np.tile( data.center, data.shape[0] ).reshape(data.shape[0],3).transpose()
+        centers = np.tile(data.center, 
+                          data.shape[0]).reshape(data.shape[0], 3).transpose()
         dist = periodic_dist(positions, centers,
-                         pf.domain_right_edge-pf.domain_left_edge,
-                         pf.periodicity)
+                             pf.domain_right_edge-pf.domain_left_edge,
+                             pf.periodicity)
         # WARNING: this value has not been externally verified
         yield assert_array_less, dist, 0.25
+
+def test_ellipsoid_selector():
+    # generate fake data with a number of non-cubical grids
+    pf = fake_random_pf(64, nprocs=51)
+    assert(all(pf.periodicity))
+
+    ellipsoids = [ [0.0, 0.0, 0.0],
+                   [0.5, 0.5, 0.5],
+                   [1.0, 1.0, 1.0],
+                   [0.25, 0.75, 0.25] ]
+
+    # spherical ellipsoid tests
+    ratios = 3*[0.25]
+    for center in ellipsoids:
+        data = pf.h.ellipsoid(center, ratios[0], ratios[1], ratios[2], 
+                              np.array([1., 0., 0.]), 0.)
+        data.get_data()
+
+        dd = pf.h.all_data()
+        dd.set_field_parameter("center", center)
+        n_outside = (dd["RadiusCode"] >= ratios[0]).sum()
+        assert_equal(data.size + n_outside, dd.size)
+
+        positions = np.array([data[ax] for ax in 'xyz'])
+        centers = np.tile(data.center, 
+                          data.shape[0]).reshape(data.shape[0], 3).transpose()
+        dist = periodic_dist(positions, centers,
+                             pf.domain_right_edge-pf.domain_left_edge,
+                             pf.periodicity)
+        # WARNING: this value has not been externally verified
+        yield assert_array_less, dist, ratios[0]
+
+    # aligned ellipsoid tests
+    ratios = [0.25, 0.1, 0.1]
+    for center in ellipsoids: 
+        data = pf.h.ellipsoid(center, ratios[0], ratios[1], ratios[2], 
+                              np.array([1., 0., 0.]), 0.)
+        data.get_data()
+        
+        # hack to compute elliptic distance
+        dist2 = np.zeros(data.shape[0])
+        for i,ax in enumerate('xyz'):
+            positions = np.zeros((3,data.shape[0]))
+            positions[i,:] = data[ax]
+            centers = np.zeros((3,data.shape[0]))
+            centers[i,:] = center[i]
+            dist2 += (periodic_dist(positions, centers,
+                                   pf.domain_right_edge-pf.domain_left_edge,
+                                   pf.periodicity)/ratios[i])**2
+        # WARNING: this value has not been externally verified
+        yield assert_array_less, dist2, 1.0
+
+def test_slice_selector():
+    # generate fake data with a number of non-cubical grids
+    pf = fake_random_pf(64, nprocs=51)
+    assert(all(pf.periodicity))
+
+    for i,d in enumerate('xyz'):
+        for coord in np.arange(0,1.0,0.1):
+            data = pf.h.slice(i, coord)
+            data.get_data()
+            assert(data.shape[0] == 64**2)
+            yield assert_array_less, np.abs(data[d] - coord), 1./128.+1e-6
+
+def test_cutting_plane_selector():
+    # generate fake data with a number of non-cubical grids
+    pf = fake_random_pf(64, nprocs=51)
+    assert(all(pf.periodicity))
+
+    # test cutting plane against orthogonal plane
+    for i,d in enumerate('xyz'):
+        norm = np.zeros(3)
+        norm[i] = 1.0
+
+        for coord in np.arange(0, 1.0, 0.1):
+            center = np.zeros(3)
+            center[i] = coord
+
+            data = pf.h.slice(i, coord)
+            data.get_data()
+            data2 = pf.h.cutting(norm, center)
+            data2.get_data()
+
+            assert(data.shape[0] == data2.shape[0])
+
+            cells1 = np.lexsort((data['x'],data['y'],data['z']))
+            cells2 = np.lexsort((data2['x'],data2['y'],data2['z']))
+            for d2 in 'xyz':
+                yield assert_equal, data[d2][cells1], data2[d2][cells2]
+
+#def test_region_selector():
+#
+#def test_disk_selector():
+#
+#def test_orthoray_selector():
+#
+#def test_ray_selector():


https://bitbucket.org/yt_analysis/yt-3.0/commits/3e7dcb29cd1b/
Changeset:   3e7dcb29cd1b
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-27 21:42:18
Summary:     Adding selection_routines.pxd to deps for particle_deposit.pyx.
Affected #:  1 file

diff -r 89a30ef604fe503f45f975b301fa3ca44f4295fc -r 3e7dcb29cd1b9ac7931379e3b87c985c4f28e6cd yt/geometry/setup.py
--- a/yt/geometry/setup.py
+++ b/yt/geometry/setup.py
@@ -41,6 +41,7 @@
                 libraries=["m"],
                 depends=["yt/utilities/lib/fp_utils.pxd",
                          "yt/geometry/oct_container.pxd",
+                         "yt/geometry/selection_routines.pxd",
                          "yt/geometry/particle_deposit.pxd"])
     config.add_extension("fake_octree", 
                 ["yt/geometry/fake_octree.pyx"],


https://bitbucket.org/yt_analysis/yt-3.0/commits/0ea014340e57/
Changeset:   0ea014340e57
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-27 22:07:04
Summary:     This set of changes finishes periodicity for covering grids.

Note that I have made a handful of modifications to the RegionSelector.  This
is not the only place that changes need to be made; I think we may want to
abstract out some of the logic for checking periodicity and have the base
methods conduct those operations while having selectors themselves conduct
specific operations assuming *no* periodicity.
Affected #:  2 files

diff -r 3e7dcb29cd1b9ac7931379e3b87c985c4f28e6cd -r 0ea014340e57c7c80254f1619d8c6a09c466a715 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -578,10 +578,21 @@
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil:
-        cdef int i
+        cdef int i, shift, included
+        cdef np.float64_t LE[3], RE[3]
         for i in range(3):
-            if left_edge[i] >= self.right_edge[i]: return 0
-            if right_edge[i] <= self.left_edge[i]: return 0
+            if self.periodicity[i] == 0:
+                if left_edge[i] >= self.right_edge[i]: return 0
+                if right_edge[i] <= self.left_edge[i]: return 0
+            else:
+                included = 0
+                for shift in range(3):
+                    LE[i] = left_edge[i] + self.domain_width[i] * (shift - 1)
+                    RE[i] = right_edge[i] + self.domain_width[i] * (shift - 1)
+                    if LE[i] >= self.right_edge[i]: continue
+                    if RE[i] <= self.left_edge[i]: continue
+                    included += 1
+                if included == 0: return 0
         return 1
 
     @cython.boundscheck(False)
@@ -589,14 +600,21 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
                          int eterm[3]) nogil:
-        cdef int i
-        cdef np.float64_t dxp
+        cdef int i, shift, included
+        cdef np.float64_t dxp, ppos[3]
         for i in range(3):
             dxp = self.dx_pad * dds[i]
-            if pos[i] - dxp >= self.right_edge[i]:
-                eterm[i] = 1
-                return 0
-            if pos[i] + dxp <= self.left_edge[i]: return 0
+            if self.periodicity[i] == 0:
+                if pos[i] - dxp >= self.right_edge[i]: return 0
+                if pos[i] + dxp <= self.left_edge[i]: return 0
+            else:
+                included = 0
+                for shift in range(3):
+                    ppos[i] = pos[i] + self.domain_width[i] * (shift - 1)
+                    if ppos[i] - dxp >= self.right_edge[i]: continue
+                    if ppos[i] + dxp <= self.left_edge[i]: continue
+                    included = 1
+                if included == 0: return 0
         return 1
 
     @cython.boundscheck(False)

diff -r 3e7dcb29cd1b9ac7931379e3b87c985c4f28e6cd -r 0ea014340e57c7c80254f1619d8c6a09c466a715 yt/utilities/lib/misc_utilities.pyx
--- a/yt/utilities/lib/misc_utilities.pyx
+++ b/yt/utilities/lib/misc_utilities.pyx
@@ -563,9 +563,9 @@
         offsets[i][0] = offsets[i][2] = 0
         offsets[i][1] = 1
         if left_index[i] < 0:
+            offsets[i][2] = 1
+        if left_index[i] + dim[i] >= level_dims[i]:
             offsets[i][0] = 1
-        if left_index[i] + dim[i] >= level_dims[i]:
-            offsets[i][2] = 1
     for n in range(nf):
         tot = 0
         ofield = output_fields[n]


https://bitbucket.org/yt_analysis/yt-3.0/commits/3b3cb646c88a/
Changeset:   3b3cb646c88a
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-27 23:04:09
Summary:     Removing eterm, check and set_bounds from selection_routines.
Affected #:  2 files

diff -r 0ea014340e57c7c80254f1619d8c6a09c466a715 -r 3b3cb646c88a3faeffa5233c5d8aa464aed985ce yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -43,8 +43,7 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = ?) nogil
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
@@ -53,7 +52,3 @@
 
 	# compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
     cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
-
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check)

diff -r 0ea014340e57c7c80254f1619d8c6a09c466a715 -r 3b3cb646c88a3faeffa5233c5d8aa464aed985ce yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -195,9 +195,7 @@
         res = self.select_grid(LE, RE, level, root)
         if res == 1 and data.domain > 0 and root.domain != data.domain:
             res = -1
-        cdef int eterm[3] 
         cdef int increment = 1
-        eterm[0] = eterm[1] = eterm[2] = 0
         cdef int next_level, this_level
         # next_level: an int that says whether or not we can progress to children
         # this_level: an int that says whether or not we can select from this
@@ -241,7 +239,7 @@
                             data.pos[2] = (data.pos[2] >> 1)
                             data.level -= 1
                         elif this_level == 1:
-                            selected = self.select_cell(spos, sdds, eterm)
+                            selected = self.select_cell(spos, sdds)
                             if ch != NULL:
                                 selected *= self.overlap_cells
                             data.global_index += increment
@@ -261,8 +259,7 @@
                                np.int32_t level, Oct *o = NULL) nogil:
         return 0
     
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 0
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil:
@@ -303,7 +300,6 @@
             ind[i][1] = gobj.ActiveDimensions[i]
             dds[i] = odds[i]
         cdef int count = 0
-        cdef int check = 1
         # Check for the level bounds
         cdef np.int32_t level = gobj.Level
         if level < self.min_level or level > self.max_level:
@@ -312,35 +308,18 @@
         cdef int this_level = 0
         if level == self.max_level:
             this_level = 1
-        cdef int eterm[3]
-        self.set_bounds(<np.float64_t *> left_edge.data,
-                        <np.float64_t *> right_edge.data,
-                        dds, ind, &check)
         with nogil:
-            if check == 1:
-                pos[0] = left_edge[0] + dds[0] * 0.5
-                for i in range(ind[0][0], ind[0][1]):
-                    eterm[0] = 0
-                    pos[1] = left_edge[1] + dds[1] * 0.5
-                    for j in range(ind[1][0], ind[1][1]):
-                        eterm[1] = 0
-                        pos[2] = left_edge[2] + dds[2] * 0.5
-                        for k in range(ind[2][0], ind[2][1]):
-                            eterm[2] = 0
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += self.select_cell(pos, dds, eterm)
-                            if eterm[2] == 1: break
-                            pos[2] += dds[1]
-                        if eterm[1] == 1: break
-                        pos[1] += dds[1]
-                    if eterm[0] == 1: break
-                    pos[0] += dds[0]
-            else:
-                for i in range(ind[0][0], ind[0][1]):
-                    for j in range(ind[1][0], ind[1][1]):
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += 1
+            pos[0] = left_edge[0] + dds[0] * 0.5
+            for i in range(ind[0][0], ind[0][1]):
+                pos[1] = left_edge[1] + dds[1] * 0.5
+                for j in range(ind[1][0], ind[1][1]):
+                    pos[2] = left_edge[2] + dds[2] * 0.5
+                    for k in range(ind[2][0], ind[2][1]):
+                        if child_mask[i,j,k] == 1 or this_level == 1:
+                            count += self.select_cell(pos, dds)
+                        pos[2] += dds[1]
+                    pos[1] += dds[1]
+                pos[0] += dds[0]
         return count
 
     @cython.boundscheck(False)
@@ -361,12 +340,7 @@
             ind[i][0] = 0
             ind[i][1] = gobj.ActiveDimensions[i]
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
-        cdef int check = 1
         cdef int total = 0
-        cdef int eterm[3]
-        self.set_bounds(<np.float64_t *> left_edge.data,
-                        <np.float64_t *> right_edge.data,
-                        dds, ind, &check)
         cdef int temp
         # Check for the level bounds
         cdef np.int32_t level = gobj.Level
@@ -377,40 +351,21 @@
         if level == self.max_level:
             this_level = 1
         with nogil:
-            if check == 1:
-                pos[0] = left_edge[0] + dds[0] * 0.5
-                for i in range(ind[0][0], ind[0][1]):
-                    eterm[0] = 0
-                    pos[1] = left_edge[1] + dds[1] * 0.5
-                    for j in range(ind[1][0], ind[1][1]):
-                        eterm[1] = 0
-                        pos[2] = left_edge[2] + dds[2] * 0.5
-                        for k in range(ind[2][0], ind[2][1]):
-                            eterm[2] = 0
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = self.select_cell(pos, dds, eterm)
-                                total += mask[i,j,k]
-                            if eterm[2] == 1: break
-                            pos[2] += dds[1]
-                        if eterm[1] == 1: break
-                        pos[1] += dds[1]
-                    if eterm[0] == 1: break
-                    pos[0] += dds[0]
-            else:
-                for i in range(ind[0][0], ind[0][1]):
-                    for j in range(ind[1][0], ind[1][1]):
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = 1
+            pos[0] = left_edge[0] + dds[0] * 0.5
+            for i in range(ind[0][0], ind[0][1]):
+                pos[1] = left_edge[1] + dds[1] * 0.5
+                for j in range(ind[1][0], ind[1][1]):
+                    pos[2] = left_edge[2] + dds[2] * 0.5
+                    for k in range(ind[2][0], ind[2][1]):
+                        if child_mask[i,j,k] == 1 or this_level == 1:
+                            mask[i,j,k] = self.select_cell(pos, dds)
                             total += mask[i,j,k]
+                        pos[2] += dds[1]
+                    pos[1] += dds[1]
+                pos[0] += dds[0]
         if total == 0: return None
         return mask.astype("bool")
 
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        return
-
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -494,8 +449,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         # sphere center either inside cell or center of cell lies inside sphere
         if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
             pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
@@ -591,71 +545,45 @@
                     RE[i] = right_edge[i] + self.domain_width[i] * (shift - 1)
                     if LE[i] >= self.right_edge[i]: continue
                     if RE[i] <= self.left_edge[i]: continue
-                    included += 1
+                    included = 1
+                    break
                 if included == 0: return 0
         return 1
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef int i, shift, included
-        cdef np.float64_t dxp, ppos[3]
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        cdef int i
+        cdef np.float64_t LE[3], RE[3]
+        if self.dx_pad == 0.0:
+            return self.select_point(pos)
         for i in range(3):
-            dxp = self.dx_pad * dds[i]
-            if self.periodicity[i] == 0:
-                if pos[i] - dxp >= self.right_edge[i]: return 0
-                if pos[i] + dxp <= self.left_edge[i]: return 0
-            else:
-                included = 0
-                for shift in range(3):
-                    ppos[i] = pos[i] + self.domain_width[i] * (shift - 1)
-                    if ppos[i] - dxp >= self.right_edge[i]: continue
-                    if ppos[i] + dxp <= self.left_edge[i]: continue
-                    included = 1
-                if included == 0: return 0
-        return 1
+            LE[i] = pos[i] - self.dx_pad * dds[i]
+            RE[i] = pos[i] + self.dx_pad * dds[i]
+        return self.select_bbox(LE, RE)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_point(self, np.float64_t pos[3]) nogil:
         # assume pos[3] is inside domain
-        cdef int i
-        for i in range(3) :
-            if pos[i] < self.left_edge[i] or \
-                    pos[i] >= self.right_edge[i] :
-                return 0
+        cdef int i, shift, included
+        cdef np.float64_t dxp, ppos[3]
+        for i in range(3):
+            if self.periodicity[i] == 0:
+                if pos[i] < self.left_edge[i]: return 0
+                if pos[i] >= self.right_edge[i]: return 0
+            else:
+                included = 0
+                for shift in range(3):
+                    ppos[i] = pos[i] + self.domain_width[i] * (shift - 1)
+                    if ppos[i] < self.left_edge[i]: continue
+                    if ppos[i] >= self.right_edge[i]: continue
+                    included = 1
+                if included == 0: return 0
         return 1
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int temp, i, all_inside
-        # Left pos is left_edge + 0.5 * dds
-        # This means the grid is fully within the region
-        # Note vice versa!
-        all_inside = 1 
-        for i in range(3):
-            # If the region starts after the grid does...
-            if self.left_edge[i] > left_edge[i]:
-                temp = <int> ((self.left_edge[i] - left_edge[i])/dds[i]) - 1
-                #ind[i][0] = iclip(temp, ind[i][0], ind[i][1])
-                all_inside = 0
-            # If the region ends before the grid does...
-            if self.right_edge[i] < right_edge[i]:
-                temp = <int> ((self.right_edge[i] - left_edge[i])/dds[i]) + 1
-                #ind[i][1] = iclip(temp, ind[i][0], ind[i][1])
-                all_inside = 0
-        if all_inside == 0:
-            check[0] = 1
-        else:
-            check[0] = 0
-
 region_selector = RegionSelector
 
 cdef class DiskSelector(SelectorObject):
@@ -684,8 +612,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return self.select_point( pos ) 
 
     @cython.boundscheck(False)
@@ -789,8 +716,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         cdef np.float64_t left_edge[3]
         cdef np.float64_t right_edge[3]
         cdef int i
@@ -862,19 +788,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int i
-        for i in range(3):
-            if self.axis == i:
-                ind[i][0] = <int> ((self.coord - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-        check[0] = 0
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
@@ -883,8 +796,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if pos[self.axis] + 0.5*dds[self.axis] > self.coord \
            and pos[self.axis] - 0.5*dds[self.axis] <= self.coord:
             return 1
@@ -940,8 +852,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
            self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
            self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax] and \
@@ -973,22 +884,6 @@
             return 1
         return 0
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int i
-        for i in range(3):
-            if self.px_ax == i:
-                ind[i][0] = <int> ((self.px - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-            elif self.py_ax == i:
-                ind[i][0] = <int> ((self.py - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-        check[0] = 0
-
 ortho_ray_selector = OrthoRaySelector
 
 cdef struct IntegrationAccumulator:
@@ -1168,15 +1063,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1233,8 +1119,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return self.select_point(pos)
 
     @cython.boundscheck(False)
@@ -1302,15 +1187,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1335,8 +1211,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil:
@@ -1359,15 +1234,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1377,8 +1243,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],
@@ -1410,15 +1275,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1428,8 +1284,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],
@@ -1449,15 +1304,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1469,8 +1315,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],


https://bitbucket.org/yt_analysis/yt-3.0/commits/86d2add0210d/
Changeset:   86d2add0210d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-27 23:06:36
Summary:     Simplifying ind[] logic since set_bounds no longer exists.
Affected #:  1 file

diff -r 3b3cb646c88a3faeffa5233c5d8aa464aed985ce -r 86d2add0210db947e3e144df84193c7ecec75393 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -293,11 +293,10 @@
         cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         cdef np.float64_t dds[3], pos[3]
-        cdef int i, j, k, ind[3][2]
+        cdef int i, j, k, dim[3]
         child_mask = gobj.child_mask
         for i in range(3):
-            ind[i][0] = 0
-            ind[i][1] = gobj.ActiveDimensions[i]
+            dim[i] = gobj.ActiveDimensions[i]
             dds[i] = odds[i]
         cdef int count = 0
         # Check for the level bounds
@@ -310,11 +309,11 @@
             this_level = 1
         with nogil:
             pos[0] = left_edge[0] + dds[0] * 0.5
-            for i in range(ind[0][0], ind[0][1]):
+            for i in range(dim[0]):
                 pos[1] = left_edge[1] + dds[1] * 0.5
-                for j in range(ind[1][0], ind[1][1]):
+                for j in range(dim[1]):
                     pos[2] = left_edge[2] + dds[2] * 0.5
-                    for k in range(ind[2][0], ind[2][1]):
+                    for k in range(dim[2]):
                         if child_mask[i,j,k] == 1 or this_level == 1:
                             count += self.select_cell(pos, dds)
                         pos[2] += dds[1]
@@ -330,6 +329,7 @@
         child_mask = gobj.child_mask
         cdef np.ndarray[np.uint8_t, ndim=3] mask 
         cdef int ind[3][2]
+        cdef int dim[3]
         cdef np.ndarray[np.float64_t, ndim=1] odds = gobj.dds
         cdef np.ndarray[np.float64_t, ndim=1] left_edge = gobj.LeftEdge
         cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
@@ -337,8 +337,7 @@
         cdef np.float64_t dds[3], pos[3]
         for i in range(3):
             dds[i] = odds[i]
-            ind[i][0] = 0
-            ind[i][1] = gobj.ActiveDimensions[i]
+            dim[i] = gobj.ActiveDimensions[i]
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
         cdef int total = 0
         cdef int temp
@@ -352,11 +351,11 @@
             this_level = 1
         with nogil:
             pos[0] = left_edge[0] + dds[0] * 0.5
-            for i in range(ind[0][0], ind[0][1]):
+            for i in range(dim[0]):
                 pos[1] = left_edge[1] + dds[1] * 0.5
-                for j in range(ind[1][0], ind[1][1]):
+                for j in range(dim[1]):
                     pos[2] = left_edge[2] + dds[2] * 0.5
-                    for k in range(ind[2][0], ind[2][1]):
+                    for k in range(dim[2]):
                         if child_mask[i,j,k] == 1 or this_level == 1:
                             mask[i,j,k] = self.select_cell(pos, dds)
                             total += mask[i,j,k]


https://bitbucket.org/yt_analysis/yt-3.0/commits/fe583dd3f5cd/
Changeset:   fe583dd3f5cd
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 00:08:40
Summary:     Fixing LE/RE checks and a mask->bool change.

VorticityStretching test now passes.
Affected #:  1 file

diff -r 86d2add0210db947e3e144df84193c7ecec75393 -r fe583dd3f5cd6ab51c8ad027bfeeae79e748b1c2 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -344,7 +344,7 @@
         # Check for the level bounds
         cdef np.int32_t level = gobj.Level
         if level < self.min_level or level > self.max_level:
-            return mask
+            return mask.astype("bool")
         # We set this to 1 if we ignore child_mask
         cdef int this_level = 0
         if level == self.max_level:
@@ -532,20 +532,19 @@
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil:
         cdef int i, shift, included
-        cdef np.float64_t LE[3], RE[3]
+        cdef np.float64_t LE, RE
         for i in range(3):
-            if self.periodicity[i] == 0:
-                if left_edge[i] >= self.right_edge[i]: return 0
-                if right_edge[i] <= self.left_edge[i]: return 0
+            if not self.periodicity[i]:
+                if left_edge[i] > self.right_edge[i]: return 0
+                if right_edge[i] < self.left_edge[i]: return 0
             else:
-                included = 0
+                included = 1
                 for shift in range(3):
-                    LE[i] = left_edge[i] + self.domain_width[i] * (shift - 1)
-                    RE[i] = right_edge[i] + self.domain_width[i] * (shift - 1)
-                    if LE[i] >= self.right_edge[i]: continue
-                    if RE[i] <= self.left_edge[i]: continue
+                    LE = left_edge[i] + self.domain_width[i] * (shift - 1)
+                    RE = right_edge[i] + self.domain_width[i] * (shift - 1)
+                    if LE > self.right_edge[i]: continue
+                    if RE < self.left_edge[i]: continue
                     included = 1
-                    break
                 if included == 0: return 0
         return 1
 
@@ -568,17 +567,17 @@
     cdef int select_point(self, np.float64_t pos[3]) nogil:
         # assume pos[3] is inside domain
         cdef int i, shift, included
-        cdef np.float64_t dxp, ppos[3]
+        cdef np.float64_t dxp, ppos
         for i in range(3):
-            if self.periodicity[i] == 0:
+            if not self.periodicity[i]:
                 if pos[i] < self.left_edge[i]: return 0
-                if pos[i] >= self.right_edge[i]: return 0
+                if pos[i] > self.right_edge[i]: return 0
             else:
                 included = 0
                 for shift in range(3):
-                    ppos[i] = pos[i] + self.domain_width[i] * (shift - 1)
-                    if ppos[i] < self.left_edge[i]: continue
-                    if ppos[i] >= self.right_edge[i]: continue
+                    ppos = pos[i] + self.domain_width[i] * (shift - 1)
+                    if ppos < self.left_edge[i]: continue
+                    if ppos > self.right_edge[i]: continue
                     included = 1
                 if included == 0: return 0
         return 1


https://bitbucket.org/yt_analysis/yt-3.0/commits/c5ec4a7b568d/
Changeset:   c5ec4a7b568d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 00:24:03
Summary:     Removing references to 'tot'
Affected #:  1 file

diff -r fe583dd3f5cd6ab51c8ad027bfeeae79e748b1c2 -r c5ec4a7b568d5a6a7b1b72524d451f587a2410f8 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -501,7 +501,7 @@
                     * self.pf.refine_by**self.level
         for chunk in self._data_source.chunks(fields, "io"):
             input_fields = [chunk[field] for field in fields]
-            tot += fill_region(input_fields, output_fields, self.level,
+            fill_region(input_fields, output_fields, self.level,
                         self.global_startindex, chunk.icoords, chunk.ires,
                         domain_dims, self.pf.refine_by)
         for name, v in zip(fields, output_fields):
@@ -656,15 +656,14 @@
     def _fill_fields(self, fields):
         ls = self._initialize_level_state(fields)
         for level in range(self.level + 1):
-            tot = 0
             domain_dims = self.pf.domain_dimensions.astype("int64") \
                         * self.pf.refine_by**level
             for chunk in ls.data_source.chunks(fields, "io"):
                 chunk[fields[0]]
                 input_fields = [chunk[field] for field in fields]
-                tot += fill_region(input_fields, ls.fields, ls.current_level,
-                                ls.global_startindex, chunk.icoords,
-                                chunk.ires, domain_dims, self.pf.refine_by)
+                fill_region(input_fields, ls.fields, ls.current_level,
+                            ls.global_startindex, chunk.icoords,
+                            chunk.ires, domain_dims, self.pf.refine_by)
             self._update_level_state(ls)
         for name, v in zip(fields, ls.fields):
             if self.level > 0: v = v[1:-1,1:-1,1:-1]


https://bitbucket.org/yt_analysis/yt-3.0/commits/f667a4827c4c/
Changeset:   f667a4827c4c
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 00:42:57
Summary:     Update fill_region tests for new API.
Affected #:  2 files

diff -r c5ec4a7b568d5a6a7b1b72524d451f587a2410f8 -r f667a4827c4ccd6af263b170be232cbdfc4e0a4c yt/utilities/lib/misc_utilities.pyx
--- a/yt/utilities/lib/misc_utilities.pyx
+++ b/yt/utilities/lib/misc_utilities.pyx
@@ -544,7 +544,7 @@
                 np.ndarray[np.int64_t, ndim=1] left_index,
                 np.ndarray[np.int64_t, ndim=2] ipos,
                 np.ndarray[np.int64_t, ndim=1] ires,
-                np.ndarray[np.int64_t] level_dims,
+                np.ndarray[np.int64_t, ndim=1] level_dims,
                 np.int64_t refine_by = 2
                 ):
     cdef int i, n

diff -r c5ec4a7b568d5a6a7b1b72524d451f587a2410f8 -r f667a4827c4ccd6af263b170be232cbdfc4e0a4c yt/utilities/lib/tests/test_fill_region.py
--- a/yt/utilities/lib/tests/test_fill_region.py
+++ b/yt/utilities/lib/tests/test_fill_region.py
@@ -21,8 +21,9 @@
         ipos[:,1] = ind[1].ravel()
         ipos[:,2] = ind[2].ravel()
         ires = np.zeros(NDIM*NDIM*NDIM, "int64")
+        ddims = np.array([NDIM, NDIM, NDIM], dtype="int64") * rf
         fill_region(input_fields, output_fields, level,
-                    left_index, ipos, ires)
+                    left_index, ipos, ires, ddims, 2)
         for r in range(level + 1):
             for o, i in zip(output_fields, v):
                 assert_equal( o[r::rf,r::rf,r::rf], i)


https://bitbucket.org/yt_analysis/yt-3.0/commits/4fe8b6e0dd2e/
Changeset:   4fe8b6e0dd2e
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 01:06:37
Summary:     Converting Ellipsoid tests to give more information.
Affected #:  1 file

diff -r f667a4827c4ccd6af263b170be232cbdfc4e0a4c -r 4fe8b6e0dd2e57b5d8337bfc2785c300d3502e6c yt/data_objects/tests/test_ellipsoid.py
--- a/yt/data_objects/tests/test_ellipsoid.py
+++ b/yt/data_objects/tests/test_ellipsoid.py
@@ -26,10 +26,10 @@
                 e0 = e0s[:,i]
                 tilt = tilts[i]
                 ell = pf.h.ellipsoid(c, A, B, C, e0, tilt)
-                yield assert_equal, np.all(ell["Radius"] <= A), True
+                yield assert_array_less, ell["Radius"], A
                 p = np.array([ell[ax] for ax in 'xyz'])
                 v  = np.zeros_like(ell["Radius"])
                 v += (((p - c[:,None]) * ell._e0[:,None]).sum(axis=0) / ell._A)**2
                 v += (((p - c[:,None]) * ell._e1[:,None]).sum(axis=0) / ell._B)**2
                 v += (((p - c[:,None]) * ell._e2[:,None]).sum(axis=0) / ell._C)**2
-                yield assert_equal, np.all(np.sqrt(v) <= 1.0), True
+                yield assert_array_less, np.sqrt(v), 1.0


https://bitbucket.org/yt_analysis/yt-3.0/commits/b17bd07c2f8e/
Changeset:   b17bd07c2f8e
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 01:49:19
Summary:     Match behavior in the Selector (which *is* periodic) in the tests.
Affected #:  1 file

diff -r 4fe8b6e0dd2e57b5d8337bfc2785c300d3502e6c -r b17bd07c2f8e44417695144aea92be8df605c723 yt/data_objects/tests/test_ellipsoid.py
--- a/yt/data_objects/tests/test_ellipsoid.py
+++ b/yt/data_objects/tests/test_ellipsoid.py
@@ -5,13 +5,23 @@
     ytcfg["yt","loglevel"] = "50"
     ytcfg["yt","__withintesting"] = "True"
 
+def _difference(x1, x2, dw):
+    rel = x1 - x2
+    rel[rel >  dw/2.0] -= dw
+    rel[rel < -dw/2.0] += dw
+    return rel
+
 def test_ellipsoid():
     # We decompose in different ways
-    cs = [np.array([0.5, 0.5, 0.5]),
+    cs = [
+          np.array([0.5, 0.5, 0.5]),
           np.array([0.1, 0.2, 0.3]),
-          np.array([0.8, 0.8, 0.8])]
+          np.array([0.8, 0.8, 0.8])
+          ]
+    np.random.seed(int(0x4d3d3d3))
     for nprocs in [1, 2, 4, 8]:
         pf = fake_random_pf(64, nprocs = nprocs)
+        DW = pf.domain_right_edge - pf.domain_left_edge
         min_dx = 2.0/pf.domain_dimensions
         ABC = np.random.random((3, 12)) * 0.1
         e0s = np.random.random((3, 12))
@@ -28,8 +38,15 @@
                 ell = pf.h.ellipsoid(c, A, B, C, e0, tilt)
                 yield assert_array_less, ell["Radius"], A
                 p = np.array([ell[ax] for ax in 'xyz'])
-                v  = np.zeros_like(ell["Radius"])
-                v += (((p - c[:,None]) * ell._e0[:,None]).sum(axis=0) / ell._A)**2
-                v += (((p - c[:,None]) * ell._e1[:,None]).sum(axis=0) / ell._B)**2
-                v += (((p - c[:,None]) * ell._e2[:,None]).sum(axis=0) / ell._C)**2
-                yield assert_array_less, np.sqrt(v), 1.0
+                dot_evec = [np.zeros_like(ell["Radius"]) for i in range(3)]
+                vecs = [ell._e0, ell._e1, ell._e2]
+                mags = [ell._A, ell._B, ell._C]
+                my_c = np.array([c]*p.shape[1]).transpose()
+                for ax_i in range(3):
+                    dist = _difference(p[ax_i,:], my_c[ax_i,:], DW[ax_i])
+                    for ax_j in range(3):
+                        dot_evec[ax_j] += dist * vecs[ax_j][ax_i]
+                dist = 0
+                for ax_i in range(3):
+                    dist += dot_evec[ax_i]**2.0 / mags[ax_i]**2.0
+                yield assert_array_less, dist, 1.0


https://bitbucket.org/yt_analysis/yt-3.0/commits/bb6b0bdb90bc/
Changeset:   bb6b0bdb90bc
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 05:03:49
Summary:     Switching usage of id(selector) to hash(selector) and implement _hash_vals.

New SelectorObjects need to implement _hash_vals() methods that unambiguously
refer to the object.  Note that these do *not* include information about the
parameter file.
Affected #:  4 files

diff -r b17bd07c2f8e44417695144aea92be8df605c723 -r bb6b0bdb90bc438e03fd0cff10193c9ce73fdd53 yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -493,11 +493,11 @@
         return vals.reshape(self.ActiveDimensions, order="C")
 
     def _get_selector_mask(self, selector):
-        if id(selector) == self._last_selector_id:
+        if hash(selector) == self._last_selector_id:
             mask = self._last_mask
         else:
             self._last_mask = mask = selector.fill_mask(self)
-            self._last_selector_id = id(selector)
+            self._last_selector_id = hash(selector)
             if mask is None:
                 self._last_count = 0
             else:

diff -r b17bd07c2f8e44417695144aea92be8df605c723 -r bb6b0bdb90bc438e03fd0cff10193c9ce73fdd53 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -162,7 +162,7 @@
         return n
 
     def count(self, selector):
-        if id(selector) == self._last_selector_id:
+        if hash(selector) == self._last_selector_id:
             if self._last_mask is None: return 0
             return self._last_mask.sum()
         self.select(selector)

diff -r b17bd07c2f8e44417695144aea92be8df605c723 -r bb6b0bdb90bc438e03fd0cff10193c9ce73fdd53 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -426,6 +426,21 @@
         if count == 0: return None
         return mask.astype("bool")
 
+    def __hash__(self):
+        return hash(self._hash_vals() + self._base_hash())
+
+    def _hash_vals(self):
+        raise NotImplementedError
+
+    def _base_hash(self):
+        return (self.min_level, self.max_level, self.overlap_cells,
+                self.periodicity[0],
+                self.periodicity[1],
+                self.periodicity[2],
+                self.domain_width[0],
+                self.domain_width[1],
+                self.domain_width[2])
+
 cdef class SphereSelector(SelectorObject):
     cdef np.float64_t radius
     cdef np.float64_t radius2
@@ -503,6 +518,10 @@
         if dist <= self.radius2: return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.radius, self.radius2,
+                self.center[0], self.center[1], self.center[2])
+
 sphere_selector = SphereSelector
 
 cdef class RegionSelector(SelectorObject):
@@ -582,6 +601,11 @@
                 if included == 0: return 0
         return 1
 
+    def _hash_vals(self):
+        return (self.left_edge[0], self.left_edge[1], self.left_edge[2],
+                self.right_edge[0], self.right_edge[1], self.right_edge[2],
+                self.dx_pad)
+
 region_selector = RegionSelector
 
 cdef class DiskSelector(SelectorObject):
@@ -691,6 +715,11 @@
         if all_over == 0 and all_under == 0 and any_radius == 1: return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.norm_vec[0], self.norm_vec[1], self.norm_vec[2],
+                self.center[0], self.center[1], self.center[2],
+                self.radius, self.radius2, self.height)
+
 disk_selector = DiskSelector
 
 cdef class CuttingPlaneSelector(SelectorObject):
@@ -773,6 +802,10 @@
             return 0
         return 1
 
+    def _hash_vals(self):
+        return (self.norm_vec[0], self.norm_vec[1], self.norm_vec[2],
+                self.d)
+
 cutting_selector = CuttingPlaneSelector
 
 cdef class SliceSelector(SelectorObject):
@@ -822,6 +855,9 @@
             return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.axis, self.coord)
+
 slice_selector = SliceSelector
 
 cdef class OrthoRaySelector(SelectorObject):
@@ -882,6 +918,9 @@
             return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.px_ax, self.py_ax, self.px, self.py, self.axis)
+
 ortho_ray_selector = OrthoRaySelector
 
 cdef struct IntegrationAccumulator:
@@ -1048,6 +1087,11 @@
                     return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.p1[0], self.p1[1], self.p1[2],
+                self.p2[0], self.p2[1], self.p2[2],
+                self.vec[0], self.vec[1], self.vec[2])
+
 ray_selector = RaySelector
 
 cdef class DataCollectionSelector(SelectorObject):
@@ -1088,6 +1132,9 @@
         mask = np.ones(gobj.ActiveDimensions, dtype='uint8')
         return mask.astype("bool")
 
+    def _hash_vals(self):
+        return (hash(self.obj_ids.tostring()), self.nids)
+
 data_collection_selector = DataCollectionSelector
 
 cdef class EllipsoidSelector(SelectorObject):
@@ -1174,6 +1221,13 @@
         if dist <= self.mag[0]**2: return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.vec[0][0], self.vec[0][1], self.vec[0][2],
+                self.vec[1][0], self.vec[1][1], self.vec[1][2],
+                self.vec[2][0], self.vec[2][1], self.vec[2][2],
+                self.mag[0], self.mag[1], self.mag[2],
+                self.center[0], self.center[1], self.center[2])
+
 ellipsoid_selector = EllipsoidSelector
 
 cdef class GridSelector(SelectorObject):
@@ -1216,6 +1270,9 @@
         # we apparently don't check if the point actually lies in the grid..
         return 1
 
+    def _hash_vals(self):
+        return (self.ind,)
+
 grid_selector = GridSelector
 
 cdef class OctreeSubsetSelector(SelectorObject):
@@ -1254,6 +1311,9 @@
         if res == 1 and o != NULL and o.domain != self.domain_id:
             return -1
         return res
+    
+    def _hash_vals(self):
+        return (hash(self.base_selector), self.domain_id)
 
 octree_subset_selector = OctreeSubsetSelector
 
@@ -1291,6 +1351,9 @@
         # Because visitors now use select_grid, we should be explicitly
         # checking this.
         return self.base_selector.select_grid(left_edge, right_edge, level, o)
+    
+    def _hash_vals(self):
+        return (hash(self.base_selector), self.min_ind, self.max_ind)
 
 particle_octree_subset_selector = ParticleOctreeSubsetSelector
 
@@ -1331,4 +1394,7 @@
                                np.float64_t right_edge[3]) nogil:
         return 1
 
+    def _hash_vals(self):
+        return ("always", 1,)
+
 always_selector = AlwaysSelector

diff -r b17bd07c2f8e44417695144aea92be8df605c723 -r bb6b0bdb90bc438e03fd0cff10193c9ce73fdd53 yt/utilities/tests/test_selectors.py
--- a/yt/utilities/tests/test_selectors.py
+++ b/yt/utilities/tests/test_selectors.py
@@ -93,10 +93,11 @@
     assert(all(pf.periodicity))
 
     for i,d in enumerate('xyz'):
-        for coord in np.arange(0,1.0,0.1):
+        for coord in np.arange(0.0,1.0,0.1):
             data = pf.h.slice(i, coord)
             data.get_data()
-            assert(data.shape[0] == 64**2)
+            yield assert_equal, data.shape[0], 64**2
+            yield assert_equal, data["Ones"].shape[0], 64**2
             yield assert_array_less, np.abs(data[d] - coord), 1./128.+1e-6
 
 def test_cutting_plane_selector():


https://bitbucket.org/yt_analysis/yt-3.0/commits/d3914f60a628/
Changeset:   d3914f60a628
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 07:34:28
Summary:     Adding in select_bbox, select_point routines for octree subsets.
Affected #:  1 file

diff -r bb6b0bdb90bc438e03fd0cff10193c9ce73fdd53 -r d3914f60a62865c033cef7547467d9bef453df93 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -1301,6 +1301,22 @@
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return self.base_selector.select_bbox(left_edge, right_edge)
+    
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                          np.float64_t right_edge[3], np.int32_t level,
                          Oct *o = NULL) nogil:
@@ -1345,6 +1361,19 @@
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return self.base_selector.select_bbox(left_edge, right_edge)
+    
     cdef int select_grid(self, np.float64_t left_edge[3],
                          np.float64_t right_edge[3], np.int32_t level,
                          Oct *o = NULL) nogil:


https://bitbucket.org/yt_analysis/yt-3.0/commits/b95e8f2a3c0e/
Changeset:   b95e8f2a3c0e
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-28 07:35:02
Summary:     Adding select_sphere for OctreeSubset selectors.
Affected #:  1 file

diff -r d3914f60a62865c033cef7547467d9bef453df93 -r b95e8f2a3c0e10f8b10c60b606886c54523a9df9 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -1298,6 +1298,12 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
@@ -1358,6 +1364,12 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/07a9034ce92c/
Changeset:   07a9034ce92c
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-07-29 23:01:23
Summary:     This applies the patch listed in paste 3709.

Note that this does not necessarily mean we *must* use this implementation.  I
have isolated this commit to enable easy rollback.  However, this now works out
of the box for testing spatial support.
Affected #:  1 file

diff -r ecc2c63f54cbd6b4087f3cc53445e219d45d4c5f -r 07a9034ce92ccf59c473b9e33cad9f3bde33dcf1 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -103,8 +103,31 @@
         tr = dict((field, v) for field, v in zip(fields, tr))
         return tr
 
-    def fill_particles(self, field_data, fields):
-        raise NotImplementedError
+    def fill_particles(self, field_data, fields, selector):
+        art_fields = {}
+        for s, f in fields:
+            for i in range(self.pf.num_species):
+                if s == "all" or self.pf.particle_species[i] == yt_to_art[s]:
+                    if yt_to_art[f] in self.pf.particle_variables[i]:
+                        art_fields[(i, yt_to_art[f])] = 1
+
+        species_data = self.oct_handler.fill_sfc_particles(art_fields.keys())
+
+        for s, f in fields:
+            af = yt_to_art[f]
+            npart = sum(len(species_data[(i, af)])
+                     for i in range(self.pf.num_species)
+                     if s == "all"
+                     or self.pf.particle_species[i] == yt_to_art[s])
+
+            cp = len(field_data[(s, f)])
+            field_data[(s, f)].resize(cp + npart)
+            for i in range(self.pf.num_species):
+                if s == "all" or self.pf.particle_species[i] == yt_to_art[s]:
+                    npart = len(species_data[(i, yt_to_art[f])])
+                    field_data[(s, f)][cp:cp+npart] = \
+                        species_data[(i, yt_to_art[f])]
+                    cp += npart
 
 class ARTIOChunk(object):
 
@@ -267,15 +290,21 @@
                     all(dobj.right_edge == self.pf.domain_right_edge)
             except:
                 all_data = False
-
+            base_region = getattr(dobj, "base_region", dobj)
+            sfc_start = getattr(dobj, "sfc_start", None)
+            sfc_end = getattr(dobj, "sfc_end", None)
             if all_data:
                 mylog.debug("Selecting entire artio domain")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges_all()
+            elif sfc_start is not None and sfc_end is not None:
+                mylog.debug("Restricting to %s .. %s", sfc_start, sfc_end)
+                list_sfc_ranges = [(sfc_start, sfc_end)]
             else:
                 mylog.debug("Running selector on artio base grid")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges(
                     dobj.selector)
-            dobj._chunk_info = [ARTIOChunk(self.pf, start, end)
+            dobj._chunk_info = [ARTIOOctreeSubset(base_region,
+                                    start, end, self.pf)
                                 for (start, end) in list_sfc_ranges]
             mylog.info("Created %d chunks for ARTIO" % len(list_sfc_ranges))
         dobj._current_chunk = list(self._chunk_all(dobj))[0]
@@ -288,7 +317,7 @@
 
     def _chunk_all(self, dobj):
         oobjs = getattr(dobj._current_chunk, "objs", dobj._chunk_info)
-        yield YTDataChunk(dobj, "all", oobjs, self._data_size)
+        yield YTDataChunk(dobj, "all", oobjs, None)
 
     def _chunk_spatial(self, dobj, ngz):
         if ngz > 0:
@@ -296,16 +325,17 @@
         sobjs = getattr(dobj._current_chunk, "objs", dobj._chunk_info)
         # These are ARTIOChunk objects
         for i,og in enumerate(sobjs):
-            g = ARTIOOctreeSubset(dobj, og.sfc_start, og.sfc_end, self.pf)
             if ngz > 0:
-                g = g.retrieve_ghost_zones(ngz, [], smoothed=True)
+                g = og.retrieve_ghost_zones(ngz, [], smoothed=True)
+            else:
+                g = og
             yield YTDataChunk(dobj, "spatial", [g], None)
 
     def _chunk_io(self, dobj, cache = True):
         # _current_chunk is made from identify_base_chunk
         oobjs = getattr(dobj._current_chunk, "objs", dobj._chunk_info)
         for chunk in oobjs:
-            yield YTDataChunk(dobj, "io", [chunk], self._data_size,
+            yield YTDataChunk(dobj, "io", [chunk], None,
                               cache = cache)
 
     def _read_fluid_fields(self, fields, dobj, chunk=None):


https://bitbucket.org/yt_analysis/yt-3.0/commits/3704d8e94159/
Changeset:   3704d8e94159
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-13 16:52:52
Summary:     Initial attempt to apply selectors and simplify particle logic in ARTIO.
Affected #:  2 files

diff -r 07a9034ce92ccf59c473b9e33cad9f3bde33dcf1 -r 3704d8e9415903016dfd7c8959cc6e006972c340 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -103,31 +103,17 @@
         tr = dict((field, v) for field, v in zip(fields, tr))
         return tr
 
-    def fill_particles(self, field_data, fields, selector):
-        art_fields = {}
+    def fill_particles(self, fields):
+        art_fields = []
         for s, f in fields:
-            for i in range(self.pf.num_species):
-                if s == "all" or self.pf.particle_species[i] == yt_to_art[s]:
-                    if yt_to_art[f] in self.pf.particle_variables[i]:
-                        art_fields[(i, yt_to_art[f])] = 1
-
+            i = self.pf.particle_species.index(yt_to_art[s])
+            art_fields.append((i, yt_to_art[f]))
         species_data = self.oct_handler.fill_sfc_particles(art_fields.keys())
-
+        tr = defaultdict(dict)
         for s, f in fields:
-            af = yt_to_art[f]
-            npart = sum(len(species_data[(i, af)])
-                     for i in range(self.pf.num_species)
-                     if s == "all"
-                     or self.pf.particle_species[i] == yt_to_art[s])
-
-            cp = len(field_data[(s, f)])
-            field_data[(s, f)].resize(cp + npart)
-            for i in range(self.pf.num_species):
-                if s == "all" or self.pf.particle_species[i] == yt_to_art[s]:
-                    npart = len(species_data[(i, yt_to_art[f])])
-                    field_data[(s, f)][cp:cp+npart] = \
-                        species_data[(i, yt_to_art[f])]
-                    cp += npart
+            i = self.pf.particle_species.index(yt_to_art[s])
+            tr[s][f] = species_data.pop((i, yt_to_art[f]))
+        return species_data
 
 class ARTIOChunk(object):
 

diff -r 07a9034ce92ccf59c473b9e33cad9f3bde33dcf1 -r 3704d8e9415903016dfd7c8959cc6e006972c340 yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -44,12 +44,29 @@
         return tr
 
     def _read_particle_selection(self, chunks, selector, fields):
-        # TODO: determine proper datatype for fields
-        tr = dict((ftuple, np.empty(0, dtype='float32')) for ftuple in fields)
+        fd = dict((ftuple, []) for ftuple in fields)
+        ftypes = set(ftype for (ftype, fname) in fields)
+        for ftype in ftypes:
+            for ax in 'xyz':
+                ftuple = (ftype, "particle_position_%s" % ax)
+                if ftuple not in fd:
+                    fd[ftuple] = []
         for onechunk in chunks:
+            # We're going to read here
             for artchunk in onechunk.objs:
-                artchunk.fill_particles(tr, fields, selector)
-        for ftype, fname in tr.keys():
-            if fname == "particle_mass":
-                tr[ftype, fname] = tr[ftype, fname].astype("float64")
+                rv = artchunk.fill_particles(fd.keys())
+                # Now we count and also cut
+                for ftype in rv:
+                    mask = selector.select_points(
+                        rv[ftype]["particle_position_x"],
+                        rv[ftype]["particle_position_y"],
+                        rv[ftype]["particle_position_z"])
+                    if mask is None: continue
+                    for fname in rv[ftype]:
+                        if (ftype, fname) not in fields: continue
+                        tr[ftype, fname].append(rv[ftype][fname][mask])
+        for f in fd.keys():
+            n, v = fd.pop(f)
+            if f not in fields: continue
+            tr[f] = np.concatenate(v)
         return tr


https://bitbucket.org/yt_analysis/yt-3.0/commits/d2bc27e7524f/
Changeset:   d2bc27e7524f
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-13 17:31:39
Summary:     Fix lingering ARTIO issus with "all", which is no longer a special-case
definition.
Affected #:  4 files

diff -r 3704d8e9415903016dfd7c8959cc6e006972c340 -r d2bc27e7524f9637c6bac553207e9a14563aa359 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -108,12 +108,12 @@
         for s, f in fields:
             i = self.pf.particle_species.index(yt_to_art[s])
             art_fields.append((i, yt_to_art[f]))
-        species_data = self.oct_handler.fill_sfc_particles(art_fields.keys())
+        species_data = self.oct_handler.fill_sfc_particles(art_fields)
         tr = defaultdict(dict)
         for s, f in fields:
             i = self.pf.particle_species.index(yt_to_art[s])
             tr[s][f] = species_data.pop((i, yt_to_art[f]))
-        return species_data
+        return tr
 
 class ARTIOChunk(object):
 
@@ -256,11 +256,11 @@
     def _detect_particle_fields(self):
         fields = set()
         for ptype in self.pf.particle_types:
+            if ptype == "all": continue
             for f in yt_to_art.values():
                 if all(f in self.pf.particle_variables[i]
                        for i in range(self.pf.num_species)
-                       if ptype == "all"
-                       or art_to_yt[self.pf.particle_species[i]] == ptype):
+                       if art_to_yt[self.pf.particle_species[i]] == ptype):
                     fields.add((ptype, art_to_yt[f]))
         return list(fields)
 
@@ -349,6 +349,8 @@
     _hierarchy_class = ARTIOGeometryHandler
     _fieldinfo_fallback = ARTIOFieldInfo
     _fieldinfo_known = KnownARTIOFields
+    _particle_mass_name = "particle_mass"
+    _particle_coordinates_name = "Coordinates"
 
     def __init__(self, filename, data_style='artio',
                  storage_filename=None):

diff -r 3704d8e9415903016dfd7c8959cc6e006972c340 -r d2bc27e7524f9637c6bac553207e9a14563aa359 yt/frontends/artio/fields.py
--- a/yt/frontends/artio/fields.py
+++ b/yt/frontends/artio/fields.py
@@ -281,7 +281,8 @@
 
 for fname in ["particle_position_%s" % ax for ax in 'xyz'] + \
              ["particle_velocity_%s" % ax for ax in 'xyz'] + \
-             ["particle_index", "particle_species"]:
+             ["particle_index", "particle_species",
+              "particle_mass"]:
     func = _field_concat(fname)
     ARTIOFieldInfo.add_field(("all", fname), function=func,
             particle_type = True)

diff -r 3704d8e9415903016dfd7c8959cc6e006972c340 -r d2bc27e7524f9637c6bac553207e9a14563aa359 yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -64,9 +64,12 @@
                     if mask is None: continue
                     for fname in rv[ftype]:
                         if (ftype, fname) not in fields: continue
-                        tr[ftype, fname].append(rv[ftype][fname][mask])
+                        fd[ftype, fname].append(rv[ftype][fname][mask])
+        # This needs to be pre-initialized in case we are later concatenated.
+        tr = dict((ftuple, np.empty(0, dtype='float64')) for ftuple in fields)
         for f in fd.keys():
-            n, v = fd.pop(f)
+            v = fd.pop(f)
             if f not in fields: continue
+            if len(v) == 0: continue
             tr[f] = np.concatenate(v)
         return tr

diff -r 3704d8e9415903016dfd7c8959cc6e006972c340 -r d2bc27e7524f9637c6bac553207e9a14563aa359 yt/geometry/geometry_handler.py
--- a/yt/geometry/geometry_handler.py
+++ b/yt/geometry/geometry_handler.py
@@ -220,6 +220,7 @@
             for pt in self.parameter_file.particle_types:
                 new_fi = copy.copy(finfo)
                 new_fi.name = (pt, new_fi.name)
+                if new_fi.name in fi: continue
                 fi[new_fi.name] = new_fi
                 new_fields.append(new_fi.name)
             fields_to_check += new_fields


https://bitbucket.org/yt_analysis/yt-3.0/commits/2ab98bc9848d/
Changeset:   2ab98bc9848d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-13 17:37:42
Summary:     Force promotion to float64 of particle fields.
Affected #:  1 file

diff -r d2bc27e7524f9637c6bac553207e9a14563aa359 -r 2ab98bc9848deacf0e4d2a1809e283a6644940bb yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -291,10 +291,10 @@
             elif self.parameters["num_secondary_variables"][species] > 0 and \
                     field in self.parameters["species_%02u_secondary_variable_labels"%(species,)] :
                 selected_secondary[species].append((self.parameters["species_%02u_secondary_variable_labels"%(species,)].index(field),(species,field)))
-                data[(species,field)] = np.empty(0,dtype="float32")
+                data[(species,field)] = np.empty(0,dtype="float64")
             elif field == "MASS" :
                 selected_mass[species] = (species,field)
-                data[(species,field)] = np.empty(0,dtype="float32")
+                data[(species,field)] = np.empty(0,dtype="float64")
             elif field == "PID" :
                 selected_pid[species] = (species,field)
                 data[(species,field)] = np.empty(0,dtype="int64")
@@ -403,7 +403,7 @@
         ires = np.empty(0, dtype="int64")
 
         #data = [ np.empty(max_cells, dtype="float32") for i in range(num_fields) ]
-        data = [ np.empty(0,dtype="float32") for i in range(num_fields)]
+        data = [ np.empty(0,dtype="float64") for i in range(num_fields)]
 
         count = 0
         for sfc in range( sfc_start, sfc_end+1 ) :
@@ -539,14 +539,14 @@
     int s_ind[16] # Max of 16 vars
     # Pointers to the bools and data arrays for mass, pid and species
     int n_mass
-    np.float32_t *mass
+    np.float64_t *mass
     int n_pid
     np.int64_t *pid
     int n_species
     np.int8_t *species
     # Pointers to the pointers to primary and secondary vars
     np.float64_t *pvars[16]
-    np.float32_t *svars[16]
+    np.float64_t *svars[16]
 
 cdef class ARTIOOctreeContainer(SparseOctreeContainer):
     # This is a transitory, created-on-demand OctreeContainer.  It should not
@@ -790,7 +790,6 @@
 
         cdef np.ndarray[np.int8_t, ndim=1] npi8arr
         cdef np.ndarray[np.int64_t, ndim=1] npi64arr
-        cdef np.ndarray[np.float32_t, ndim=1] npf32arr
         cdef np.ndarray[np.float64_t, ndim=1] npf64arr
 
         # Now we set up our field pointers
@@ -845,10 +844,10 @@
             vp = &vpoints[species]
             if field == "MASS":
                 vp.n_mass = 1
-                npf32arr = data[(species, field)] = np.zeros(tp, dtype="float32")
+                npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
                 # We fill this *now*
-                npf32arr += params["particle_species_mass"][species]
-                vp.mass = <np.float32_t*> npf32arr.data
+                npf64arr += params["particle_species_mass"][species]
+                vp.mass = <np.float64_t*> npf64arr.data
             elif field == "PID":
                 vp.n_pid = 1
                 npi64arr = data[(species, field)] = np.zeros(tp, dtype="int64")
@@ -865,9 +864,9 @@
                 vp.pvars[vp.n_p] = <np.float64_t *> npf64arr.data
                 vp.n_p += 1
             elif nsec_vars[species] > 0 and field in sec_vars :
-                npf32arr = data[(species, field)] = np.zeros(tp, dtype="float32")
+                npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
                 vp.s_ind[vp.n_s] = sec_vars.index(field)
-                vp.svars[vp.n_s] = <np.float32_t *> npf32arr.data
+                vp.svars[vp.n_s] = <np.float64_t *> npf64arr.data
                 vp.n_s += 1
 
         for sfc in range(self.sfc_start, self.sfc_end + 1):


https://bitbucket.org/yt_analysis/yt-3.0/commits/6634b00b3c69/
Changeset:   6634b00b3c69
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-14 22:30:30
Summary:     Adding a check to set the field type if we need to guess it.
Affected #:  1 file

diff -r 2ab98bc9848deacf0e4d2a1809e283a6644940bb -r 6634b00b3c69bd26487ed5c346876296ac1e3c11 yt/data_objects/field_info_container.py
--- a/yt/data_objects/field_info_container.py
+++ b/yt/data_objects/field_info_container.py
@@ -276,6 +276,11 @@
             else:
                 field = item
             finfo = self.pf._get_field_info(*field)
+            # For those cases where we are guessing the field type, we will
+            # need to re-update -- otherwise, our item will always not have the
+            # field type.  This can lead to, for instance, "unknown" particle
+            # types not getting correctly identified.
+            item = self.pf._last_freq
         else:
             FI = getattr(self.pf, "field_info", FieldInfo)
             if item in FI:


https://bitbucket.org/yt_analysis/yt-3.0/commits/221bbbf705dc/
Changeset:   221bbbf705dc
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-14 22:31:00
Summary:     Clear up some particle type adding for ARTIO.

Note that this also includes changing add_field to add_artio_field for
particle_mass.
Affected #:  1 file

diff -r 6634b00b3c69bd26487ed5c346876296ac1e3c11 -r 221bbbf705dc23bd1c3bef2d2a507dc785827bf9 yt/frontends/artio/fields.py
--- a/yt/frontends/artio/fields.py
+++ b/yt/frontends/artio/fields.py
@@ -248,24 +248,23 @@
 ##################################################
 #Particle fields
 
-for ax in 'xyz':
-    pf = "particle_velocity_%s" % ax
-    add_artio_field(pf, function=NullFunc,
-                    particle_type=True)
+for ptype in ("nbody", "stars"):
+    for ax in 'xyz':
+        add_artio_field((ptype, "particle_velocity_%s" % ax),
+                        function=NullFunc,
+                        particle_type=True)
+        add_artio_field((ptype, "particle_position_%s" % ax),
+                        function=NullFunc,
+                        particle_type=True)
 
-for ax in 'xyz':
-    pf = "particle_position_%s" % ax
-    add_artio_field(pf, function=NullFunc,
-                    particle_type=True)
-
-def _convertParticleMass(data):
-    return np.float64(data.convert('particle_mass'))
-add_field("particle_mass",
-          function=NullFunc,
-          convert_function=_convertParticleMass,
-          units=r"\rm{g}",
-          particle_type=True)
-add_artio_field("particle_index", function=NullFunc, particle_type=True)
+    def _convertParticleMass(data):
+        return np.float64(data.convert('particle_mass'))
+    add_artio_field((ptype, "particle_mass"),
+              function=NullFunc,
+              convert_function=_convertParticleMass,
+              units=r"\rm{g}",
+              particle_type=True)
+    add_artio_field((ptype, "particle_index"), function=NullFunc, particle_type=True)
 
 #add_artio_field("creation_time", function=NullFunc, particle_type=True)
 def _particle_age(field, data):


https://bitbucket.org/yt_analysis/yt-3.0/commits/c41e6bb4cf1f/
Changeset:   c41e6bb4cf1f
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-14 22:52:18
Summary:     This enables correct dependency checking for particle filters.
Affected #:  1 file

diff -r 221bbbf705dc23bd1c3bef2d2a507dc785827bf9 -r c41e6bb4cf1fe63ac37bab386828597f443f0376 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -261,6 +261,10 @@
             raise YTGeometryNotSupported(self.geometry)
 
     def add_particle_filter(self, filter):
+        # This is a dummy, which we set up to enable passthrough of "all"
+        # concatenation fields.
+        n = getattr(filter, "name", filter)
+        self.known_filters[n] = None
         if isinstance(filter, types.StringTypes):
             used = False
             for f in filter_registry[filter]:
@@ -271,6 +275,7 @@
         else:
             used = self.h._setup_filtered_type(filter)
         if not used:
+            self.known_filters.pop(n, None)
             return False
         self.known_filters[filter.name] = filter
         return True


https://bitbucket.org/yt_analysis/yt-3.0/commits/864facfc4dd0/
Changeset:   864facfc4dd0
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-14 23:40:54
Summary:     ARTIO can have multiple species_id->species_name mappings for particles.

This re-enables the ability to have multiple species ids corresponding to, say,
an n-body dataset.
Affected #:  1 file

diff -r c41e6bb4cf1fe63ac37bab386828597f443f0376 -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -106,13 +106,29 @@
     def fill_particles(self, fields):
         art_fields = []
         for s, f in fields:
-            i = self.pf.particle_species.index(yt_to_art[s])
-            art_fields.append((i, yt_to_art[f]))
+            fn = yt_to_art[f]
+            for i in self.pf.particle_type_map[s]:
+                if fn in self.pf.particle_variables[i]:
+                    art_fields.append((i, fn))
         species_data = self.oct_handler.fill_sfc_particles(art_fields)
         tr = defaultdict(dict)
+        # Now we need to sum things up and then fill
         for s, f in fields:
-            i = self.pf.particle_species.index(yt_to_art[s])
-            tr[s][f] = species_data.pop((i, yt_to_art[f]))
+            count = 0
+            fn = yt_to_art[f]
+            dt = "float64" # default
+            for i in self.pf.particle_type_map[s]:
+                if (i, fn) not in species_data: continue
+                # No vector fields in ARTIO
+                count += species_data[i, fn].size
+                dt = species_data[i, fn].dtype
+            tr[s][f] = np.zeros(count, dtype=dt)
+            cp = 0
+            for i in self.pf.particle_type_map[s]:
+                if (i, fn) not in species_data: continue
+                v = species_data.pop((i, fn))
+                tr[s][f][cp:cp+v.size] = v
+                cp += v.size
         return tr
 
 class ARTIOChunk(object):
@@ -464,6 +480,12 @@
                                    for i in range(self.num_species)]
         self.particle_species =\
             self.artio_parameters["particle_species_labels"]
+        self.particle_type_map = {}
+        for i, s in enumerate(self.particle_species):
+            f = art_to_yt[s]
+            if f not in self.particle_type_map:
+                self.particle_type_map[f] = []
+            self.particle_type_map[f].append(i)
 
         for species in range(self.num_species):
             # Mass would be best as a derived field,


https://bitbucket.org/yt_analysis/yt-3.0/commits/1728ebb7cd28/
Changeset:   1728ebb7cd28
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-14 23:44:23
Summary:     Merging with main repository.
Affected #:  47 files

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,13 +12,16 @@
 yt/frontends/sph/smoothing_kernel.c
 yt/geometry/fake_octree.c
 yt/geometry/oct_container.c
+yt/geometry/oct_visitors.c
 yt/geometry/particle_deposit.c
+yt/geometry/particle_oct_container.c
 yt/geometry/selection_routines.c
 yt/utilities/amr_utils.c
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
 yt/utilities/lib/alt_ray_tracers.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/analysis_modules/halo_profiler/standard_analysis.py
--- a/yt/analysis_modules/halo_profiler/standard_analysis.py
+++ b/yt/analysis_modules/halo_profiler/standard_analysis.py
@@ -30,6 +30,7 @@
 
 class StandardRadialAnalysis(object):
     def __init__(self, pf, center, radius, n_bins = 128, inner_radius = None):
+        raise NotImplementedError  # see TODO
         self.pf = pf
         # We actually don't want to replicate the handling of setting the
         # center here, so we will pass it to the sphere creator.
@@ -53,6 +54,7 @@
         prof = BinnedProfile1D(self.obj, self.n_bins, "Radius",
                                self.inner_radius, self.outer_radius)
         by_weights = defaultdict(list)
+        # TODO: analysis_field_list is undefined
         for fspec in analysis_field_list:
             if isinstance(fspec, types.TupleType) and len(fspec) == 2:
                 field, weight = fspec

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/analyzer_objects.py
--- a/yt/data_objects/analyzer_objects.py
+++ b/yt/data_objects/analyzer_objects.py
@@ -80,7 +80,7 @@
 
     def eval(self, pf):
         slc = self.SlicePlot(pf, self.axis, self.field, center = self.center)
-        return pc.save()
+        return slc.save()
 
 class QuantityProxy(AnalysisTask):
     _params = None

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -36,6 +36,7 @@
 import fileinput
 from re import finditer
 
+from yt.config import ytcfg
 from yt.funcs import *
 from yt.utilities.logger import ytLogger
 from .data_containers import \
@@ -703,7 +704,7 @@
         new_fields = []
         for input_field in level_state.fields:
             output_field = np.zeros(output_dims, dtype="float64")
-            output_left = self.global_startindex + 0.5
+            output_left = level_state.global_startindex + 0.5
             ghost_zone_interpolate(rf, input_field, input_left,
                                    output_field, output_left)
             new_fields.append(output_field)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/field_info_container.py
--- a/yt/data_objects/field_info_container.py
+++ b/yt/data_objects/field_info_container.py
@@ -449,7 +449,7 @@
         dd['units'] = self._units
         dd['projected_units'] = self._projected_units,
         dd['take_log'] = self.take_log
-        dd['validators'] = self.validators.copy()
+        dd['validators'] = list(self.validators)
         dd['particle_type'] = self.particle_type
         dd['vector_field'] = self.vector_field
         dd['display_field'] = True

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -489,6 +489,7 @@
         op.initialize()
         op.process_grid(self, positions, fields)
         vals = op.finalize()
+        if vals is None: return
         return vals.reshape(self.ActiveDimensions, order="C")
 
     def select_blocks(self, selector):

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -135,6 +135,7 @@
         op.process_octree(self.oct_handler, self.domain_ind, pos, f64,
             self.domain_id, self._domain_offset)
         vals = op.finalize()
+        if vals is None: return
         return np.asfortranarray(vals)
 
     def select_icoords(self, dobj):

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/particle_fields.py
--- a/yt/data_objects/particle_fields.py
+++ b/yt/data_objects/particle_fields.py
@@ -137,6 +137,19 @@
             particle_type = True,
             units = r"\mathrm{M}_\odot")
 
+    def particle_mesh_ids(field, data):
+        pos = data[ptype, coord_name]
+        ids = np.zeros(pos.shape[0], dtype="float64") - 1
+        # This is float64 in name only.  It will be properly cast inside the
+        # deposit operation.
+        #_ids = ids.view("float64")
+        data.deposit(pos, [ids], method = "mesh_id")
+        return ids
+    registry.add_field((ptype, "mesh_id"),
+            function = particle_mesh_ids,
+            validators = [ValidateSpatial()],
+            particle_type = True)
+
     return list(set(registry.keys()).difference(orig))
 
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/profiles.py
--- a/yt/data_objects/profiles.py
+++ b/yt/data_objects/profiles.py
@@ -545,6 +545,8 @@
         self.total_stuff = source_data.sum()
         binned_field = self._get_empty_field()
         weight_field = self._get_empty_field()
+        m_field = self._get_empty_field()
+        q_field = self._get_empty_field()
         used_field = self._get_empty_field()
         mi = args[0]
         bin_indices_x = args[1][self.indices].ravel().astype('int64')
@@ -553,8 +555,8 @@
         weight_data = weight_data[mi][self.indices]
         nx = bin_indices_x.size
         #mylog.debug("Binning %s / %s times", source_data.size, nx)
-        Bin2DProfile(bin_indices_x, bin_indices_y, weight_data, source_data,
-                     weight_field, binned_field, used_field)
+        bin_profile2d(bin_indices_x, bin_indices_y, weight_data, source_data,
+                      weight_field, binned_field, m_field, q_field, used_field)
         if accumulation: # Fix for laziness
             if not iterable(accumulation):
                 raise SyntaxError("Accumulation needs to have length 2")

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -194,7 +194,7 @@
             ts = np.abs(ts)
         self._dts[grid.id] = dts
         self._ts[grid.id] = ts
-        self._masks[grid.id] = masks
+        self._masks[grid.id] = mask
         return mask
 
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/tests/test_fields.py
--- a/yt/data_objects/tests/test_fields.py
+++ b/yt/data_objects/tests/test_fields.py
@@ -98,4 +98,5 @@
         if fname.startswith("Overdensity"): continue
         if FieldInfo[field].particle_type: continue
         for nproc in [1, 4, 8]:
+            test_all_fields.__name__ = "%s_%s" % (field, nproc)
             yield TestFieldAccess(field, nproc)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -376,12 +376,6 @@
 add_field("DynamicalTime", function=_DynamicalTime,
            units=r"\rm{s}")
 
-def JeansMassMsun(field,data):
-    return (MJ_constant * 
-            ((data["Temperature"]/data["MeanMolecularWeight"])**(1.5)) *
-            (data["Density"]**(-0.5)))
-add_field("JeansMassMsun",function=JeansMassMsun,units=r"\rm{Msun}")
-
 def _CellMass(field, data):
     return data["Density"] * data["CellVolume"]
 def _convertCellMassMsun(data):
@@ -619,7 +613,7 @@
 def _convertSpecificAngularMomentum(data):
     return data.convert("cm")
 def _convertSpecificAngularMomentumKMSMPC(data):
-    return data.convert("mpc")/1e5
+    return km_per_cm*data.convert("mpc")
 
 def _SpecificAngularMomentumX(field, data):
     xv, yv, zv = obtain_velocities(data)
@@ -678,8 +672,6 @@
 #          function=_ParticleSpecificAngularMomentum, particle_type=True,
 #          convert_function=_convertSpecificAngularMomentum, vector_field=True,
 #          units=r"\rm{cm}^2/\rm{s}", validators=[ValidateParameter('center')])
-def _convertSpecificAngularMomentumKMSMPC(data):
-    return km_per_cm*data.convert("mpc")
 #add_field("ParticleSpecificAngularMomentumKMSMPC",
 #          function=_ParticleSpecificAngularMomentum, particle_type=True,
 #          convert_function=_convertSpecificAngularMomentumKMSMPC, vector_field=True,
@@ -909,7 +901,7 @@
     pos = pos - np.reshape(center, (3, 1))
     vel = vel - np.reshape(bv, (3, 1))
     spht = get_sph_theta_component(vel, theta, phi, normal)
-    return sphrt
+    return spht
 
 add_field("ParticleThetaVelocity", function=_ParticleThetaVelocity,
           particle_type=True, units=r"\rm{cm}/\rm{s}",
@@ -928,8 +920,8 @@
     phi = get_sph_phi(pos.copy(), center)
     pos = pos - np.reshape(center, (3, 1))
     vel = vel - np.reshape(bv, (3, 1))
-    sphp = get_sph_phi_component(vel, theta, phi, normal)
-    return sphrp
+    sphp = get_sph_phi_component(vel, phi, normal)
+    return sphp
 
 add_field("ParticlePhiVelocity", function=_ParticleThetaVelocity,
           particle_type=True, units=r"\rm{cm}/\rm{s}",

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/frontends/enzo/data_structures.py
--- a/yt/frontends/enzo/data_structures.py
+++ b/yt/frontends/enzo/data_structures.py
@@ -675,7 +675,7 @@
 
 class EnzoHierarchy1D(EnzoHierarchy):
 
-    def _fill_arrays(self, ei, si, LE, RE, npart):
+    def _fill_arrays(self, ei, si, LE, RE, npart, nap):
         self.grid_dimensions[:,:1] = ei
         self.grid_dimensions[:,:1] -= np.array(si, self.float_type)
         self.grid_dimensions += 1
@@ -685,10 +685,12 @@
         self.grid_left_edge[:,1:] = 0.0
         self.grid_right_edge[:,1:] = 1.0
         self.grid_dimensions[:,1:] = 1
+        if nap is not None:
+            raise NotImplementedError
 
 class EnzoHierarchy2D(EnzoHierarchy):
 
-    def _fill_arrays(self, ei, si, LE, RE, npart):
+    def _fill_arrays(self, ei, si, LE, RE, npart, nap):
         self.grid_dimensions[:,:2] = ei
         self.grid_dimensions[:,:2] -= np.array(si, self.float_type)
         self.grid_dimensions += 1
@@ -698,6 +700,8 @@
         self.grid_left_edge[:,2] = 0.0
         self.grid_right_edge[:,2] = 1.0
         self.grid_dimensions[:,2] = 1
+        if nap is not None:
+            raise NotImplementedError
 
 class EnzoStaticOutput(StaticOutput):
     """

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/frontends/enzo/io.py
--- a/yt/frontends/enzo/io.py
+++ b/yt/frontends/enzo/io.py
@@ -277,6 +277,33 @@
                         (grid.id, field)).transpose()
         return t
 
+    def _read_fluid_selection(self, chunks, selector, fields, size):
+        rv = {}
+        # Now we have to do something unpleasant
+        chunks = list(chunks)
+        if selector.__class__.__name__ == "GridSelector":
+            return self._read_grid_chunk(chunks, fields)
+        if any((ftype != "gas" for ftype, fname in fields)):
+            raise NotImplementedError
+        for field in fields:
+            ftype, fname = field
+            fsize = size
+            rv[field] = np.empty(fsize, dtype="float64")
+        ng = sum(len(c.objs) for c in chunks)
+        mylog.debug("Reading %s cells of %s fields in %s grids",
+                   size, [f2 for f1, f2 in fields], ng)
+        ind = 0
+        for chunk in chunks:
+            data = self._read_chunk_data(chunk, fields)
+            for g in chunk.objs:
+                for field in fields:
+                    ftype, fname = field
+                    ds = np.atleast_3d(data[g.id].pop(fname))
+                    nd = g.select(selector, ds, rv[field], ind)  # caches
+                ind += nd
+                data.pop(g.id)
+        return rv
+
 
 class IOHandlerPacked1D(IOHandlerPackedHDF5):
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/frontends/sph/data_structures.py
--- a/yt/frontends/sph/data_structures.py
+++ b/yt/frontends/sph/data_structures.py
@@ -28,6 +28,7 @@
 import stat
 import weakref
 import struct
+import glob
 from itertools import izip
 
 from yt.utilities.fortran_utils import read_record
@@ -46,6 +47,7 @@
     G, \
     gravitational_constant_cgs, \
     km_per_pc, \
+    cm_per_kpc, \
     mass_sun_cgs
 from yt.utilities.cosmology import Cosmology
 from .fields import \
@@ -107,11 +109,12 @@
         mpch = {}
         mpch.update(mpc_conversion)
         unit_base = self._unit_base or {}
-        for unit in mpc_conversion:
-            mpch['%sh' % unit] = mpch[unit] * self.hubble_constant
-            mpch['%shcm' % unit] = (mpch["%sh" % unit] / 
-                    (1 + self.current_redshift))
-            mpch['%scm' % unit] = mpch[unit] / (1 + self.current_redshift)
+        if self.cosmological_simulation:
+            for unit in mpc_conversion:
+                mpch['%sh' % unit] = mpch[unit] * self.hubble_constant
+                mpch['%shcm' % unit] = (mpch["%sh" % unit] /
+                                (1 + self.current_redshift))
+                mpch['%scm' % unit] = mpch[unit] / (1 + self.current_redshift)
         # ud == unit destination
         # ur == unit registry
         for ud, ur in [(self.units, mpch), (self.time_units, sec_conversion)]:
@@ -151,7 +154,8 @@
 
     def __init__(self, filename, data_style="gadget_binary",
                  additional_fields = (),
-                 unit_base = None):
+                 unit_base = None, n_ref = 64):
+        self.n_ref = n_ref
         self.storage_filename = None
         if unit_base is not None and "UnitLength_in_cm" in unit_base:
             # We assume this is comoving, because in the absence of comoving
@@ -264,10 +268,11 @@
     _particle_coordinates_name = "Coordinates"
     _header_spec = None # Override so that there's no confusion
 
-    def __init__(self, filename, data_style="OWLS"):
+    def __init__(self, filename, data_style="OWLS", n_ref = 64):
         self.storage_filename = None
         super(OWLSStaticOutput, self).__init__(filename, data_style,
-                                               unit_base = None)
+                                               unit_base = None,
+                                               n_ref = n_ref)
 
     def __repr__(self):
         return os.path.basename(self.parameter_filename).split(".")[0]
@@ -357,7 +362,10 @@
                  domain_left_edge = None,
                  domain_right_edge = None,
                  unit_base = None,
-                 cosmology_parameters = None):
+                 cosmology_parameters = None,
+                 parameter_file = None,
+                 n_ref = 64):
+        self.n_ref = n_ref
         self.endian = endian
         self.storage_filename = None
         if domain_left_edge is None:
@@ -375,6 +383,7 @@
 
         self._unit_base = unit_base or {}
         self._cosmology_parameters = cosmology_parameters
+        self._param_file = parameter_file
         super(TipsyStaticOutput, self).__init__(filename, data_style)
 
     def __repr__(self):
@@ -382,44 +391,74 @@
 
     def _parse_parameter_file(self):
 
-        # The entries in this header are capitalized and named to match Table 4
-        # in the GADGET-2 user guide.
+        # Parsing the header of the tipsy file, from this we obtain
+        # the snapshot time and particle counts.
 
         f = open(self.parameter_filename, "rb")
         hh = self.endian + "".join(["%s" % (b) for a,b in self._header_spec])
         hvals = dict([(a, c) for (a, b), c in zip(self._header_spec,
                      struct.unpack(hh, f.read(struct.calcsize(hh))))])
+        self.parameters.update(hvals)
         self._header_offset = f.tell()
 
+        # These are always true, for now.
         self.dimensionality = 3
         self.refine_by = 2
         self.parameters["HydroMethod"] = "sph"
+
         self.unique_identifier = \
             int(os.stat(self.parameter_filename)[stat.ST_CTIME])
-        # Set standard values
 
-        # This may not be correct.
+        # Read in parameter file, if available.
+        if self._param_file is None:
+            pfn = glob.glob(os.path.join(self.directory, "*.param"))
+            assert len(pfn) < 2, \
+                "More than one param file is in the data directory"
+            if pfn == []:
+                pfn = None
+            else:
+                pfn = pfn[0]
+        else:
+            pfn = self._param_file
+
+        if pfn is not None:
+            for line in (l.strip() for l in open(pfn)):
+                # skip comment lines and blank lines
+                l = line.strip()
+                if l.startswith('#') or l == '':
+                    continue
+                # parse parameters according to tipsy parameter type
+                param, val = (i.strip() for i in line.split('=',1))
+                if param.startswith('n') or param.startswith('i'):
+                    val = long(val)
+                elif param.startswith('d'):
+                    val = float(val)
+                elif param.startswith('b'):
+                    val = bool(float(val))
+                self.parameters[param] = val
+
         self.current_time = hvals["time"]
+        self.domain_dimensions = np.ones(3, "int32") * 2
+        if self.parameters.get('bPeriodic', True):
+            self.periodicity = (True, True, True)
+        else:
+            self.periodicity = (False, False, False)
 
-        # NOTE: These are now set in the main initializer.
-        #self.domain_left_edge = np.zeros(3, "float64") - 0.5
-        #self.domain_right_edge = np.ones(3, "float64") + 0.5
-        self.domain_dimensions = np.ones(3, "int32") * 2
-        self.periodicity = (True, True, True)
-
-        self.cosmological_simulation = 1
-
-        cosm = self._cosmology_parameters or {}
-        dcosm = dict(current_redshift = 0.0,
-                     omega_lambda = 0.0,
-                     omega_matter = 0.0,
-                     hubble_constant = 1.0)
-        for param in ['current_redshift', 'omega_lambda',
-                      'omega_matter', 'hubble_constant']:
-            pval = cosm.get(param, dcosm[param])
-            setattr(self, param, pval)
-
-        self.parameters = hvals
+        if self.parameters.get('bComove', True):
+            self.cosmological_simulation = 1
+            cosm = self._cosmology_parameters or {}
+            dcosm = dict(current_redshift = 0.0,
+                         omega_lambda = 0.0,
+                         omega_matter = 0.0,
+                         hubble_constant = 1.0)
+            for param in ['current_redshift', 'omega_lambda',
+                          'omega_matter', 'hubble_constant']:
+                pval = cosm.get(param, dcosm[param])
+                setattr(self, param, pval)
+        else:
+            self.cosmological_simulation = 0.0
+            kpc_unit = self.parameters.get('dKpcUnit', 1.0)
+            self._unit_base['cm'] = 1.0 / (kpc_unit * cm_per_kpc)
 
         self.filename_template = self.parameter_filename
         self.file_count = 1
@@ -428,12 +467,17 @@
 
     def _set_units(self):
         super(TipsyStaticOutput, self)._set_units()
-        DW = (self.domain_right_edge - self.domain_left_edge).max()
-        cosmo = Cosmology(self.hubble_constant * 100.0,
-                          self.omega_matter, self.omega_lambda)
-        length_unit = DW * self.units['cm'] # Get it in proper cm
-        density_unit = cosmo.CriticalDensity(self.current_redshift)
-        mass_unit = density_unit * length_unit**3
+        if self.cosmological_simulation:
+            DW = (self.domain_right_edge - self.domain_left_edge).max()
+            cosmo = Cosmology(self.hubble_constant * 100.0,
+                              self.omega_matter, self.omega_lambda)
+            length_unit = DW * self.units['cm'] # Get it in proper cm
+            density_unit = cosmo.CriticalDensity(self.current_redshift)
+            mass_unit = density_unit * length_unit**3
+        else:
+            mass_unit = self.parameters.get('dMsolUnit', 1.0) * mass_sun_cgs
+            length_unit = self.parameters.get('dKpcUnit', 1.0) * cm_per_kpc
+            density_unit = mass_unit / length_unit**3
         time_unit = 1.0 / np.sqrt(G*density_unit)
         velocity_unit = length_unit / time_unit
         self.conversion_factors["velocity"] = velocity_unit

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/frontends/sph/io.py
--- a/yt/frontends/sph/io.py
+++ b/yt/frontends/sph/io.py
@@ -380,6 +380,12 @@
                 rv[field] = np.empty(size, dtype="float64")
                 if size == 0: continue
                 rv[field][:] = vals[field][mask]
+            if field == "Coordinates":
+                eps = np.finfo(rv[field].dtype).eps
+                for i in range(3):
+                  rv[field][:,i] = np.clip(rv[field][:,i],
+                      self.domain_left_edge[i] + eps,
+                      self.domain_right_edge[i] - eps)
         return rv
 
     def _read_particle_selection(self, chunks, selector, fields):
@@ -421,6 +427,8 @@
         ind = 0
         DLE, DRE = pf.domain_left_edge, pf.domain_right_edge
         dx = (DRE - DLE) / (2**_ORDER_MAX)
+        self.domain_left_edge = DLE
+        self.domain_right_edge = DRE
         with open(data_file.filename, "rb") as f:
             f.seek(pf._header_offset)
             for iptype, ptype in enumerate(self._ptypes):
@@ -446,9 +454,11 @@
                                                pf.domain_left_edge,
                                                pf.domain_right_edge)
                     pos = np.empty((pp.size, 3), dtype="float64")
-                    pos[:,0] = pp["Coordinates"]["x"]
-                    pos[:,1] = pp["Coordinates"]["y"]
-                    pos[:,2] = pp["Coordinates"]["z"]
+                    for i, ax in enumerate("xyz"):
+                        eps = np.finfo(pp["Coordinates"][ax].dtype).eps
+                        pos[:,i] = np.clip(pp["Coordinates"][ax],
+                                    pf.domain_left_edge[i] + eps,
+                                    pf.domain_right_edge[i] - eps)
                     regions.add_data_file(pos, data_file.file_id)
                     morton[ind:ind+c] = compute_morton(
                         pos[:,0], pos[:,1], pos[:,2],

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/frontends/stream/api.py
--- a/yt/frontends/stream/api.py
+++ b/yt/frontends/stream/api.py
@@ -31,6 +31,7 @@
       StreamHandler, \
       load_uniform_grid, \
       load_amr_grids, \
+      load_particles, \
       refine_amr
 
 from .fields import \

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -733,9 +733,11 @@
     _data_style = "stream_particles"
     file_count = 1
     filename_template = "stream_file"
+    n_ref = 64
 
 def load_particles(data, sim_unit_to_cm, bbox=None,
-                      sim_time=0.0, periodicity=(True, True, True)):
+                      sim_time=0.0, periodicity=(True, True, True),
+                      n_ref = 64):
     r"""Load a set of particles into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamParticleHandler`.
 
@@ -764,6 +766,9 @@
     periodicity : tuple of booleans
         Determines whether the data will be treated as periodic along
         each axis
+    n_ref : int
+        The number of particles that result in refining an oct used for
+        indexing the particles.
 
     Examples
     --------
@@ -818,6 +823,7 @@
     handler.cosmology_simulation = 0
 
     spf = StreamParticlesStaticOutput(handler)
+    spf.n_ref = n_ref
     spf.units["cm"] = sim_unit_to_cm
     spf.units['1'] = 1.0
     spf.units["unitary"] = 1.0

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/coordinate_handler.py
--- a/yt/geometry/coordinate_handler.py
+++ b/yt/geometry/coordinate_handler.py
@@ -36,7 +36,7 @@
     ParallelAnalysisInterface, parallel_splitter
 from yt.utilities.lib.misc_utilities import \
     pixelize_cylinder
-import yt.visualization._MPL
+import yt.visualization._MPL as _MPL
 
 from .cartesian_fields import CartesianFieldInfo
 from .cylindrical_fields import CylindricalFieldInfo, PolarFieldInfo
@@ -103,7 +103,7 @@
     c2[...,0] = ((coord[...,0] - center[0])**2.0
               +  (coord[...,1] - center[1])**2.0)**0.5
     c2[...,1] = coord[...,2] # rzt
-    c2[...,2] = np.arctans(coord[...,1] - center[1],
+    c2[...,2] = np.arctan2(coord[...,1] - center[1],
                            coord[...,0] - center[0])
     return c2
 
@@ -145,7 +145,7 @@
                               data_source['py'], data_source['pdx'],
                               data_source['pdy'], data_source['pdz'],
                               data_source.center, data_source._inv_mat, indices,
-                              data_source[item], size[0], size[1], bounds).transpose()
+                              data_source[field], size[0], size[1], bounds).transpose()
         return buff
 
     def convert_from_cartesian(self, coord):
@@ -258,7 +258,7 @@
 
     @property
     def period(self):
-        return na.array([0.0, 0.0, 2.0*np.pi])
+        return np.array([0.0, 0.0, 2.0*np.pi])
 
 class CylindricalCoordinateHandler(CoordinateHandler):
 
@@ -331,5 +331,5 @@
 
     @property
     def period(self):
-        return na.array([0.0, 0.0, 2.0*np.pi])
+        return np.array([0.0, 0.0, 2.0*np.pi])
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/cylindrical_fields.py
--- a/yt/geometry/cylindrical_fields.py
+++ b/yt/geometry/cylindrical_fields.py
@@ -35,6 +35,8 @@
     NeedsDataField, \
     NeedsProperty, \
     NeedsParameter
+from yt.utilities.exceptions import \
+    YTCoordinateNotImplemented
 
 CylindricalFieldInfo = FieldInfoContainer()
 CylindricalFieldInfo.name = id(CylindricalFieldInfo)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/oct_container.pxd
--- a/yt/geometry/oct_container.pxd
+++ b/yt/geometry/oct_container.pxd
@@ -53,6 +53,7 @@
     cdef OctAllocationContainer *cont
     cdef OctAllocationContainer **domains
     cdef Oct ****root_mesh
+    cdef oct_visitor_function *fill_func
     cdef int partial_coverage
     cdef int nn[3]
     cdef np.float64_t DLE[3], DRE[3]

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/oct_container.pyx
--- a/yt/geometry/oct_container.pyx
+++ b/yt/geometry/oct_container.pyx
@@ -109,6 +109,7 @@
             self.DLE[i] = domain_left_edge[i] #0
             self.DRE[i] = domain_right_edge[i] #num_grid
         self._initialize_root_mesh()
+        self.fill_func = oct_visitors.fill_file_indices_oind
 
     def _initialize_root_mesh(self):
         self.root_mesh = <Oct****> malloc(sizeof(void*) * self.nn[0])
@@ -613,7 +614,7 @@
         p[2] = cell_inds.data
         data.array = p
         data.domain = domain_id
-        self.visit_all_octs(selector, oct_visitors.fill_file_indices, &data)
+        self.visit_all_octs(selector, self.fill_func, &data)
         return levels, cell_inds, file_inds
 
     @cython.boundscheck(False)
@@ -673,6 +674,7 @@
         for i in range(3):
             self.DLE[i] = domain_left_edge[i] #0
             self.DRE[i] = domain_right_edge[i] #num_grid
+        self.fill_func = oct_visitors.fill_file_indices_rind
 
     cdef int get_root(self, int ind[3], Oct **o):
         o[0] = NULL

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/oct_visitors.pxd
--- a/yt/geometry/oct_visitors.pxd
+++ b/yt/geometry/oct_visitors.pxd
@@ -60,7 +60,8 @@
 cdef oct_visitor_function copy_array_i64
 cdef oct_visitor_function identify_octs
 cdef oct_visitor_function assign_domain_ind
-cdef oct_visitor_function fill_file_indices
+cdef oct_visitor_function fill_file_indices_oind
+cdef oct_visitor_function fill_file_indices_rind
 
 cdef inline int cind(int i, int j, int k):
     return (((i*2)+j)*2+k)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/oct_visitors.pyx
--- a/yt/geometry/oct_visitors.pyx
+++ b/yt/geometry/oct_visitors.pyx
@@ -152,7 +152,7 @@
     o.domain_ind = data.global_index
     data.index += 1
 
-cdef void fill_file_indices(Oct *o, OctVisitorData *data, np.uint8_t selected):
+cdef void fill_file_indices_oind(Oct *o, OctVisitorData *data, np.uint8_t selected):
     # We fill these arrays, then inside the level filler we use these as
     # indices as we fill a second array from the data.
     if selected == 0: return
@@ -164,3 +164,16 @@
     find_arr[data.index] = o.file_ind
     cell_arr[data.index] = oind(data)
     data.index +=1
+
+cdef void fill_file_indices_rind(Oct *o, OctVisitorData *data, np.uint8_t selected):
+    # We fill these arrays, then inside the level filler we use these as
+    # indices as we fill a second array from the data.
+    if selected == 0: return
+    cdef void **p = <void **> data.array
+    cdef np.uint8_t *level_arr = <np.uint8_t *> p[0]
+    cdef np.int64_t *find_arr = <np.int64_t *> p[1]
+    cdef np.uint8_t *cell_arr = <np.uint8_t *> p[2]
+    level_arr[data.index] = data.level
+    find_arr[data.index] = o.file_ind
+    cell_arr[data.index] = rind(data)
+    data.index +=1

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/particle_deposit.pxd
--- a/yt/geometry/particle_deposit.pxd
+++ b/yt/geometry/particle_deposit.pxd
@@ -63,6 +63,8 @@
     # We assume each will allocate and define their own temporary storage
     cdef public object nvals
     cdef public int bad_indices
+    cdef int update_values
     cdef void process(self, int dim[3], np.float64_t left_edge[3],
                       np.float64_t dds[3], np.int64_t offset,
-                      np.float64_t ppos[3], np.float64_t *fields)
+                      np.float64_t ppos[3], np.float64_t *fields,
+                      np.int64_t domain_ind)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/particle_deposit.pyx
--- a/yt/geometry/particle_deposit.pyx
+++ b/yt/geometry/particle_deposit.pyx
@@ -38,6 +38,7 @@
 cdef class ParticleDepositOperation:
     def __init__(self, nvals):
         self.nvals = nvals
+        self.update_values = 0 # This is the default
 
     def initialize(self, *args):
         raise NotImplementedError
@@ -101,7 +102,10 @@
             if offset < 0: continue
             # Check that we found the oct ...
             self.process(dims, oi.left_edge, oi.dds,
-                         offset, pos, field_vals)
+                         offset, pos, field_vals, oct.domain_ind)
+            if self.update_values == 1:
+                for j in range(nf):
+                    field_pointers[j][i] = field_vals[j] 
         
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -116,6 +120,7 @@
         cdef np.ndarray[np.float64_t, ndim=1] tarr
         field_pointers = <np.float64_t**> alloca(sizeof(np.float64_t *) * nf)
         field_vals = <np.float64_t*>alloca(sizeof(np.float64_t) * nf)
+        cdef np.int64_t gid = getattr(gobj, "id", -1)
         for i in range(nf):
             tarr = fields[i]
             field_pointers[i] = <np.float64_t *> tarr.data
@@ -131,11 +136,15 @@
                 field_vals[j] = field_pointers[j][i]
             for j in range(3):
                 pos[j] = positions[i, j]
-            self.process(dims, left_edge, dds, 0, pos, field_vals)
+            self.process(dims, left_edge, dds, 0, pos, field_vals, gid)
+            if self.update_values == 1:
+                for j in range(nf):
+                    field_pointers[j][i] = field_vals[j] 
 
     cdef void process(self, int dim[3], np.float64_t left_edge[3],
                       np.float64_t dds[3], np.int64_t offset,
-                      np.float64_t ppos[3], np.float64_t *fields):
+                      np.float64_t ppos[3], np.float64_t *fields,
+                      np.int64_t domain_ind):
         raise NotImplementedError
 
 cdef class CountParticles(ParticleDepositOperation):
@@ -154,7 +163,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset, # offset into IO field
                       np.float64_t ppos[3], # this particle's position
-                      np.float64_t *fields # any other fields we need
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         # here we do our thing; this is the kernel
         cdef int ii[3], i
@@ -190,7 +200,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset,
                       np.float64_t ppos[3],
-                      np.float64_t *fields
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], half_len, ib0[3], ib1[3]
         cdef int i, j, k
@@ -243,7 +254,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset, 
                       np.float64_t ppos[3],
-                      np.float64_t *fields 
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], i
         for i in range(3):
@@ -289,7 +301,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset,
                       np.float64_t ppos[3],
-                      np.float64_t *fields
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], i, cell_index
         cdef float k, mk, qk
@@ -331,7 +344,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset, # offset into IO field
                       np.float64_t ppos[3], # this particle's position
-                      np.float64_t *fields # any other fields we need
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         
         cdef int i, j, k, ind[3], ii
@@ -375,14 +389,15 @@
         self.ow = np.zeros(self.nvals, dtype='float64', order='F')
         cdef np.ndarray warr = self.ow
         self.w = <np.float64_t*> warr.data
-    
+
     @cython.cdivision(True)
     cdef void process(self, int dim[3],
                       np.float64_t left_edge[3], 
                       np.float64_t dds[3],
                       np.int64_t offset, 
                       np.float64_t ppos[3],
-                      np.float64_t *fields 
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], i
         for i in range(3):
@@ -393,5 +408,27 @@
     def finalize(self):
         return self.owf / self.ow
 
-deposit_weighted_mean= WeightedMeanParticleField
+deposit_weighted_mean = WeightedMeanParticleField
 
+cdef class MeshIdentifier(ParticleDepositOperation):
+    # This is a tricky one!  What it does is put into the particle array the
+    # value of the oct or block (grids will always be zero) identifier that a
+    # given particle resides in
+    def initialize(self):
+        self.update_values = 1
+
+    @cython.cdivision(True)
+    cdef void process(self, int dim[3],
+                      np.float64_t left_edge[3], 
+                      np.float64_t dds[3],
+                      np.int64_t offset, 
+                      np.float64_t ppos[3],
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
+                      ):
+        fields[0] = domain_ind
+
+    def finalize(self):
+        return
+
+deposit_mesh_id = MeshIdentifier

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/particle_geometry_handler.py
--- a/yt/geometry/particle_geometry_handler.py
+++ b/yt/geometry/particle_geometry_handler.py
@@ -87,7 +87,7 @@
         pf = self.parameter_file
         self.oct_handler = ParticleOctreeContainer(
             [1, 1, 1], pf.domain_left_edge, pf.domain_right_edge)
-        self.oct_handler.n_ref = 64
+        self.oct_handler.n_ref = pf.n_ref
         mylog.info("Allocating for %0.3e particles", self.total_particles)
         # No more than 256^3 in the region finder.
         N = min(len(self.data_files), 256) 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/particle_oct_container.pyx
--- a/yt/geometry/particle_oct_container.pyx
+++ b/yt/geometry/particle_oct_container.pyx
@@ -190,7 +190,7 @@
                 if cur.children == NULL or \
                    cur.children[cind(ind[0],ind[1],ind[2])] == NULL:
                     cur = self.refine_oct(cur, index, level)
-                    self.filter_particles(cur, data, p, level + 1)
+                    self.filter_particles(cur, data, p, level)
                 else:
                     cur = cur.children[cind(ind[0],ind[1],ind[2])]
             cur.file_ind += 1
@@ -215,7 +215,7 @@
                     o.children[cind(i,j,k)] = noct
         o.file_ind = self.n_ref + 1
         for i in range(3):
-            ind[i] = (index >> ((ORDER_MAX - (level + 1))*3 + (2 - i))) & 1
+            ind[i] = (index >> ((ORDER_MAX - level)*3 + (2 - i))) & 1
         noct = o.children[cind(ind[0],ind[1],ind[2])]
         return noct
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/geometry/tests/test_particle_octree.py
--- a/yt/geometry/tests/test_particle_octree.py
+++ b/yt/geometry/tests/test_particle_octree.py
@@ -3,6 +3,8 @@
 from yt.geometry.particle_oct_container import ParticleOctreeContainer
 from yt.geometry.oct_container import _ORDER_MAX
 from yt.utilities.lib.geometry_utils import get_morton_indices
+from yt.frontends.stream.api import load_particles
+import yt.data_objects.api
 import time, os
 
 NPART = 32**3
@@ -35,7 +37,27 @@
         # This visits every cell -- including those covered by octs.
         #for dom in range(ndom):
         #    level_count += octree.count_levels(total_count.size-1, dom, mask)
-        yield assert_equal, total_count, [1, 8, 64, 104, 184, 480, 1680, 1480]
+        yield assert_equal, total_count, [1, 8, 64, 64, 256, 536, 1856, 1672]
+
+def test_particle_octree_counts():
+    np.random.seed(int(0x4d3d3d3))
+    # Eight times as many!
+    pos = []
+    data = {}
+    bbox = []
+    for i, ax in enumerate('xyz'):
+        DW = DRE[i] - DLE[i]
+        LE = DLE[i]
+        data["particle_position_%s" % ax] = \
+            np.random.normal(0.5, scale=0.05, size=(NPART*8)) * DW + LE
+        bbox.append( [DLE[i], DRE[i]] )
+    bbox = np.array(bbox)
+    for n_ref in [16, 32, 64, 512, 1024]:
+        pf = load_particles(data, 1.0, bbox = bbox, n_ref = n_ref)
+        dd = pf.h.all_data()
+        bi = dd["all","mesh_id"]
+        v = np.bincount(bi.astype("int64"))
+        yield assert_equal, v.max() <= n_ref, True
 
 if __name__=="__main__":
     for i in test_add_particles_random():

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -54,14 +54,14 @@
 
 class Tree(object):
     def __init__(self, pf, comm_rank=0, comm_size=1, left=None, right=None, 
-        min_level=None, max_level=None, source=None):
+        min_level=None, max_level=None, data_source=None):
 
         self.pf = pf
         self._id_offset = self.pf.h.grids[0]._id_offset
 
-        if source is None:
-            source = pf.h.all_data()
-        self.source = source
+        if data_source is None:
+            data_source = pf.h.all_data()
+        self.data_source = data_source
         if left is None:
             left = np.array([-np.inf]*3)
         if right is None:
@@ -87,8 +87,8 @@
     def build(self):
         lvl_range = range(self.min_level, self.max_level+1)
         for lvl in lvl_range:
-            #grids = self.source.select_grids(lvl)
-            grids = np.array([b for b, mask in self.source.blocks if b.Level == lvl])
+            #grids = self.data_source.select_grids(lvl)
+            grids = np.array([b for b, mask in self.data_source.blocks if b.Level == lvl])
             if len(grids) == 0: continue
             self.add_grids(grids)
 
@@ -141,7 +141,7 @@
     no_ghost = True
 
     def __init__(self, pf, min_level=None, max_level=None,
-                 source=None):
+                 data_source=None):
 
         ParallelAnalysisInterface.__init__(self)
 
@@ -158,14 +158,14 @@
         except AttributeError:
             self._id_offset = 0
 
-        if source is None:
-            source = self.pf.h.all_data()
-        self.source = source
+        if data_source is None:
+            data_source = self.pf.h.all_data()
+        self.data_source = data_source
 
         mylog.debug('Building AMRKDTree')
         self.tree = Tree(pf, self.comm.rank, self.comm.size,
                          min_level=min_level, max_level=max_level,
-                         source=source)
+                         data_source=data_source)
 
     def set_fields(self, fields, log_fields, no_ghost):
         self.fields = fields
@@ -257,17 +257,23 @@
         else:
             dds = []
             for i, field in enumerate(self.fields):
-                vcd = grid.get_vertex_centered_data(field, smoothed=True,no_ghost=self.no_ghost).astype('float64')
+                vcd = grid.get_vertex_centered_data(field, smoothed=True, no_ghost=self.no_ghost).astype('float64')
                 if self.log_fields[i]: vcd = np.log10(vcd)
                 dds.append(vcd)
                 self.current_saved_grids.append(grid)
                 self.current_vcds.append(dds)
 
+        if self.data_source.selector is None:
+            mask = np.ones(dims, dtype='uint8')
+        else:
+            mask = self.data_source.selector.fill_mask(grid)[li[0]:ri[0], li[1]:ri[1], li[2]:ri[2] ].astype('uint8')
+
         data = [d[li[0]:ri[0]+1,
                   li[1]:ri[1]+1,
                   li[2]:ri[2]+1].copy() for d in dds]
 
         brick = PartitionedGrid(grid.id, data,
+                                mask,
                                 nle.copy(),
                                 nre.copy(),
                                 dims.astype('int64'))

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/cosmology.py
--- a/yt/utilities/cosmology.py
+++ b/yt/utilities/cosmology.py
@@ -61,7 +61,7 @@
                           self.HubbleDistance()))
          elif (self.OmegaCurvatureNow < 0):
              return (self.HubbleDistance() / np.sqrt(np.fabs(self.OmegaCurvatureNow)) * 
-                     sin(np.sqrt(np.fabs(self.OmegaCurvatureNow)) * 
+                     np.sin(np.sqrt(np.fabs(self.OmegaCurvatureNow)) * 
                          self.ComovingRadialDistance(z_i,z_f) / self.HubbleDistance()))
          else:
              return self.ComovingRadialDistance(z_i,z_f)
@@ -73,7 +73,7 @@
                       np.sqrt(1 + self.OmegaCurvatureNow * 
                            sqr(self.ComovingTransverseDistance(z_i,z_f) / 
                                self.HubbleDistance())) - 
-                      anp.sinh(np.fabs(self.OmegaCurvatureNow) * 
+                      np.sinh(np.fabs(self.OmegaCurvatureNow) * 
                             self.ComovingTransverseDistance(z_i,z_f) / 
                             self.HubbleDistance()) / np.sqrt(self.OmegaCurvatureNow)) / 1e9)
         elif (self.OmegaCurvatureNow < 0):
@@ -83,7 +83,7 @@
                       np.sqrt(1 + self.OmegaCurvatureNow * 
                            sqr(self.ComovingTransverseDistance(z_i,z_f) / 
                                self.HubbleDistance())) - 
-                      asin(np.fabs(self.OmegaCurvatureNow) * 
+                      np.arcsin(np.fabs(self.OmegaCurvatureNow) * 
                            self.ComovingTransverseDistance(z_i,z_f) / 
                            self.HubbleDistance()) / 
                       np.sqrt(np.fabs(self.OmegaCurvatureNow))) / 1e9)
@@ -269,7 +269,7 @@
         # 3) For OmegaMatterNow > 1 and OmegaLambdaNow == 0, use sin/cos.
  
         if ((self.OmegaMatterNow > 1) and (self.OmegaLambdaNow == 0)):
-            eta = np.acos(1 - 2*(1-self.OmegaMatterNow)/self.OmegaMatterNow/(1+z))
+            eta = np.arccos(1 - 2*(1-self.OmegaMatterNow)/self.OmegaMatterNow/(1+z))
             TimeHubble0 = self.OmegaMatterNow/(2*np.power(1.0-self.OmegaMatterNow, 1.5))*\
                 (eta - np.sin(eta))
  

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/exceptions.py
--- a/yt/utilities/exceptions.py
+++ b/yt/utilities/exceptions.py
@@ -109,7 +109,7 @@
                 % (self.display_name, self.field_name) + self.mathtext_error
 
 class YTCannotParseUnitDisplayName(YTException):
-    def __init__(self, field_name, display_unit, mathtext_error):
+    def __init__(self, field_name, unit_name, mathtext_error):
         self.field_name = field_name
         self.unit_name = unit_name
         self.mathtext_error = mathtext_error

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/flagging_methods.py
--- a/yt/utilities/flagging_methods.py
+++ b/yt/utilities/flagging_methods.py
@@ -162,6 +162,9 @@
                 # Note that sd is offset by one
                 if sd[i-1] * sd[i] < 0:
                     strength = np.abs(sd[i-1] - sd[i])
+                    # TODO this differs from what I could find in ENZO
+                    # there's |center - i| < |center - zero_cross| instead
+                    # additionally zero_cross is undefined in first pass  
                     if strength > zero_strength or \
                        (strength == zero_strength and np.abs(center - i) < np.abs(zero_cross -i )):
                         zero_strength = strength

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/fortran_utils.py
--- a/yt/utilities/fortran_utils.py
+++ b/yt/utilities/fortran_utils.py
@@ -121,7 +121,8 @@
     vec_fmt = "%s%s" % (endian, d)
     vec_size = struct.calcsize(vec_fmt)
     if vec_len % vec_size != 0:
-        print "fmt = '%s' ; length = %s ; size= %s" % (fmt, length, size)
+        print("fmt = '%s' ; length = %s ; size= %s"
+              % (vec_fmt, vec_len, vec_size))
         raise RuntimeError
     vec_num = vec_len / vec_size
     if isinstance(f, file): # Needs to be explicitly a file

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/lib/grid_traversal.pxd
--- a/yt/utilities/lib/grid_traversal.pxd
+++ b/yt/utilities/lib/grid_traversal.pxd
@@ -30,6 +30,8 @@
 cdef struct VolumeContainer:
     int n_fields
     np.float64_t **data
+    # The mask has dimensions one fewer in each direction than data
+    np.uint8_t *mask
     np.float64_t left_edge[3]
     np.float64_t right_edge[3]
     np.float64_t dds[3]

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -60,6 +60,7 @@
 
 cdef class PartitionedGrid:
     cdef public object my_data
+    cdef public object source_mask 
     cdef public object LeftEdge
     cdef public object RightEdge
     cdef public int parent_grid_id
@@ -74,12 +75,14 @@
     @cython.cdivision(True)
     def __cinit__(self,
                   int parent_grid_id, data,
+                  mask,
                   np.ndarray[np.float64_t, ndim=1] left_edge,
                   np.ndarray[np.float64_t, ndim=1] right_edge,
                   np.ndarray[np.int64_t, ndim=1] dims,
 		  star_kdtree_container star_tree = None):
         # The data is likely brought in via a slice, so we copy it
         cdef np.ndarray[np.float64_t, ndim=3] tdata
+        cdef np.ndarray[np.uint8_t, ndim=3] mask_data
         self.container = NULL
         self.parent_grid_id = parent_grid_id
         self.LeftEdge = left_edge
@@ -96,10 +99,13 @@
             c.dds[i] = (c.right_edge[i] - c.left_edge[i])/dims[i]
             c.idds[i] = 1.0/c.dds[i]
         self.my_data = data
+        self.source_mask = mask
+        mask_data = mask
         c.data = <np.float64_t **> malloc(sizeof(np.float64_t*) * n_fields)
         for i in range(n_fields):
             tdata = data[i]
             c.data[i] = <np.float64_t *> tdata.data
+        c.mask = <np.uint8_t *> mask_data.data
         if star_tree is None:
             self.star_list = NULL
         else:
@@ -503,6 +509,10 @@
     # we assume this has vertex-centered data.
     cdef int offset = index[0] * (vc.dims[1] + 1) * (vc.dims[2] + 1) \
                     + index[1] * (vc.dims[2] + 1) + index[2]
+    cdef int cell_offset = index[0] * (vc.dims[1]) * (vc.dims[2]) \
+                    + index[1] * (vc.dims[2]) + index[2]
+    if vc.mask[cell_offset] != 1:
+        return
     cdef np.float64_t slopes[6], dp[3], ds[3]
     cdef np.float64_t dt = (exit_t - enter_t) / vri.n_samples
     cdef np.float64_t dvs[6]

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/parallel_tools/controller_system.py
--- a/yt/utilities/parallel_tools/controller_system.py
+++ b/yt/utilities/parallel_tools/controller_system.py
@@ -27,6 +27,8 @@
     from .parallel_analysis_interface import MPI
 except ImportError:
     pass
+from .parallel_analysis_interface import \
+    ProcessorPool
 from contextmanager import contextlib
 from abc import ABCMeta, abstractmethod, abstractproperty
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/parallel_tools/io_runner.py
--- a/yt/utilities/parallel_tools/io_runner.py
+++ b/yt/utilities/parallel_tools/io_runner.py
@@ -24,7 +24,10 @@
 """
 
 import os
-from .parallel_analysis_interface import ProcessorPool
+import np
+from yt.utilities.logger import ytLogger as mylog
+from .parallel_analysis_interface import \
+    ProcessorPool, parallel_objects
 from yt.utilities.io_handler import BaseIOHandler
 from contextlib import contextmanager
 import time
@@ -168,6 +171,7 @@
     pf.h.io = original_io
 
 def io_nodes(fn, n_io, n_work, func, *args, **kwargs):
+    from yt.mods import load
     pool, wg = ProcessorPool.from_sizes([(n_io, "io"), (n_work, "work")])
     rv = None
     if wg.name == "work":

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a 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
@@ -1115,8 +1115,9 @@
         """
         LE, RE = left_edge[:], right_edge[:]
         if not self._distributed:
+            raise NotImplemented
             return LE, RE, re
-        
+
         cc = MPI.Compute_dims(self.comm.size / rank_ratio, 3)
         mi = self.comm.rank % (self.comm.size / rank_ratio)
         cx, cy, cz = np.unravel_index(mi, cc)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/parameter_file_storage.py
--- a/yt/utilities/parameter_file_storage.py
+++ b/yt/utilities/parameter_file_storage.py
@@ -221,7 +221,8 @@
     def __init__(self, path = None):
         if path is None:
             path = ytcfg.get("yt", "enzo_db")
-            if len(path) == 0: raise Runtime
+            if len(path) == 0:
+                raise RuntimeError
         import sqlite3
         self.conn = sqlite3.connect(path)
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/pykdtree.py
--- a/yt/utilities/pykdtree.py
+++ b/yt/utilities/pykdtree.py
@@ -2,6 +2,7 @@
 # Released under the scipy license
 import sys
 import numpy as np
+import scipy
 from heapq import heappush, heappop
 
 def minkowski_distance_p(x,y,p=2):

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/utilities/rpdb.py
--- a/yt/utilities/rpdb.py
+++ b/yt/utilities/rpdb.py
@@ -25,6 +25,7 @@
 
 import cmd, pdb, cStringIO, xmlrpclib, socket, sys
 import traceback
+import signal
 from SimpleXMLRPCServer import SimpleXMLRPCServer
 from yt.config import ytcfg
 

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -121,6 +121,10 @@
         accuracy/smoothness in resulting image.  The effects are
         less notable when the transfer function is smooth and
         broad. Default: True
+    data_source: data container, optional
+        Optionally specify an arbitrary data source to the volume rendering.
+        All cells not included in the data source will be ignored during ray
+        casting. By default this will get set to pf.h.all_data().
 
     Examples
     --------
@@ -164,7 +168,7 @@
                  log_fields = None,
                  sub_samples = 5, pf = None,
                  min_level=None, max_level=None, no_ghost=True,
-                 source=None,
+                 data_source=None,
                  use_light=False):
         ParallelAnalysisInterface.__init__(self)
         if pf is not None: self.pf = pf
@@ -196,13 +200,13 @@
         if self.no_ghost:
             mylog.info('Warning: no_ghost is currently True (default). This may lead to artifacts at grid boundaries.')
 
-        if source is None:
-            source = self.pf.h.all_data()
-        self.source = source
+        if data_source is None:
+            data_source = self.pf.h.all_data()
+        self.data_source = data_source
 
         if volume is None:
             volume = AMRKDTree(self.pf, min_level=min_level, 
-                               max_level=max_level, source=self.source)
+                               max_level=max_level, data_source=self.data_source)
         self.volume = volume        
 
     def _setup_box_properties(self, width, center, unit_vectors):
@@ -1125,6 +1129,8 @@
                  sub_samples = 5, log_fields = None, volume = None,
                  pf = None, use_kd=True, no_ghost=False, use_light=False,
                  inner_radius = 10):
+        mylog.error('I am sorry, HEALpix Camera does not work yet in 3.0')
+        raise NotImplementedError
         ParallelAnalysisInterface.__init__(self)
         if pf is not None: self.pf = pf
         self.center = np.array(center, dtype='float64')
@@ -1155,8 +1161,8 @@
         self.light_dir = None
         self.light_rgba = None
         if volume is None:
-            volume = AMRKDTree(self.pf, fields=self.fields, no_ghost=no_ghost,
-                               log_fields=log_fields)
+            volume = AMRKDTree(self.pf, min_level=min_level,
+                               max_level=max_level, data_source=self.data_source)
         self.use_kd = isinstance(volume, AMRKDTree)
         self.volume = volume
 
@@ -1963,7 +1969,7 @@
             yield self.snapshot()
 
 def allsky_projection(pf, center, radius, nside, field, weight = None,
-                      inner_radius = 10, rotation = None, source = None):
+                      inner_radius = 10, rotation = None, data_source = None):
     r"""Project through a parameter file, through an allsky-method
     decomposition from HEALpix, and return the image plane.
 
@@ -1998,7 +2004,7 @@
         If supplied, the vectors will be rotated by this.  You can construct
         this by, for instance, calling np.array([v1,v2,v3]) where those are the
         three reference planes of an orthogonal frame (see ortho_find).
-    source : data container, default None
+    data_source : data container, default None
         If this is supplied, this gives the data source from which the all sky
         projection pulls its data from.
 
@@ -2044,16 +2050,16 @@
     positions += inner_radius * dx * vs
     vs *= radius
     uv = np.ones(3, dtype='float64')
-    if source is not None:
-        grids = source._grids
+    if data_source is not None:
+        grids = data_source._grids
     else:
         grids = pf.h.sphere(center, radius)._grids
     sampler = ProjectionSampler(positions, vs, center, (0.0, 0.0, 0.0, 0.0),
                                 image, uv, uv, np.zeros(3, dtype='float64'))
     pb = get_pbar("Sampling ", len(grids))
     for i,grid in enumerate(grids):
-        if source is not None:
-            data = [grid[field] * source._get_cut_mask(grid) * \
+        if data_source is not None:
+            data = [grid[field] * data_source._get_cut_mask(grid) * \
                 grid.child_mask.astype('float64')
                 for field in fields]
         else:
@@ -2197,12 +2203,13 @@
                     np.minimum(mi, this_point, mi)
                     np.maximum(ma, this_point, ma)
         # Now we have a bounding box.
-        source = pf.h.region(self.center, mi, ma)
+        data_source = pf.h.region(self.center, mi, ma)
 
-        for i, (grid, mask) in enumerate(source.blocks):
+        for i, (grid, mask) in enumerate(data_source.blocks):
             data = [(grid[field] * mask).astype("float64") for field in fields]
             pg = PartitionedGrid(
                 grid.id, data,
+                mask.astype('uint8'),
                 grid.LeftEdge, grid.RightEdge, grid.ActiveDimensions.astype("int64"))
             grid.clear_data()
             sampler(pg, num_threads = num_threads)

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/visualization/volume_rendering/setup.py
--- a/yt/visualization/volume_rendering/setup.py
+++ b/yt/visualization/volume_rendering/setup.py
@@ -12,4 +12,5 @@
     config = Configuration('volume_rendering', parent_package, top_path)
     config.make_config_py()  # installs __config__.py
     #config.make_svn_version_py()
+    config.add_subpackage('tests')
     return config

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/visualization/volume_rendering/tests/test_vr_cameras.py
--- /dev/null
+++ b/yt/visualization/volume_rendering/tests/test_vr_cameras.py
@@ -0,0 +1,163 @@
+"""
+Test for Volume Rendering Cameras, and their movement. 
+
+Author: Samuel Skillman <samskillman at gmail.com>
+Homepage: http://yt-project.org/
+License:
+  Copyright (C) 2013 Samuel Skillman.  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 os.path
+import tempfile
+import shutil
+from yt.testing import \
+    fake_random_pf
+import numpy as np
+from yt.mods import ColorTransferFunction, ProjectionTransferFunction
+from yt.visualization.volume_rendering.api import \
+    PerspectiveCamera, StereoPairCamera, InteractiveCamera, ProjectionCamera
+from yt.visualization.tests.test_plotwindow import assert_fname
+from unittest import TestCase
+
+# This toggles using a temporary directory. Turn off to examine images.
+use_tmpdir = True 
+
+
+def setup():
+    """Test specific setup."""
+    from yt.config import ytcfg
+    ytcfg["yt", "__withintesting"] = "True"
+
+
+class CameraTest(TestCase):
+    def setUp(self):
+        if use_tmpdir:
+            self.curdir = os.getcwd()
+            # Perform I/O in safe place instead of yt main dir
+            self.tmpdir = tempfile.mkdtemp()
+            os.chdir(self.tmpdir)
+        else:
+            self.curdir, self.tmpdir = None, None
+
+        self.pf = fake_random_pf(64)
+        self.c = self.pf.domain_center
+        self.L = np.array([0.5, 0.5, 0.5])
+        self.W = 1.5*self.pf.domain_width
+        self.N = 64
+        self.field = "Density"
+
+    def tearDown(self):
+        if use_tmpdir:
+            os.chdir(self.curdir)
+            shutil.rmtree(self.tmpdir)
+
+    def setup_transfer_function(self, camera_type):
+        if camera_type in ['perspective', 'camera',
+                           'stereopair', 'interactive']:
+            mi, ma = self.pf.h.all_data().quantities['Extrema']('Density')[0]
+            tf = ColorTransferFunction((mi-1., ma+1.), grey_opacity=True)
+            tf.map_to_colormap(mi, ma, scale=10., colormap='RdBu_r')
+            return tf
+        elif camera_type in ['healpix']:
+            return ProjectionTransferFunction()
+        else:
+            pass
+
+    def test_camera(self):
+        pf = self.pf
+        tf = self.setup_transfer_function('camera')
+        cam = self.pf.h.camera(self.c, self.L, self.W, self.N,
+                               transfer_function=tf)
+        cam.snapshot('camera.png')
+        assert_fname('camera.png')
+
+    def test_data_source_camera(self):
+        pf = self.pf
+        tf = self.setup_transfer_function('camera')
+        data_source = pf.h.sphere(pf.domain_center, pf.domain_width[0]*0.5)
+
+        cam = pf.h.camera(self.c, self.L, self.W, self.N,
+                          transfer_function=tf, data_source=data_source)
+        cam.snapshot('data_source_camera.png')
+        assert_fname('data_source_camera.png')
+
+    def test_perspective_camera(self):
+        pf = self.pf
+        tf = self.setup_transfer_function('camera')
+
+        cam = PerspectiveCamera(self.c, self.L, self.W, self.N, pf=pf,
+                                transfer_function=tf)
+        cam.snapshot('perspective.png')
+        assert_fname('perspective.png')
+
+    def test_interactive_camera(self):
+        pf = self.pf
+        tf = self.setup_transfer_function('camera')
+
+        cam = InteractiveCamera(self.c, self.L, self.W, self.N, pf=pf,
+                                transfer_function=tf)
+        # Can't take a snapshot here since IC uses pylab.'
+
+    def test_projection_camera(self):
+        pf = self.pf
+
+        cam = ProjectionCamera(self.c, self.L, self.W, self.N, pf=pf,
+                               field='Density')
+        cam.snapshot('projection.png')
+        assert_fname('projection.png')
+
+    def test_stereo_camera(self):
+        pf = self.pf
+        tf = self.setup_transfer_function('camera')
+
+        cam = pf.h.camera(self.c, self.L, self.W, self.N, transfer_function=tf)
+        stereo_cam = StereoPairCamera(cam)
+        # Take image
+        cam1, cam2 = stereo_cam.split()
+        cam1.snapshot(fn='stereo1.png')
+        cam2.snapshot(fn='stereo2.png')
+        assert_fname('stereo1.png')
+        assert_fname('stereo2.png')
+
+    def test_camera_movement(self):
+        pf = self.pf
+        tf = self.setup_transfer_function('camera')
+
+        cam = pf.h.camera(self.c, self.L, self.W, self.N, transfer_function=tf)
+        cam.zoom(0.5)
+        for snap in cam.zoomin(2.0, 3):
+            snap
+        for snap in cam.move_to(np.array(self.c) + 0.1, 3,
+                                final_width=None, exponential=False):
+            snap
+        for snap in cam.move_to(np.array(self.c) - 0.1, 3,
+                                final_width=2.0*self.W, exponential=False):
+            snap
+        for snap in cam.move_to(np.array(self.c), 3,
+                                final_width=1.0*self.W, exponential=True):
+            snap
+        cam.rotate(np.pi/10)
+        cam.pitch(np.pi/10)
+        cam.yaw(np.pi/10)
+        cam.roll(np.pi/10)
+        for snap in cam.rotation(np.pi, 3, rot_vector=None):
+            snap
+        for snap in cam.rotation(np.pi, 3, rot_vector=np.random.random(3)):
+            snap
+        cam.snapshot('final.png')
+        assert_fname('final.png')

diff -r 864facfc4dd016d43ff88d1b959ea105a9676ec3 -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a yt/visualization/volume_rendering/transfer_functions.py
--- a/yt/visualization/volume_rendering/transfer_functions.py
+++ b/yt/visualization/volume_rendering/transfer_functions.py
@@ -636,24 +636,59 @@
                 v, w, (r,g,b,alpha)))
 
     def map_to_colormap(self, mi, ma, scale=1.0, colormap="gist_stern",
-            scale_func=None):
+                        scale_func=None):
+        r"""Map a range of values to a full colormap.
+
+        Given a minimum and maximum value in the TransferFunction, map a full
+        colormap over that range at an alpha level of `scale`.
+        Optionally specify a scale_func function that modifies the alpha as
+        a function of the transfer function value.
+
+        Parameters
+        ----------
+        mi : float
+            The start of the TransferFunction to map the colormap
+        ma : float
+            The end of the TransferFunction to map the colormap
+        scale: float, optional
+            The alpha value to be used for the height of the transfer function.
+            Larger values will be more opaque.
+        colormap : string, optional
+            An acceptable colormap.  See either yt.visualization.color_maps or
+            http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps .
+        scale_func: function(value, minval, maxval), optional
+            A user-defined function that can be used to scale the alpha channel
+            as a function of the TransferFunction field values. Function maps
+            value to somewhere between minval and maxval.
+
+        Examples
+        --------
+
+        >>> def linramp(vals, minval, maxval):
+        ...     return (vals - vals.min())/(vals.(max) - vals.min())
+        >>> tf = ColorTransferFunction( (-10.0, -5.0) )
+        >>> tf.map_to_colormap(-8.0, -6.0, scale=10.0, colormap='algae')
+        >>> tf.map_to_colormap(-6.0, -5.0, scale=10.0, colormap='algae',
+        ...                    scale_func = linramp)
+        """
+
         rel0 = int(self.nbins*(mi - self.x_bounds[0])/(self.x_bounds[1] -
-            self.x_bounds[0]))
+                                                       self.x_bounds[0]))
         rel1 = int(self.nbins*(ma - self.x_bounds[0])/(self.x_bounds[1] -
-            self.x_bounds[0]))
+                                                       self.x_bounds[0]))
         rel0 = max(rel0, 0)
         rel1 = min(rel1, self.nbins-1)
-        tomap = np.linspace(0.,1.,num=rel1-rel0)
+        tomap = np.linspace(0., 1., num=rel1-rel0)
         cmap = get_cmap(colormap)
         cc = cmap(tomap)
         if scale_func is None:
             scale_mult = 1.0
         else:
-            scale_mult = scale_func(tomap,0.0,1.0)
-        self.red.y[rel0:rel1]  = cc[:,0]*scale_mult
-        self.green.y[rel0:rel1]= cc[:,1]*scale_mult
-        self.blue.y[rel0:rel1] = cc[:,2]*scale_mult
-        self.alpha.y[rel0:rel1]= scale*cc[:,3]*scale_mult
+            scale_mult = scale_func(tomap, 0.0, 1.0)
+        self.red.y[rel0:rel1] = cc[:, 0]*scale_mult
+        self.green.y[rel0:rel1] = cc[:, 1]*scale_mult
+        self.blue.y[rel0:rel1] = cc[:, 2]*scale_mult
+        self.alpha.y[rel0:rel1] = scale*cc[:, 3]*scale_mult
 
     def add_layers(self, N, w=None, mi=None, ma=None, alpha = None,
                    colormap="gist_stern", col_bounds = None):


https://bitbucket.org/yt_analysis/yt-3.0/commits/50570595c5a2/
Changeset:   50570595c5a2
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 18:41:06
Summary:     Abstracting out _num_zones, _num_ghost_zones and all the hardcoded 2's and 8's.
Affected #:  1 file

diff -r 1728ebb7cd28b8f7bba15db9cc7a9fbd84d3186a -r 50570595c5a2f3bb76e9cb096a814d271791cb33 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -91,9 +91,13 @@
             return tr
         return tr
 
+    @property
+    def nz(self):
+        return self._num_zones + 2*self._num_ghost_zones
+
     def _reshape_vals(self, arr):
         if len(arr.shape) == 4: return arr
-        nz = self._num_zones + 2*self._num_ghost_zones
+        nz = self.nz
         n_oct = arr.shape[0] / (nz**3.0)
         if arr.size == nz*nz*nz*n_oct:
             arr = arr.reshape((nz, nz, nz, n_oct), order="F")
@@ -125,7 +129,8 @@
         cls = getattr(particle_deposit, "deposit_%s" % method, None)
         if cls is None:
             raise YTParticleDepositionNotImplemented(method)
-        nvals = (2, 2, 2, (self.domain_ind >= 0).sum())
+        nz = self.nz
+        nvals = (nz, nz, nz, (self.domain_ind >= 0).sum())
         op = cls(nvals) # We allocate number of zones, not number of octs
         op.initialize()
         mylog.debug("Depositing %s (%s^3) particles into %s Octs",
@@ -141,7 +146,7 @@
     def select_icoords(self, dobj):
         d = self.oct_handler.icoords(self.selector, domain_id = self.domain_id,
                                      num_octs = self._num_octs)
-        self._num_octs = d.shape[0] / 8
+        self._num_octs = d.shape[0] / (self.nz**3)
         tr = self.oct_handler.selector_fill(dobj.selector, d, None, 0, 3,
                                             domain_id = self.domain_id)
         return tr
@@ -149,7 +154,7 @@
     def select_fcoords(self, dobj):
         d = self.oct_handler.fcoords(self.selector, domain_id = self.domain_id,
                                      num_octs = self._num_octs)
-        self._num_octs = d.shape[0] / 8
+        self._num_octs = d.shape[0] / (self.nz**3)
         tr = self.oct_handler.selector_fill(dobj.selector, d, None, 0, 3,
                                             domain_id = self.domain_id)
         return tr
@@ -157,7 +162,7 @@
     def select_fwidth(self, dobj):
         d = self.oct_handler.fwidth(self.selector, domain_id = self.domain_id,
                                   num_octs = self._num_octs)
-        self._num_octs = d.shape[0] / 8
+        self._num_octs = d.shape[0] / (self.nz**3)
         tr = self.oct_handler.selector_fill(dobj.selector, d, None, 0, 3,
                                             domain_id = self.domain_id)
         return tr
@@ -165,7 +170,7 @@
     def select_ires(self, dobj):
         d = self.oct_handler.ires(self.selector, domain_id = self.domain_id,
                                   num_octs = self._num_octs)
-        self._num_octs = d.shape[0] / 8
+        self._num_octs = d.shape[0] / (self.nz**3)
         tr = self.oct_handler.selector_fill(dobj.selector, d, None, 0, 1,
                                             domain_id = self.domain_id)
         return tr
@@ -222,7 +227,8 @@
         self.ind = None
         self.octree_subset = octree_subset
         # Cache some attributes
-        self.ActiveDimensions = np.array([2,2,2], dtype="int64")
+        nz = octree_subset.nz
+        self.ActiveDimensions = np.array([nz,nz,nz], dtype="int64")
         for attr in ["ires", "icoords", "fcoords", "fwidth"]:
             v = getattr(octree_subset, attr)
             setattr(self, "_%s" % attr, octree_subset._reshape_vals(v))


https://bitbucket.org/yt_analysis/yt-3.0/commits/f768678fb46d/
Changeset:   f768678fb46d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 20:10:06
Summary:     Enable selectors to be defined in other modules than selection_routines.

This will enable ARTIO and other frontends to define their own
selector_functions.
Affected #:  1 file

diff -r 50570595c5a2f3bb76e9cb096a814d271791cb33 -r f768678fb46dbdcbe05d29270fcc575359bc9d49 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -435,7 +435,9 @@
     @property
     def selector(self):
         if self._selector is not None: return self._selector
-        sclass = getattr(yt.geometry.selection_routines,
+        s_module = getattr(self, '_selector_module',
+                           yt.geometry.selection_routines)
+        sclass = getattr(s_module,
                          "%s_selector" % self._type_name, None)
         if sclass is None:
             raise YTDataSelectorNotImplemented(self._type_name)


https://bitbucket.org/yt_analysis/yt-3.0/commits/f71522f54c80/
Changeset:   f71522f54c80
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 20:11:13
Summary:     Initial implementation of a RootMeshContainer for ARTIO.

This is meant to take the place of the ARTIOOctreeContainer when the root mesh
is being examined.  It will implement the same methods as OctreeSubset and it
has its own selector object.
Affected #:  2 files

diff -r f768678fb46dbdcbe05d29270fcc575359bc9d49 -r f71522f54c8029619ac841c1dac6fad3346190b3 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -110,8 +110,8 @@
    
     
 cdef extern from "artio_internal.h":
-    np.int64_t artio_sfc_index( artio_fileset_handle *handle, int coords[3] )
-    void artio_sfc_coords( artio_fileset_handle *handle, int64_t index, int coords[3] )
+    np.int64_t artio_sfc_index( artio_fileset_handle *handle, int coords[3] ) nogil
+    void artio_sfc_coords( artio_fileset_handle *handle, int64_t index, int coords[3] ) nogil
 
 cdef void check_artio_status(int status, char *fname="[unknown]"):
     if status!=ARTIO_SUCCESS :
@@ -911,4 +911,243 @@
         free(primary_variables)
         free(secondary_variables)
         return data
- 
+
+cdef class ARTIORootMeshContainer:
+    cdef public artio_fileset artio_handle
+    cdef np.float64_t DLE[3]
+    cdef np.float64_t DRE[3]
+    cdef np.float64_t dds[3]
+    cdef np.int64_t dims[3]
+    cdef artio_fileset_handle *handle
+
+    def __init__(self, domain_dimensions, # cells
+                 domain_left_edge,
+                 domain_right_edge,
+                 artio_fileset artio_handle):
+        self.artio_handle = artio_handle
+        self.handle = artio_handle.handle
+        cdef int i
+        for i in range(3):
+            self.dims[i] = domain_dimensions[i]
+            self.DLE[i] = domain_left_edge[i]
+            self.DRE[i] = domain_right_edge[i]
+            self.dds[i] = (self.DRE[i] - self.DLE[i])/self.dims[i]
+
+    cdef np.int64_t pos_to_sfc(self, np.float64_t pos[3]) nogil:
+        # Calculate the index
+        cdef int coords[3], i
+        cdef np.int64_t sfc
+        for i in range(3):
+            coords[i] = <int>((pos[i] - self.DLE[i])/self.dds[i])
+        sfc = artio_sfc_index(self.handle, coords)
+        return sfc
+
+    cdef void sfc_to_pos(self, np.int64_t sfc, np.float64_t pos[3]) nogil:
+        cdef int coords[3], i
+        artio_sfc_coords(self.handle, sfc, coords)
+        for i in range(3):
+            pos[i] = self.DLE[i] + (coords[i] + 0.5) * self.dds[i]
+
+    cdef np.int64_t count_cells(self, SelectorObject selector):
+        # We visit each cell if it is not refined and determine whether it is
+        # included or not.
+        cdef np.int64_t sfc
+        cdef np.float64_t pos[3], right_edge[3]
+        cdef int num_cells = 0
+        cdef int i, eterm[3]
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            self.sfc_to_pos(sfc, pos)
+            num_cells += selector.select_cell(pos, self.dds, eterm)
+        return num_cells
+
+    def icoords(self, SelectorObject selector, np.int64_t num_octs = -1,
+                int domain_id = -1):
+        # Note that num_octs does not have to equal sfc_end - sfc_start + 1.
+        cdef np.int64_t sfc
+        cdef int acoords[3], i
+        # We call it num_octs, but it's really num_cells.
+        if num_octs == -1:
+            # We need to count, but this process will only occur one time,
+            # since num_octs will later be cached.
+            num_octs = self.sfc_start - self.sfc_end + 1
+        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+        cdef np.ndarray[np.int64_t, ndim=2] coords
+        coords = np.empty((num_octs, 3), dtype="int64")
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            # Note that we do *no* checks on refinement here.  In fact, this
+            # entire setup should not need to touch the disk except if the
+            # artio sfc calculators need to.
+            artio_sfc_coords(self.handle, sfc, acoords)
+            for i in range(3):
+                coords[sfc - self.sfc_start, i] = acoords[i]
+        return coords
+
+    def fcoords(self, SelectorObject selector, np.int64_t num_octs = -1,
+                int domain_id = -1):
+        # Note that num_octs does not have to equal sfc_end - sfc_start + 1.
+        cdef np.int64_t sfc
+        cdef np.float64_t pos[3]
+        cdef int acoords[3], i
+        # We call it num_octs, but it's really num_cells.
+        if num_octs == -1:
+            # We need to count, but this process will only occur one time,
+            # since num_octs will later be cached.
+            num_octs = self.sfc_start - self.sfc_end + 1
+        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+        cdef np.ndarray[np.float64_t, ndim=2] coords
+        coords = np.empty((num_octs, 3), dtype="float64")
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            # Note that we do *no* checks on refinement here.  In fact, this
+            # entire setup should not need to touch the disk except if the
+            # artio sfc calculators need to.
+            self.sfc_to_pos(sfc, pos)
+            for i in range(3):
+                coords[sfc - self.sfc_start, i] = pos[i]
+        return coords
+
+    def fwidth(self, SelectorObject selector, np.int64_t num_octs = -1,
+                int domain_id = -1):
+        cdef int i
+        if num_octs == -1:
+            # We need to count, but this process will only occur one time,
+            # since num_octs will later be cached.
+            num_octs = self.sfc_start - self.sfc_end + 1
+        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+        cdef np.ndarray[np.float64_t, ndim=2] width
+        width = np.zeros((num_octs, 3), dtype="float64")
+        for i in range(3):
+            width[:,i] = self.dds[i]
+        return width
+
+    def ires(self, SelectorObject selector, np.int64_t num_octs = -1,
+                int domain_id = -1):
+        if num_octs == -1:
+            # We need to count, but this process will only occur one time,
+            # since num_octs will later be cached.
+            num_octs = self.sfc_start - self.sfc_end + 1
+        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+        cdef np.ndarray[np.int64_t, ndim=1] res
+        res = np.zeros(num_octs, dtype="int64")
+        return res
+
+    def selector_fill(self, SelectorObject selector,
+                      np.ndarray source,
+                      np.ndarray dest = None,
+                      np.int64_t offset = 0, int dims = 1,
+                      int domain_id = -1):
+        # This is where we use the selector to transplant from one to the
+        # other.  Note that we *do* apply the selector here.
+        cdef np.int64_t num_cells = -1
+        cdef np.int64_t ind = offset
+        cdef np.int64_t sfc
+        cdef np.float64_t pos[3]
+        cdef int dim, status, eterm[3]
+        cdef int num_oct_levels, level
+        if dest is None:
+            # Note that RAMSES can have partial refinement inside an Oct.  This
+            # means we actually do want the number of Octs, not the number of
+            # cells.
+            num_cells = self.count_cells(selector)
+            if dims > 1:
+                dest = np.zeros((num_cells, dims), dtype=source.dtype,
+                    order='C')
+            else:
+                dest = np.zeros(num_cells, dtype=source.dtype, order='C')
+        status = artio_grid_cache_sfc_range(self.handle, self.sfc_start,
+                                            self.sfc_end)
+        check_artio_status(status) 
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            # We check if the SFC is in our selector, and if so, we copy
+            self.sfc_to_pos(sfc, pos)
+            if selector.select_cell(pos, self.dds, eterm) == 0: continue
+            # Now we just need to check if the cells are refined.
+            status = artio_grid_read_root_cell_begin( self.handle,
+                sfc, NULL, NULL, &num_oct_levels, NULL)
+            check_artio_status(status)
+            status = artio_grid_read_root_cell_end( self.handle )
+            check_artio_status(status)
+            # If refined, we skip
+            if num_oct_levels > 0: continue
+            if dims > 1:
+                for dim in range(dims):
+                    dest[ind, dim] = source[sfc - self.sfc_start, dim]
+            else:
+                dest[ind] = source[sfc - self.sfc_start]
+            ind += 1
+
+        artio_grid_clear_sfc_cache(self.handle)
+        return ind - offset
+
+    def domain_ind(self, selector, int domain_id = -1):
+        raise NotImplementedError
+
+    def mask(self, SelectorObject selector, np.int64_t num_octs = -1,
+             int domain_id = -1):
+        raise NotImplementedError
+        
+
+cdef class RootMeshSubsetSelector(SelectorObject):
+    # This is a numpy array, which will be a bool of ndim 1
+    cdef np.uint64_t sfc_start
+    cdef np.uint64_t sfc_end
+    cdef SelectorObject base_selector
+    cdef ARTIORootMeshContainer root_mesh
+
+    def __init__(self, dobj):
+        self.sfc_start = dobj.sfc_start
+        self.sfc_end = dobj.sfc_end
+        self.root_mesh = dobj.oct_handler
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef void set_bounds(self,
+                         np.float64_t left_edge[3], np.float64_t right_edge[3],
+                         np.float64_t dds[3], int ind[3][2], int *check):
+        check[0] = 0
+        return
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    def select_grids(self,
+                     np.ndarray[np.float64_t, ndim=2] left_edges,
+                     np.ndarray[np.float64_t, ndim=2] right_edges,
+                     np.ndarray[np.int32_t, ndim=2] levels):
+        raise RuntimeError
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
+                         int eterm[3]) nogil:
+        cdef np.int64_t sfc
+        sfc = self.root_mesh.pos_to_sfc(pos)
+        if sfc >= self.sfc_start and sfc <= self.sfc_end:
+            return 1
+        return 0
+
+    cdef int select_grid(self, np.float64_t left_edge[3],
+                         np.float64_t right_edge[3], np.int32_t level,
+                         Oct *o = NULL) nogil:
+        cdef np.float64_t pos[3], v[2][3], dds[3]
+        cdef int i, j, k, eterm[3]
+        # We check each of the eight corners
+        for i in range(3):
+            v[0][i] = left_edge[i]
+            v[1][i] = right_edge[i]
+            dds[i] = (right_edge[i] - left_edge[i])
+        for i in range(2):
+            for j in range(2):
+                for k in range(2):
+                    pos[0] = v[i][0]
+                    pos[1] = v[j][1]
+                    pos[2] = v[k][2]
+                    status = self.select_cell(pos, dds, eterm)
+                    if status == 1:
+                        # Early termination
+                        return 1
+        return 0
+
+sfc_subset_selector = RootMeshSubsetSelector
+

diff -r f768678fb46dbdcbe05d29270fcc575359bc9d49 -r f71522f54c8029619ac841c1dac6fad3346190b3 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -29,7 +29,9 @@
 
 from .definitions import yt_to_art, art_to_yt, ARTIOconstants
 from _artio_caller import \
-    artio_is_valid, artio_fileset, ARTIOOctreeContainer
+    artio_is_valid, artio_fileset, ARTIOOctreeContainer, \
+    ARTIORootMeshContainer
+import _artio_caller
 from yt.utilities.definitions import \
     mpc_conversion, sec_conversion
 from .fields import ARTIOFieldInfo, KnownARTIOFields, b2t
@@ -131,6 +133,24 @@
                 cp += v.size
         return tr
 
+# We create something of a fake octree here.  This is primarily to enable us to
+# reuse code for things like __getitem__ and the like.  We will also create a
+# new oct_handler type that is functionally equivalent, except that it will
+# only manage the root mesh.
+class ARTIORootMeshSubset(ARTIOOctreeSubset):
+    _num_zones = 1
+    _type_name = 'sfc_subset'
+    _selector_module = _artio_caller
+
+    @property
+    def oct_handler(self):
+        if self._oct_handler is None: 
+            self._oct_handler = ARTIORootMeshContainer(
+                self.pf.domain_dimensions, # Cells, not octs
+                self.pf.domain_left_edge, self.pf.domain_right_edge,
+                self.pf._handle)
+        return self._oct_handler
+
 class ARTIOChunk(object):
 
     def __init__(self, pf, sfc_start, sfc_end):


https://bitbucket.org/yt_analysis/yt-3.0/commits/fc5d5462154b/
Changeset:   fc5d5462154b
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 20:43:32
Summary:     Removing SFC mesh selector and replace with AlwaysSelector.  Fix
num_octs_per_level pointer.  Various fixes to the root mesh.  Enable chunking.
Affected #:  3 files

diff -r f71522f54c8029619ac841c1dac6fad3346190b3 -r fc5d5462154bb09c3da1d981e48b98d7fe1f579e yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -6,7 +6,7 @@
 cimport numpy as np
 import sys 
 
-from yt.geometry.selection_routines cimport SelectorObject
+from yt.geometry.selection_routines cimport SelectorObject, AlwaysSelector
 from yt.geometry.oct_container cimport \
     OctreeContainer, OctAllocationContainer, \
     SparseOctreeContainer
@@ -919,11 +919,14 @@
     cdef np.float64_t dds[3]
     cdef np.int64_t dims[3]
     cdef artio_fileset_handle *handle
+    cdef np.uint64_t sfc_start
+    cdef np.uint64_t sfc_end
 
     def __init__(self, domain_dimensions, # cells
                  domain_left_edge,
                  domain_right_edge,
-                 artio_fileset artio_handle):
+                 artio_fileset artio_handle,
+                 sfc_start, sfc_end):
         self.artio_handle = artio_handle
         self.handle = artio_handle.handle
         cdef int i
@@ -932,6 +935,8 @@
             self.DLE[i] = domain_left_edge[i]
             self.DRE[i] = domain_right_edge[i]
             self.dds[i] = (self.DRE[i] - self.DLE[i])/self.dims[i]
+        self.sfc_start = sfc_start
+        self.sfc_end = sfc_end
 
     cdef np.int64_t pos_to_sfc(self, np.float64_t pos[3]) nogil:
         # Calculate the index
@@ -969,8 +974,8 @@
         if num_octs == -1:
             # We need to count, but this process will only occur one time,
             # since num_octs will later be cached.
-            num_octs = self.sfc_start - self.sfc_end + 1
-        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+            num_octs = self.sfc_end - self.sfc_start + 1
+        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
         cdef np.ndarray[np.int64_t, ndim=2] coords
         coords = np.empty((num_octs, 3), dtype="int64")
         for sfc in range(self.sfc_start, self.sfc_end + 1):
@@ -992,8 +997,8 @@
         if num_octs == -1:
             # We need to count, but this process will only occur one time,
             # since num_octs will later be cached.
-            num_octs = self.sfc_start - self.sfc_end + 1
-        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+            num_octs = self.sfc_end - self.sfc_start + 1
+        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
         cdef np.ndarray[np.float64_t, ndim=2] coords
         coords = np.empty((num_octs, 3), dtype="float64")
         for sfc in range(self.sfc_start, self.sfc_end + 1):
@@ -1011,8 +1016,8 @@
         if num_octs == -1:
             # We need to count, but this process will only occur one time,
             # since num_octs will later be cached.
-            num_octs = self.sfc_start - self.sfc_end + 1
-        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+            num_octs = self.sfc_end - self.sfc_start + 1
+        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
         cdef np.ndarray[np.float64_t, ndim=2] width
         width = np.zeros((num_octs, 3), dtype="float64")
         for i in range(3):
@@ -1024,8 +1029,8 @@
         if num_octs == -1:
             # We need to count, but this process will only occur one time,
             # since num_octs will later be cached.
-            num_octs = self.sfc_start - self.sfc_end + 1
-        assert(num_octs == (self.sfc_start - self.sfc_end + 1))
+            num_octs = self.sfc_end - self.sfc_start + 1
+        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
         cdef np.ndarray[np.int64_t, ndim=1] res
         res = np.zeros(num_octs, dtype="int64")
         return res
@@ -1041,8 +1046,12 @@
         cdef np.int64_t ind = offset
         cdef np.int64_t sfc
         cdef np.float64_t pos[3]
+        cdef np.float64_t dpos[3]
         cdef int dim, status, eterm[3]
         cdef int num_oct_levels, level
+        cdef int max_level = self.artio_handle.max_level
+        cdef int *num_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
         if dest is None:
             # Note that RAMSES can have partial refinement inside an Oct.  This
             # means we actually do want the number of Octs, not the number of
@@ -1062,7 +1071,7 @@
             if selector.select_cell(pos, self.dds, eterm) == 0: continue
             # Now we just need to check if the cells are refined.
             status = artio_grid_read_root_cell_begin( self.handle,
-                sfc, NULL, NULL, &num_oct_levels, NULL)
+                sfc, dpos, NULL, &num_oct_levels, num_octs_per_level)
             check_artio_status(status)
             status = artio_grid_read_root_cell_end( self.handle )
             check_artio_status(status)
@@ -1076,6 +1085,9 @@
             ind += 1
 
         artio_grid_clear_sfc_cache(self.handle)
+        free(num_octs_per_level)
+        if num_cells >= 0:
+            return dest
         return ind - offset
 
     def domain_ind(self, selector, int domain_id = -1):
@@ -1085,69 +1097,5 @@
              int domain_id = -1):
         raise NotImplementedError
         
+sfc_subset_selector = AlwaysSelector
 
-cdef class RootMeshSubsetSelector(SelectorObject):
-    # This is a numpy array, which will be a bool of ndim 1
-    cdef np.uint64_t sfc_start
-    cdef np.uint64_t sfc_end
-    cdef SelectorObject base_selector
-    cdef ARTIORootMeshContainer root_mesh
-
-    def __init__(self, dobj):
-        self.sfc_start = dobj.sfc_start
-        self.sfc_end = dobj.sfc_end
-        self.root_mesh = dobj.oct_handler
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    def select_grids(self,
-                     np.ndarray[np.float64_t, ndim=2] left_edges,
-                     np.ndarray[np.float64_t, ndim=2] right_edges,
-                     np.ndarray[np.int32_t, ndim=2] levels):
-        raise RuntimeError
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.int64_t sfc
-        sfc = self.root_mesh.pos_to_sfc(pos)
-        if sfc >= self.sfc_start and sfc <= self.sfc_end:
-            return 1
-        return 0
-
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                         np.float64_t right_edge[3], np.int32_t level,
-                         Oct *o = NULL) nogil:
-        cdef np.float64_t pos[3], v[2][3], dds[3]
-        cdef int i, j, k, eterm[3]
-        # We check each of the eight corners
-        for i in range(3):
-            v[0][i] = left_edge[i]
-            v[1][i] = right_edge[i]
-            dds[i] = (right_edge[i] - left_edge[i])
-        for i in range(2):
-            for j in range(2):
-                for k in range(2):
-                    pos[0] = v[i][0]
-                    pos[1] = v[j][1]
-                    pos[2] = v[k][2]
-                    status = self.select_cell(pos, dds, eterm)
-                    if status == 1:
-                        # Early termination
-                        return 1
-        return 0
-
-sfc_subset_selector = RootMeshSubsetSelector
-

diff -r f71522f54c8029619ac841c1dac6fad3346190b3 -r fc5d5462154bb09c3da1d981e48b98d7fe1f579e yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -55,6 +55,7 @@
     domain_id = 1
     _con_args = ("base_region", "sfc_start", "sfc_end", "pf")
     _type_name = 'octree_subset'
+    min_level = 1
 
     def __init__(self, base_region, sfc_start, sfc_end, pf):
         self.field_data = YTFieldData()
@@ -141,6 +142,7 @@
     _num_zones = 1
     _type_name = 'sfc_subset'
     _selector_module = _artio_caller
+    min_level = 0
 
     @property
     def oct_handler(self):
@@ -148,7 +150,8 @@
             self._oct_handler = ARTIORootMeshContainer(
                 self.pf.domain_dimensions, # Cells, not octs
                 self.pf.domain_left_edge, self.pf.domain_right_edge,
-                self.pf._handle)
+                self.pf._handle,
+                self.sfc_start, self.sfc_end)
         return self._oct_handler
 
 class ARTIOChunk(object):
@@ -325,9 +328,11 @@
                 mylog.debug("Running selector on artio base grid")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges(
                     dobj.selector)
-            dobj._chunk_info = [ARTIOOctreeSubset(base_region,
-                                    start, end, self.pf)
-                                for (start, end) in list_sfc_ranges]
+            ci =  [ARTIORootMeshSubset(base_region, start, end, self.pf)
+                   for (start, end) in list_sfc_ranges]
+            ci += [ARTIOOctreeSubset(base_region, start, end, self.pf)
+                   for (start, end) in list_sfc_ranges]
+            dobj._chunk_info = ci
             mylog.info("Created %d chunks for ARTIO" % len(list_sfc_ranges))
         dobj._current_chunk = list(self._chunk_all(dobj))[0]
 

diff -r f71522f54c8029619ac841c1dac6fad3346190b3 -r fc5d5462154bb09c3da1d981e48b98d7fe1f579e yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -46,3 +46,6 @@
     cdef void set_bounds(self,
                          np.float64_t left_edge[3], np.float64_t right_edge[3],
                          np.float64_t dds[3], int ind[3][2], int *check)
+
+cdef class AlwaysSelector(SelectorObject):
+    pass


https://bitbucket.org/yt_analysis/yt-3.0/commits/c339d3655862/
Changeset:   c339d3655862
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 21:10:44
Summary:     In ARTIOOctreeContainer, root mesh nodes are now domain==2.

This allows the unified chunking system to present the correct volume to the
user.
Affected #:  2 files

diff -r fc5d5462154bb09c3da1d981e48b98d7fe1f579e -r c339d365586272c6e49c0e4e081b8eb161566279 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -632,7 +632,7 @@
         for i in range(max_level + 1):
             self.level_indices[i] = tot
             tot += tot_octs_per_level[i]
-        self.allocate_domains([tot], num_root)
+        self.allocate_domains([tot - num_root, num_root], num_root)
         # Now we have everything counted, and we need to create the appropriate
         # number of arrays.
         cdef np.ndarray[np.float64_t, ndim=2] pos
@@ -675,17 +675,25 @@
         nadded = 0
         cdef np.int64_t si, ei
         si = 0
+        # We initialize domain to 2 so that all root mesh octs are viewed as
+        # not belonging to this domain.  This way we don't get confused with
+        # how the different meshes are interfaced, and the root mesh container
+        # will own all the root mesh octs.
+        cdef int domain = 2
         for level in range(max_level + 1):
             self.level_indices[level] = si
             ei = si + tot_octs_per_level[level]
             if tot_octs_per_level[level] == 0: break
-            nadded = self.add(1, level, pos[si:ei, :])
-            if nadded != (ei - si):
+            nadded = self.add(domain, level, pos[si:ei, :])
+            if level > 0 and nadded != (ei - si):
+                print domain, self.sfc_start, self.sfc_end
                 print level, nadded, ei, si, self.max_root,
                 print self.level_indices[level]
                 print pos[si:ei,:]
+                print nadded, (ei - si), tot_octs_per_level[0]
                 raise RuntimeError
             si = ei
+            domain = 1 # Switch back to 1
         artio_grid_clear_sfc_cache(handle)
         free(mask)
         free(num_octs_per_level)

diff -r fc5d5462154bb09c3da1d981e48b98d7fe1f579e -r c339d365586272c6e49c0e4e081b8eb161566279 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -49,13 +49,11 @@
 from yt.data_objects.field_info_container import \
     FieldInfoContainer, NullFunc
 
-
 class ARTIOOctreeSubset(OctreeSubset):
     _domain_offset = 0
     domain_id = 1
     _con_args = ("base_region", "sfc_start", "sfc_end", "pf")
     _type_name = 'octree_subset'
-    min_level = 1
 
     def __init__(self, base_region, sfc_start, sfc_end, pf):
         self.field_data = YTFieldData()
@@ -142,7 +140,6 @@
     _num_zones = 1
     _type_name = 'sfc_subset'
     _selector_module = _artio_caller
-    min_level = 0
 
     @property
     def oct_handler(self):


https://bitbucket.org/yt_analysis/yt-3.0/commits/413a6845596d/
Changeset:   413a6845596d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 21:20:54
Summary:     Implementing mask operation for ARTIORootMeshContainer.
Affected #:  1 file

diff -r c339d365586272c6e49c0e4e081b8eb161566279 -r 413a6845596d74d735892ab77cc405d745b29a64 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -1098,12 +1098,42 @@
             return dest
         return ind - offset
 
-    def domain_ind(self, selector, int domain_id = -1):
-        raise NotImplementedError
-
-    def mask(self, SelectorObject selector, np.int64_t num_octs = -1,
-             int domain_id = -1):
-        raise NotImplementedError
+    def mask(self, SelectorObject selector, np.int64_t num_octs = -1):
+        cdef int i, status, eterm[3]
+        cdef double dpos[3]
+        cdef np.float64_t pos[3]
+        if num_octs == -1:
+            # We need to count, but this process will only occur one time,
+            # since num_octs will later be cached.
+            num_octs = self.sfc_end - self.sfc_start + 1
+        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
+        cdef np.ndarray[np.uint8_t, ndim=1] mask
+        cdef int num_oct_levels
+        cdef int max_level = self.artio_handle.max_level
+        cdef int *num_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
+        mask = np.zeros((num_octs * 8), dtype="uint8")
+        status = artio_grid_cache_sfc_range(self.handle, self.sfc_start,
+                                            self.sfc_end)
+        check_artio_status(status) 
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            # We check if the SFC is in our selector, and if so, we copy
+            # Note that because we initialize to zeros, we can just continue if
+            # it's not included.
+            self.sfc_to_pos(sfc, pos)
+            if selector.select_cell(pos, self.dds, eterm) == 0: continue
+            # Now we just need to check if the cells are refined.
+            status = artio_grid_read_root_cell_begin( self.handle,
+                sfc, dpos, NULL, &num_oct_levels, num_octs_per_level)
+            check_artio_status(status)
+            status = artio_grid_read_root_cell_end( self.handle )
+            check_artio_status(status)
+            # If refined, we skip
+            if num_oct_levels > 0: continue
+            mask[sfc - self.sfc_start] = 1
+        artio_grid_clear_sfc_cache(self.handle)
+        free(num_octs_per_level)
+        return mask.astype("bool")
         
 sfc_subset_selector = AlwaysSelector
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/1e11f03ded11/
Changeset:   1e11f03ded11
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 23:25:11
Summary:     Pulling particle IO into a top-level function, to reuse between root and oct.
Affected #:  1 file

diff -r 413a6845596d74d735892ab77cc405d745b29a64 -r 1e11f03ded11a775ea82e13614549a8a43bdc4a4 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -780,145 +780,153 @@
         free(num_octs_per_level)
 
     def fill_sfc_particles(self, fields):
-        cdef int status, ispec, subspecies
-        cdef np.int64_t sfc, particle, pid, ind, vind
-        cdef int num_species = self.artio_handle.num_species
-        cdef artio_fileset_handle *handle = self.artio_handle.handle
-        cdef int *num_particles_per_species =  <int *>malloc(
-            sizeof(int)*num_species) 
-        cdef int *accessed_species =  <int *>malloc(
-            sizeof(int)*num_species) 
-        cdef int *total_particles = <int *>malloc(
-            sizeof(int)*num_species) 
-        cdef particle_var_pointers *vpoints = <particle_var_pointers *> malloc(
-            sizeof(particle_var_pointers)*num_species)
-        cdef double *primary_variables
-        cdef float *secondary_variables
-        cdef np.int64_t tp
+        rv = read_sfc_particles(self.artio_handle,
+                                self.sfc_start, self.sfc_end,
+                                0, fields)
+        return rv
 
-        cdef np.ndarray[np.int8_t, ndim=1] npi8arr
-        cdef np.ndarray[np.int64_t, ndim=1] npi64arr
-        cdef np.ndarray[np.float64_t, ndim=1] npf64arr
+cdef read_sfc_particles(artio_fileset artio_handle,
+                        np.int64_t sfc_start, np.int64_t sfc_end,
+                        int read_unrefined, fields):
+    cdef int status, ispec, subspecies
+    cdef np.int64_t sfc, particle, pid, ind, vind
+    cdef int num_species = artio_handle.num_species
+    cdef artio_fileset_handle *handle = artio_handle.handle
+    cdef int *num_particles_per_species =  <int *>malloc(
+        sizeof(int)*num_species) 
+    cdef int *accessed_species =  <int *>malloc(
+        sizeof(int)*num_species) 
+    cdef int *total_particles = <int *>malloc(
+        sizeof(int)*num_species) 
+    cdef particle_var_pointers *vpoints = <particle_var_pointers *> malloc(
+        sizeof(particle_var_pointers)*num_species)
+    cdef double *primary_variables
+    cdef float *secondary_variables
+    cdef np.int64_t tp
 
-        # Now we set up our field pointers
-        params = self.artio_handle.parameters
+    cdef np.ndarray[np.int8_t, ndim=1] npi8arr
+    cdef np.ndarray[np.int64_t, ndim=1] npi64arr
+    cdef np.ndarray[np.float64_t, ndim=1] npf64arr
 
-        npri_vars = params["num_primary_variables"]
-        nsec_vars = params["num_secondary_variables"]
-        primary_variables = <double *>malloc(sizeof(double) * max(npri_vars))
-        secondary_variables = <float *>malloc(sizeof(float) * max(nsec_vars))
+    # Now we set up our field pointers
+    params = artio_handle.parameters
 
-        cdef particle_var_pointers *vp
+    npri_vars = params["num_primary_variables"]
+    nsec_vars = params["num_secondary_variables"]
+    primary_variables = <double *>malloc(sizeof(double) * max(npri_vars))
+    secondary_variables = <float *>malloc(sizeof(float) * max(nsec_vars))
+
+    cdef particle_var_pointers *vp
+
+    for ispec in range(num_species):
+        total_particles[ispec] = 0
+        accessed_species[ispec] = 0
+        # Initialize our vpoints array
+        vpoints[ispec].count = 0
+        vpoints[ispec].n_mass = 0
+        vpoints[ispec].n_pid = 0
+        vpoints[ispec].n_species = 0
+        vpoints[ispec].n_p = 0
+        vpoints[ispec].n_s = 0
+
+    status = artio_particle_cache_sfc_range( handle,
+            sfc_start, sfc_end ) 
+    check_artio_status(status)
+
+    # Pass through once.  We want every single particle.
+    for sfc in range(sfc_start, sfc_end + 1):
+        status = artio_particle_read_root_cell_begin( handle, sfc,
+                num_particles_per_species )
+        check_artio_status(status)
 
         for ispec in range(num_species):
-            total_particles[ispec] = 0
-            accessed_species[ispec] = 0
-            # Initialize our vpoints array
-            vpoints[ispec].count = 0
-            vpoints[ispec].n_mass = 0
-            vpoints[ispec].n_pid = 0
-            vpoints[ispec].n_species = 0
-            vpoints[ispec].n_p = 0
-            vpoints[ispec].n_s = 0
+            total_particles[ispec] += num_particles_per_species[ispec]
 
-        status = artio_particle_cache_sfc_range( handle,
-                self.sfc_start, self.sfc_end ) 
+        status = artio_particle_read_root_cell_end( handle )
         check_artio_status(status)
 
-        # Pass through once.  We want every single particle.
-        for sfc in range(self.sfc_start, self.sfc_end + 1):
-            status = artio_particle_read_root_cell_begin( handle, sfc,
-                    num_particles_per_species )
+    # Now we allocate our final fields, which will be filled
+    #for ispec in range(num_species):
+    #    print "In SFC %s to %s reading %s of species %s" % (
+    #        sfc_start, sfc_end + 1, total_particles[ispec], ispec)
+    data = {}
+    for species, field in sorted(fields):
+        accessed_species[species] = 1
+        pri_vars = params.get(
+            "species_%02u_primary_variable_labels" % (species,), [])
+        sec_vars = params.get(
+            "species_%02u_secondary_variable_labels" % (species,), [])
+        tp = total_particles[species]
+        vp = &vpoints[species]
+        if field == "MASS":
+            vp.n_mass = 1
+            npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
+            # We fill this *now*
+            npf64arr += params["particle_species_mass"][species]
+            vp.mass = <np.float64_t*> npf64arr.data
+        elif field == "PID":
+            vp.n_pid = 1
+            npi64arr = data[(species, field)] = np.zeros(tp, dtype="int64")
+            vp.pid = <np.int64_t*> npi64arr.data
+        elif field == "SPECIES":
+            vp.n_species = 1
+            npi8arr = data[(species, field)] = np.zeros(tp, dtype="int8")
+            # We fill this *now*
+            npi8arr += species
+            vp.species = <np.int8_t*> npi8arr.data
+        elif npri_vars[species] > 0 and field in pri_vars :
+            npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
+            vp.p_ind[vp.n_p] = pri_vars.index(field)
+            vp.pvars[vp.n_p] = <np.float64_t *> npf64arr.data
+            vp.n_p += 1
+        elif nsec_vars[species] > 0 and field in sec_vars :
+            npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
+            vp.s_ind[vp.n_s] = sec_vars.index(field)
+            vp.svars[vp.n_s] = <np.float64_t *> npf64arr.data
+            vp.n_s += 1
+
+    for sfc in range(sfc_start, sfc_end + 1):
+        status = artio_particle_read_root_cell_begin( handle, sfc,
+                num_particles_per_species )
+        check_artio_status(status)
+        for ispec in range(num_species) : 
+            if accessed_species[ispec] == 0: continue
+            status = artio_particle_read_species_begin(handle, ispec);
             check_artio_status(status)
+            vp = &vpoints[ispec]
 
-            for ispec in range(num_species):
-                total_particles[ispec] += num_particles_per_species[ispec]
+            for particle in range(num_particles_per_species[ispec]) :
+                status = artio_particle_read_particle(handle,
+                        &pid, &subspecies, primary_variables,
+                        secondary_variables)
+                check_artio_status(status)
+                ind = vp.count
 
-            status = artio_particle_read_root_cell_end( handle )
+                for i in range(vp.n_p):
+                    vind = vp.p_ind[i]
+                    vp.pvars[i][ind] = primary_variables[vind]
+                    
+                for i in range(vp.n_s):
+                    vind = vp.s_ind[i]
+                    vp.svars[i][ind] = secondary_variables[vind]
+                    
+                if vp.n_pid:
+                    vp.pid[ind] = pid
+
+                vp.count += 1
+
+            status = artio_particle_read_species_end( handle )
             check_artio_status(status)
-
-        # Now we allocate our final fields, which will be filled
-        #for ispec in range(num_species):
-        #    print "In SFC %s to %s reading %s of species %s" % (
-        #        self.sfc_start, self.sfc_end + 1, total_particles[ispec], ispec)
-        data = {}
-        for species, field in sorted(fields):
-            accessed_species[species] = 1
-            pri_vars = params.get(
-                "species_%02u_primary_variable_labels" % (species,), [])
-            sec_vars = params.get(
-                "species_%02u_secondary_variable_labels" % (species,), [])
-            tp = total_particles[species]
-            vp = &vpoints[species]
-            if field == "MASS":
-                vp.n_mass = 1
-                npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
-                # We fill this *now*
-                npf64arr += params["particle_species_mass"][species]
-                vp.mass = <np.float64_t*> npf64arr.data
-            elif field == "PID":
-                vp.n_pid = 1
-                npi64arr = data[(species, field)] = np.zeros(tp, dtype="int64")
-                vp.pid = <np.int64_t*> npi64arr.data
-            elif field == "SPECIES":
-                vp.n_species = 1
-                npi8arr = data[(species, field)] = np.zeros(tp, dtype="int8")
-                # We fill this *now*
-                npi8arr += species
-                vp.species = <np.int8_t*> npi8arr.data
-            elif npri_vars[species] > 0 and field in pri_vars :
-                npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
-                vp.p_ind[vp.n_p] = pri_vars.index(field)
-                vp.pvars[vp.n_p] = <np.float64_t *> npf64arr.data
-                vp.n_p += 1
-            elif nsec_vars[species] > 0 and field in sec_vars :
-                npf64arr = data[(species, field)] = np.zeros(tp, dtype="float64")
-                vp.s_ind[vp.n_s] = sec_vars.index(field)
-                vp.svars[vp.n_s] = <np.float64_t *> npf64arr.data
-                vp.n_s += 1
-
-        for sfc in range(self.sfc_start, self.sfc_end + 1):
-            status = artio_particle_read_root_cell_begin( handle, sfc,
-                    num_particles_per_species )
-            check_artio_status(status)
-            for ispec in range(num_species) : 
-                if accessed_species[ispec] == 0: continue
-                status = artio_particle_read_species_begin(handle, ispec);
-                check_artio_status(status)
-                vp = &vpoints[ispec]
- 
-                for particle in range(num_particles_per_species[ispec]) :
-                    status = artio_particle_read_particle(handle,
-                            &pid, &subspecies, primary_variables,
-                            secondary_variables)
-                    check_artio_status(status)
-                    ind = vp.count
-
-                    for i in range(vp.n_p):
-                        vind = vp.p_ind[i]
-                        vp.pvars[i][ind] = primary_variables[vind]
-                        
-                    for i in range(vp.n_s):
-                        vind = vp.s_ind[i]
-                        vp.svars[i][ind] = secondary_variables[vind]
-                        
-                    if vp.n_pid:
-                        vp.pid[ind] = pid
-
-                    vp.count += 1
-
-                status = artio_particle_read_species_end( handle )
-                check_artio_status(status)
-                    
-            status = artio_particle_read_root_cell_end( handle )
-            check_artio_status(status)
-        free(num_particles_per_species)
-        free(total_particles)
-        free(accessed_species)
-        free(vpoints)
-        free(primary_variables)
-        free(secondary_variables)
-        return data
+                
+        status = artio_particle_read_root_cell_end( handle )
+        check_artio_status(status)
+    free(num_particles_per_species)
+    free(total_particles)
+    free(accessed_species)
+    free(vpoints)
+    free(primary_variables)
+    free(secondary_variables)
+    return data
 
 cdef class ARTIORootMeshContainer:
     cdef public artio_fileset artio_handle
@@ -1134,6 +1142,6 @@
         artio_grid_clear_sfc_cache(self.handle)
         free(num_octs_per_level)
         return mask.astype("bool")
-        
+
 sfc_subset_selector = AlwaysSelector
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/5134c3adc446/
Changeset:   5134c3adc446
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 23:36:06
Summary:     Adding a read_unrefined argument to read_sfc_particles.
Affected #:  2 files

diff -r 1e11f03ded11a775ea82e13614549a8a43bdc4a4 -r 5134c3adc44688ad9e7f9d97e0dacffbbe4ae90c yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -105,6 +105,7 @@
     int artio_particle_read_particle(artio_fileset_handle *handle, int64_t *pid, int *subspecies,
                         double *primary_variables, float *secondary_variables)
     int artio_particle_cache_sfc_range(artio_fileset_handle *handle, int64_t sfc_start, int64_t sfc_end)
+    int artio_particle_clear_sfc_cache(artio_fileset_handle *handle)
     int artio_particle_read_species_begin(artio_fileset_handle *handle, int species)
     int artio_particle_read_species_end(artio_fileset_handle *handle) 
    
@@ -792,6 +793,7 @@
     cdef np.int64_t sfc, particle, pid, ind, vind
     cdef int num_species = artio_handle.num_species
     cdef artio_fileset_handle *handle = artio_handle.handle
+    cdef int num_oct_levels
     cdef int *num_particles_per_species =  <int *>malloc(
         sizeof(int)*num_species) 
     cdef int *accessed_species =  <int *>malloc(
@@ -800,9 +802,12 @@
         sizeof(int)*num_species) 
     cdef particle_var_pointers *vpoints = <particle_var_pointers *> malloc(
         sizeof(particle_var_pointers)*num_species)
-    cdef double *primary_variables
+    cdef double *primary_variables, dpos[3]
     cdef float *secondary_variables
     cdef np.int64_t tp
+    cdef int max_level = artio_handle.max_level
+    cdef int *num_octs_per_level = <int *>malloc(
+        (max_level + 1)*sizeof(int))
 
     cdef np.ndarray[np.int8_t, ndim=1] npi8arr
     cdef np.ndarray[np.int64_t, ndim=1] npi64arr
@@ -833,8 +838,19 @@
             sfc_start, sfc_end ) 
     check_artio_status(status)
 
+    # We cache so we can figure out if the cell is refined or not.
+    status = artio_grid_cache_sfc_range(handle, sfc_start, sfc_end)
+    check_artio_status(status) 
+
     # Pass through once.  We want every single particle.
     for sfc in range(sfc_start, sfc_end + 1):
+        status = artio_grid_read_root_cell_begin( handle,
+            sfc, dpos, NULL, &num_oct_levels, num_octs_per_level)
+        check_artio_status(status)
+        status = artio_grid_read_root_cell_end(handle)
+        check_artio_status(status)
+        if read_unrefined == 1 and num_oct_levels > 0: continue
+        if read_unrefined == 0 and num_oct_levels == 0: continue
         status = artio_particle_read_root_cell_begin( handle, sfc,
                 num_particles_per_species )
         check_artio_status(status)
@@ -886,6 +902,13 @@
             vp.n_s += 1
 
     for sfc in range(sfc_start, sfc_end + 1):
+        status = artio_grid_read_root_cell_begin( handle,
+            sfc, dpos, NULL, &num_oct_levels, num_octs_per_level)
+        check_artio_status(status)
+        status = artio_grid_read_root_cell_end(handle)
+        check_artio_status(status)
+        if read_unrefined == 1 and num_oct_levels > 0: continue
+        if read_unrefined == 0 and num_oct_levels == 0: continue
         status = artio_particle_read_root_cell_begin( handle, sfc,
                 num_particles_per_species )
         check_artio_status(status)
@@ -920,6 +943,14 @@
                 
         status = artio_particle_read_root_cell_end( handle )
         check_artio_status(status)
+
+    status = artio_particle_clear_sfc_cache(handle)
+    check_artio_status(status)
+
+    status = artio_grid_clear_sfc_cache(handle)
+    check_artio_status(status)
+
+    free(num_octs_per_level)
     free(num_particles_per_species)
     free(total_particles)
     free(accessed_species)
@@ -1143,5 +1174,12 @@
         free(num_octs_per_level)
         return mask.astype("bool")
 
+    def fill_sfc_particles(self, fields):
+        rv = read_sfc_particles(self.artio_handle,
+                                self.sfc_start, self.sfc_end,
+                                1, fields)
+        return rv
+
+
 sfc_subset_selector = AlwaysSelector
 

diff -r 1e11f03ded11a775ea82e13614549a8a43bdc4a4 -r 5134c3adc44688ad9e7f9d97e0dacffbbe4ae90c yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -151,6 +151,16 @@
                 self.sfc_start, self.sfc_end)
         return self._oct_handler
 
+    def fill(self, fields, selector):
+        # We know how big these will be.
+        field_indices = [handle.parameters["grid_variable_labels"].index(
+                        yt_to_art[f]) for (ft, f) in fields]
+        self.data_size = cell_count = self.sfc_end - self.sfc_start + 1
+        tr = [np.zeros(cell_count, dtype="float64") for field in fields]
+        self.oct_handler.fill_sfc(field_indices, tr)
+        tr = dict((field, v) for field, v in zip(fields, tr))
+        return tr
+
 class ARTIOChunk(object):
 
     def __init__(self, pf, sfc_start, sfc_end):


https://bitbucket.org/yt_analysis/yt-3.0/commits/a2a48b4e5a2c/
Changeset:   a2a48b4e5a2c
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-15 23:43:56
Summary:     Initial impementation of fill_sfc for root mesh.
Affected #:  1 file

diff -r 5134c3adc44688ad9e7f9d97e0dacffbbe4ae90c -r a2a48b4e5a2cc4f6be7e0ed466da27c9c0b858f1 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -1180,6 +1180,52 @@
                                 1, fields)
         return rv
 
+    def fill_sfc(self, field_indices, dest_fields):
+        cdef np.ndarray[np.float64_t, ndim=1] dest
+        cdef int n, status, i, di, num_oct_levels, nf, ngv, max_level
+        cdef np.int64_t sfc
+        cdef np.float64_t val
+        cdef artio_fileset_handle *handle = self.artio_handle.handle
+        cdef double dpos[3]
+        # We duplicate some of the grid_variables stuff here so that we can
+        # potentially release the GIL
+        nf = len(field_indices)
+        ngv = self.artio_handle.num_grid_variables
+        max_level = self.artio_handle.max_level
+        cdef int *num_octs_per_level = <int *>malloc(
+            (max_level + 1)*sizeof(int))
+        cdef float *grid_variables = <float *>malloc(
+            ngv * sizeof(float))
+        cdef int* field_ind = <int*> malloc(
+            nf * sizeof(int))
+        cdef np.float64_t **field_vals = <np.float64_t**> malloc(
+            nf * sizeof(np.float64_t*))
+        for i in range(nf):
+            field_ind[i] = field_indices[i]
+            # This zeros should be an empty once we handle the root grid
+            dest = dest_fields[i]
+            field_vals[i] = <np.float64_t*> dest.data
+        # First we need to walk the mesh in the file.  Then we fill in the dest
+        # location based on the file index.
+        status = artio_grid_cache_sfc_range(handle,
+            self.sfc_start, self.sfc_end )
+        check_artio_status(status) 
+        for sfc in range(self.sfc_start, self.sfc_end + 1):
+            status = artio_grid_read_root_cell_begin( handle, sfc, 
+                    dpos, grid_variables, &num_oct_levels,
+                    num_octs_per_level)
+            check_artio_status(status) 
+            for i in range(nf):
+                field_vals[i][sfc - self.sfc_start] = grid_variables[i]
+            status = artio_grid_read_root_cell_end( handle )
+            check_artio_status(status)
+        # Now we have all our sources.
+        status = artio_grid_clear_sfc_cache(handle)
+        check_artio_status(status)
+        free(field_ind)
+        free(field_vals)
+        free(grid_variables)
+        free(num_octs_per_level)
 
 sfc_subset_selector = AlwaysSelector
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/89db5792f8ab/
Changeset:   89db5792f8ab
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 02:18:13
Summary:     Getting closer to working ARTIO selectors for root mesh.
Affected #:  2 files

diff -r a2a48b4e5a2cc4f6be7e0ed466da27c9c0b858f1 -r 89db5792f8ab2ad8bd3c22852bf0803eb49b1ecf yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -14,7 +14,8 @@
     OctVisitorData, oct_visitor_function, Oct
 from libc.stdint cimport int32_t, int64_t
 from libc.stdlib cimport malloc, free
-import  data_structures  
+from libc.string cimport memcpy
+import data_structures  
 
 cdef extern from "artio.h":
     ctypedef struct artio_fileset_handle "artio_fileset" :
@@ -1090,52 +1091,41 @@
         # This is where we use the selector to transplant from one to the
         # other.  Note that we *do* apply the selector here.
         cdef np.int64_t num_cells = -1
-        cdef np.int64_t ind = offset
+        cdef np.int64_t ind
         cdef np.int64_t sfc
         cdef np.float64_t pos[3]
         cdef np.float64_t dpos[3]
-        cdef int dim, status, eterm[3]
+        cdef int dim, status, eterm[3], filled = 0
         cdef int num_oct_levels, level
         cdef int max_level = self.artio_handle.max_level
         cdef int *num_octs_per_level = <int *>malloc(
             (max_level + 1)*sizeof(int))
+        cdef char *sdata = <char*> source.data
+        cdef char *ddata
+        cdef int ss = source.dtype.itemsize
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector)
         if dest is None:
             # Note that RAMSES can have partial refinement inside an Oct.  This
             # means we actually do want the number of Octs, not the number of
             # cells.
-            num_cells = self.count_cells(selector)
+            num_cells = mask.sum()
             if dims > 1:
                 dest = np.zeros((num_cells, dims), dtype=source.dtype,
-                    order='C')
+                    order='C') - 1
             else:
-                dest = np.zeros(num_cells, dtype=source.dtype, order='C')
-        status = artio_grid_cache_sfc_range(self.handle, self.sfc_start,
-                                            self.sfc_end)
-        check_artio_status(status) 
+                dest = np.zeros(num_cells, dtype=source.dtype, order='C') - 1
+        ddata = (<char*>dest.data) + offset*ss*dims
         for sfc in range(self.sfc_start, self.sfc_end + 1):
-            # We check if the SFC is in our selector, and if so, we copy
-            self.sfc_to_pos(sfc, pos)
-            if selector.select_cell(pos, self.dds, eterm) == 0: continue
-            # Now we just need to check if the cells are refined.
-            status = artio_grid_read_root_cell_begin( self.handle,
-                sfc, dpos, NULL, &num_oct_levels, num_octs_per_level)
-            check_artio_status(status)
-            status = artio_grid_read_root_cell_end( self.handle )
-            check_artio_status(status)
-            # If refined, we skip
-            if num_oct_levels > 0: continue
-            if dims > 1:
-                for dim in range(dims):
-                    dest[ind, dim] = source[sfc - self.sfc_start, dim]
-            else:
-                dest[ind] = source[sfc - self.sfc_start]
-            ind += 1
+            if mask[sfc - self.sfc_start] == 0: continue
+            ind = (sfc - self.sfc_start) * ss * dims
+            memcpy(ddata, sdata + ind, dims * ss)
+            ddata += dims * ss
+            filled += 1
 
-        artio_grid_clear_sfc_cache(self.handle)
-        free(num_octs_per_level)
         if num_cells >= 0:
             return dest
-        return ind - offset
+        return filled - offset
 
     def mask(self, SelectorObject selector, np.int64_t num_octs = -1):
         cdef int i, status, eterm[3]

diff -r a2a48b4e5a2cc4f6be7e0ed466da27c9c0b858f1 -r 89db5792f8ab2ad8bd3c22852bf0803eb49b1ecf yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -153,6 +153,7 @@
 
     def fill(self, fields, selector):
         # We know how big these will be.
+        handle = self.pf._handle
         field_indices = [handle.parameters["grid_variable_labels"].index(
                         yt_to_art[f]) for (ft, f) in fields]
         self.data_size = cell_count = self.sfc_end - self.sfc_start + 1


https://bitbucket.org/yt_analysis/yt-3.0/commits/65c5ab3c040b/
Changeset:   65c5ab3c040b
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 02:28:23
Summary:     SFC filling needs to respect the selector.
Affected #:  2 files

diff -r 89db5792f8ab2ad8bd3c22852bf0803eb49b1ecf -r 65c5ab3c040b8fc7f5cd9646499d4d23a06cd443 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -1170,10 +1170,10 @@
                                 1, fields)
         return rv
 
-    def fill_sfc(self, field_indices, dest_fields):
+    def fill_sfc(self, SelectorObject selector, field_indices):
         cdef np.ndarray[np.float64_t, ndim=1] dest
         cdef int n, status, i, di, num_oct_levels, nf, ngv, max_level
-        cdef np.int64_t sfc
+        cdef np.int64_t sfc, num_cells
         cdef np.float64_t val
         cdef artio_fileset_handle *handle = self.artio_handle.handle
         cdef double dpos[3]
@@ -1182,6 +1182,12 @@
         nf = len(field_indices)
         ngv = self.artio_handle.num_grid_variables
         max_level = self.artio_handle.max_level
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector)
+        num_cells = mask.sum()
+        tr = []
+        for i in range(nf):
+            tr.append(np.zeros(num_cells, dtype="float64"))
         cdef int *num_octs_per_level = <int *>malloc(
             (max_level + 1)*sizeof(int))
         cdef float *grid_variables = <float *>malloc(
@@ -1193,20 +1199,22 @@
         for i in range(nf):
             field_ind[i] = field_indices[i]
             # This zeros should be an empty once we handle the root grid
-            dest = dest_fields[i]
+            dest = tr[i]
             field_vals[i] = <np.float64_t*> dest.data
         # First we need to walk the mesh in the file.  Then we fill in the dest
         # location based on the file index.
+        cdef int filled = 0
         status = artio_grid_cache_sfc_range(handle,
             self.sfc_start, self.sfc_end )
         check_artio_status(status) 
         for sfc in range(self.sfc_start, self.sfc_end + 1):
+            if mask[sfc - self.sfc_start] == 0: continue
             status = artio_grid_read_root_cell_begin( handle, sfc, 
                     dpos, grid_variables, &num_oct_levels,
                     num_octs_per_level)
             check_artio_status(status) 
             for i in range(nf):
-                field_vals[i][sfc - self.sfc_start] = grid_variables[i]
+                field_vals[i][filled] = grid_variables[i]
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
         # Now we have all our sources.
@@ -1216,6 +1224,7 @@
         free(field_vals)
         free(grid_variables)
         free(num_octs_per_level)
+        return tr
 
 sfc_subset_selector = AlwaysSelector
 

diff -r 89db5792f8ab2ad8bd3c22852bf0803eb49b1ecf -r 65c5ab3c040b8fc7f5cd9646499d4d23a06cd443 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -156,9 +156,8 @@
         handle = self.pf._handle
         field_indices = [handle.parameters["grid_variable_labels"].index(
                         yt_to_art[f]) for (ft, f) in fields]
-        self.data_size = cell_count = self.sfc_end - self.sfc_start + 1
-        tr = [np.zeros(cell_count, dtype="float64") for field in fields]
-        self.oct_handler.fill_sfc(field_indices, tr)
+        tr = self.oct_handler.fill_sfc(selector, field_indices)
+        self.data_size = tr[0].size
         tr = dict((field, v) for field, v in zip(fields, tr))
         return tr
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/cdf3ca5ce21d/
Changeset:   cdf3ca5ce21d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 16:33:33
Summary:     Switching root to domain_id = 1, cells to domain_id = 2.
Affected #:  2 files

diff -r 65c5ab3c040b8fc7f5cd9646499d4d23a06cd443 -r cdf3ca5ce21d319ec84151a5c79ec38f0984aad8 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -634,7 +634,7 @@
         for i in range(max_level + 1):
             self.level_indices[i] = tot
             tot += tot_octs_per_level[i]
-        self.allocate_domains([tot - num_root, num_root], num_root)
+        self.allocate_domains([num_root, tot - num_root], num_root)
         # Now we have everything counted, and we need to create the appropriate
         # number of arrays.
         cdef np.ndarray[np.float64_t, ndim=2] pos
@@ -677,11 +677,12 @@
         nadded = 0
         cdef np.int64_t si, ei
         si = 0
-        # We initialize domain to 2 so that all root mesh octs are viewed as
+        # We initialize domain to 1 so that all root mesh octs are viewed as
         # not belonging to this domain.  This way we don't get confused with
         # how the different meshes are interfaced, and the root mesh container
-        # will own all the root mesh octs.
-        cdef int domain = 2
+        # will own all the root mesh octs.  Then, for all octs at higher
+        # levels, we use domain == 2.
+        cdef int domain = 1
         for level in range(max_level + 1):
             self.level_indices[level] = si
             ei = si + tot_octs_per_level[level]
@@ -695,7 +696,7 @@
                 print nadded, (ei - si), tot_octs_per_level[0]
                 raise RuntimeError
             si = ei
-            domain = 1 # Switch back to 1
+            domain = 2
         artio_grid_clear_sfc_cache(handle)
         free(mask)
         free(num_octs_per_level)
@@ -734,7 +735,7 @@
         for i in range(max_level + 1):
             # This will help us keep track of where we are in the flattened
             # array, which will be indexed by file_ind.
-            local_ind[i] = self.level_indices[i]
+            local_ind[i] = self.level_indices[i] - self.level_indices[0]
         source_arrays = []
         for i in range(nf):
             field_ind[i] = field_indices[i]

diff -r 65c5ab3c040b8fc7f5cd9646499d4d23a06cd443 -r cdf3ca5ce21d319ec84151a5c79ec38f0984aad8 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -51,7 +51,7 @@
 
 class ARTIOOctreeSubset(OctreeSubset):
     _domain_offset = 0
-    domain_id = 1
+    domain_id = 2
     _con_args = ("base_region", "sfc_start", "sfc_end", "pf")
     _type_name = 'octree_subset'
 
@@ -140,6 +140,7 @@
     _num_zones = 1
     _type_name = 'sfc_subset'
     _selector_module = _artio_caller
+    domain_id = 1
 
     @property
     def oct_handler(self):
@@ -335,7 +336,7 @@
                 mylog.debug("Running selector on artio base grid")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges(
                     dobj.selector)
-            ci =  [ARTIORootMeshSubset(base_region, start, end, self.pf)
+            ci  = [ARTIORootMeshSubset(base_region, start, end, self.pf)
                    for (start, end) in list_sfc_ranges]
             ci += [ARTIOOctreeSubset(base_region, start, end, self.pf)
                    for (start, end) in list_sfc_ranges]


https://bitbucket.org/yt_analysis/yt-3.0/commits/a5f03a65bd2a/
Changeset:   a5f03a65bd2a
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 16:34:47
Summary:     Make OctreeSubsetSelector cimportable.
Affected #:  2 files

diff -r cdf3ca5ce21d319ec84151a5c79ec38f0984aad8 -r a5f03a65bd2af3408880b40ce65c94282a008e8c yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -49,3 +49,7 @@
 
 cdef class AlwaysSelector(SelectorObject):
     pass
+
+cdef class OctreeSubsetSelector(SelectorObject):
+    cdef SelectorObject base_selector
+    cdef public np.int64_t domain_id

diff -r cdf3ca5ce21d319ec84151a5c79ec38f0984aad8 -r a5f03a65bd2af3408880b40ce65c94282a008e8c yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -1119,8 +1119,6 @@
 grid_selector = GridSelector
 
 cdef class OctreeSubsetSelector(SelectorObject):
-    cdef SelectorObject base_selector
-    cdef public np.int64_t domain_id
 
     def __init__(self, dobj):
         self.base_selector = dobj.base_selector


https://bitbucket.org/yt_analysis/yt-3.0/commits/0bd7bf4764dc/
Changeset:   0bd7bf4764dc
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 17:10:55
Summary:     Special-casing when we're getting either root or cell mesh.

Also, fix up grid_variables reading and the size of the mask.
Affected #:  2 files

diff -r a5f03a65bd2af3408880b40ce65c94282a008e8c -r 0bd7bf4764dc2bfe81a741e8d842dd0e08e78357 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -1123,7 +1123,6 @@
             memcpy(ddata, sdata + ind, dims * ss)
             ddata += dims * ss
             filled += 1
-
         if num_cells >= 0:
             return dest
         return filled - offset
@@ -1142,7 +1141,7 @@
         cdef int max_level = self.artio_handle.max_level
         cdef int *num_octs_per_level = <int *>malloc(
             (max_level + 1)*sizeof(int))
-        mask = np.zeros((num_octs * 8), dtype="uint8")
+        mask = np.zeros((num_octs), dtype="uint8")
         status = artio_grid_cache_sfc_range(self.handle, self.sfc_start,
                                             self.sfc_end)
         check_artio_status(status) 
@@ -1215,7 +1214,8 @@
                     num_octs_per_level)
             check_artio_status(status) 
             for i in range(nf):
-                field_vals[i][filled] = grid_variables[i]
+                field_vals[i][filled] = grid_variables[field_ind[i]]
+            filled += 1
             status = artio_grid_read_root_cell_end( handle )
             check_artio_status(status)
         # Now we have all our sources.

diff -r a5f03a65bd2af3408880b40ce65c94282a008e8c -r 0bd7bf4764dc2bfe81a741e8d842dd0e08e78357 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -326,6 +326,7 @@
             base_region = getattr(dobj, "base_region", dobj)
             sfc_start = getattr(dobj, "sfc_start", None)
             sfc_end = getattr(dobj, "sfc_end", None)
+            domain = getattr(dobj, "domain_id", 0)
             if all_data:
                 mylog.debug("Selecting entire artio domain")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges_all()
@@ -336,10 +337,13 @@
                 mylog.debug("Running selector on artio base grid")
                 list_sfc_ranges = self.pf._handle.root_sfc_ranges(
                     dobj.selector)
-            ci  = [ARTIORootMeshSubset(base_region, start, end, self.pf)
-                   for (start, end) in list_sfc_ranges]
-            ci += [ARTIOOctreeSubset(base_region, start, end, self.pf)
-                   for (start, end) in list_sfc_ranges]
+            ci = []
+            if domain != 2:
+                ci += [ARTIORootMeshSubset(base_region, start, end, self.pf)
+                        for (start, end) in list_sfc_ranges]
+            if domain != 1:
+                ci += [ARTIOOctreeSubset(base_region, start, end, self.pf)
+                       for (start, end) in list_sfc_ranges]
             dobj._chunk_info = ci
             mylog.info("Created %d chunks for ARTIO" % len(list_sfc_ranges))
         dobj._current_chunk = list(self._chunk_all(dobj))[0]


https://bitbucket.org/yt_analysis/yt-3.0/commits/6ed8e7dba5f6/
Changeset:   6ed8e7dba5f6
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 17:44:04
Summary:     We want to return the total number filled.
Affected #:  1 file

diff -r 0bd7bf4764dc2bfe81a741e8d842dd0e08e78357 -r 6ed8e7dba5f6401cb8ec321eb7a83eec8512b07a yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -735,7 +735,7 @@
         for i in range(max_level + 1):
             # This will help us keep track of where we are in the flattened
             # array, which will be indexed by file_ind.
-            local_ind[i] = self.level_indices[i] - self.level_indices[0]
+            local_ind[i] = self.level_indices[i]
         source_arrays = []
         for i in range(nf):
             field_ind[i] = field_indices[i]
@@ -1113,9 +1113,9 @@
             num_cells = mask.sum()
             if dims > 1:
                 dest = np.zeros((num_cells, dims), dtype=source.dtype,
-                    order='C') - 1
+                    order='C')
             else:
-                dest = np.zeros(num_cells, dtype=source.dtype, order='C') - 1
+                dest = np.zeros(num_cells, dtype=source.dtype, order='C')
         ddata = (<char*>dest.data) + offset*ss*dims
         for sfc in range(self.sfc_start, self.sfc_end + 1):
             if mask[sfc - self.sfc_start] == 0: continue
@@ -1125,7 +1125,7 @@
             filled += 1
         if num_cells >= 0:
             return dest
-        return filled - offset
+        return filled
 
     def mask(self, SelectorObject selector, np.int64_t num_octs = -1):
         cdef int i, status, eterm[3]


https://bitbucket.org/yt_analysis/yt-3.0/commits/cb4cb45c581e/
Changeset:   cb4cb45c581e
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 19:46:55
Summary:     This makes ARTIO spatial work.

Note that there are several weak points still:

Mask gets called *far too many times* for the root mesh.  This is anathema to
how the masking should work.  We should instead have an iteration function, or
some type of mask caching (usually they will be able to fit in memory).

The RootMesh always selects out the refined zones.  This is not how it should
be done.

In general, what should be done is a mechanism of visiting cells, like we have
for the octs, and it should in general be identically set up.  This would allow
us to evaluate things like min_level, max_level, and not need to conduct all
the mask operations that we currently do.  However, despite its somewhat
slowness, it's going to have to work for now.
Affected #:  1 file

diff -r 6ed8e7dba5f6401cb8ec321eb7a83eec8512b07a -r cb4cb45c581eec6b5d4f5e391fb3c8e915d680dd yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -1009,10 +1009,7 @@
         cdef np.float64_t pos[3], right_edge[3]
         cdef int num_cells = 0
         cdef int i, eterm[3]
-        for sfc in range(self.sfc_start, self.sfc_end + 1):
-            self.sfc_to_pos(sfc, pos)
-            num_cells += selector.select_cell(pos, self.dds, eterm)
-        return num_cells
+        return self.mask(selector).sum()
 
     def icoords(self, SelectorObject selector, np.int64_t num_octs = -1,
                 int domain_id = -1):
@@ -1020,20 +1017,21 @@
         cdef np.int64_t sfc
         cdef int acoords[3], i
         # We call it num_octs, but it's really num_cells.
-        if num_octs == -1:
-            # We need to count, but this process will only occur one time,
-            # since num_octs will later be cached.
-            num_octs = self.sfc_end - self.sfc_start + 1
-        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector)
+        num_octs = mask.sum()
         cdef np.ndarray[np.int64_t, ndim=2] coords
         coords = np.empty((num_octs, 3), dtype="int64")
+        cdef int filled = 0
         for sfc in range(self.sfc_start, self.sfc_end + 1):
+            if mask[sfc - self.sfc_start] == 0: continue
             # Note that we do *no* checks on refinement here.  In fact, this
             # entire setup should not need to touch the disk except if the
             # artio sfc calculators need to.
             artio_sfc_coords(self.handle, sfc, acoords)
             for i in range(3):
-                coords[sfc - self.sfc_start, i] = acoords[i]
+                coords[filled, i] = acoords[i]
+            filled += 1
         return coords
 
     def fcoords(self, SelectorObject selector, np.int64_t num_octs = -1,
@@ -1043,30 +1041,29 @@
         cdef np.float64_t pos[3]
         cdef int acoords[3], i
         # We call it num_octs, but it's really num_cells.
-        if num_octs == -1:
-            # We need to count, but this process will only occur one time,
-            # since num_octs will later be cached.
-            num_octs = self.sfc_end - self.sfc_start + 1
-        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector)
+        num_octs = mask.sum()
         cdef np.ndarray[np.float64_t, ndim=2] coords
         coords = np.empty((num_octs, 3), dtype="float64")
+        cdef int filled = 0
         for sfc in range(self.sfc_start, self.sfc_end + 1):
+            if mask[sfc - self.sfc_start] == 0: continue
             # Note that we do *no* checks on refinement here.  In fact, this
             # entire setup should not need to touch the disk except if the
             # artio sfc calculators need to.
             self.sfc_to_pos(sfc, pos)
             for i in range(3):
-                coords[sfc - self.sfc_start, i] = pos[i]
+                coords[filled, i] = pos[i]
+            filled += 1
         return coords
 
     def fwidth(self, SelectorObject selector, np.int64_t num_octs = -1,
                 int domain_id = -1):
         cdef int i
-        if num_octs == -1:
-            # We need to count, but this process will only occur one time,
-            # since num_octs will later be cached.
-            num_octs = self.sfc_end - self.sfc_start + 1
-        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector)
+        num_octs = mask.sum()
         cdef np.ndarray[np.float64_t, ndim=2] width
         width = np.zeros((num_octs, 3), dtype="float64")
         for i in range(3):
@@ -1075,11 +1072,9 @@
 
     def ires(self, SelectorObject selector, np.int64_t num_octs = -1,
                 int domain_id = -1):
-        if num_octs == -1:
-            # We need to count, but this process will only occur one time,
-            # since num_octs will later be cached.
-            num_octs = self.sfc_end - self.sfc_start + 1
-        assert(num_octs == (self.sfc_end - self.sfc_start + 1))
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector)
+        num_octs = mask.sum()
         cdef np.ndarray[np.int64_t, ndim=1] res
         res = np.zeros(num_octs, dtype="int64")
         return res
@@ -1117,12 +1112,13 @@
             else:
                 dest = np.zeros(num_cells, dtype=source.dtype, order='C')
         ddata = (<char*>dest.data) + offset*ss*dims
+        ind = 0
         for sfc in range(self.sfc_start, self.sfc_end + 1):
             if mask[sfc - self.sfc_start] == 0: continue
-            ind = (sfc - self.sfc_start) * ss * dims
             memcpy(ddata, sdata + ind, dims * ss)
             ddata += dims * ss
             filled += 1
+            ind += ss * dims
         if num_cells >= 0:
             return dest
         return filled
@@ -1183,7 +1179,7 @@
         ngv = self.artio_handle.num_grid_variables
         max_level = self.artio_handle.max_level
         cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
-        mask = self.mask(selector)
+        mask = self.mask(selector, -1)
         num_cells = mask.sum()
         tr = []
         for i in range(nf):


https://bitbucket.org/yt_analysis/yt-3.0/commits/c69bbe6e3b6c/
Changeset:   c69bbe6e3b6c
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 23:12:57
Summary:     Initial RootMesh deposit operation.
Affected #:  2 files

diff -r cb4cb45c581eec6b5d4f5e391fb3c8e915d680dd -r c69bbe6e3b6c4714925343fed02dad742731bdd0 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -12,11 +12,16 @@
     SparseOctreeContainer
 from yt.geometry.oct_visitors cimport \
     OctVisitorData, oct_visitor_function, Oct
+from yt.geometry.particle_deposit cimport \
+    ParticleDepositOperation
 from libc.stdint cimport int32_t, int64_t
 from libc.stdlib cimport malloc, free
 from libc.string cimport memcpy
 import data_structures  
 
+cdef extern from "alloca.h":
+    void *alloca(int)
+
 cdef extern from "artio.h":
     ctypedef struct artio_fileset_handle "artio_fileset" :
         pass
@@ -1223,5 +1228,56 @@
         free(num_octs_per_level)
         return tr
 
+    def deposit(self, ParticleDepositOperation pdeposit,
+                SelectorObject selector,
+                np.ndarray[np.float64_t, ndim=2] positions,
+                fields):
+        # This implements the necessary calls to enable particle deposition to
+        # occur as needed.
+        cdef int nf, i, j
+        if fields is None:
+            fields = []
+        nf = len(fields)
+        cdef np.ndarray[np.uint8_t, ndim=1, cast=True] mask
+        mask = self.mask(selector, -1)
+        cdef np.ndarray[np.int64_t, ndim=1] domain_ind
+        domain_ind = np.zeros(mask.shape[0], dtype="int64") - 1
+        j = 0
+        for i in range(mask.shape[0]):
+            if mask[i] == 1:
+                domain_ind[i] = j
+                j += 1
+        cdef np.float64_t **field_pointers, *field_vals, pos[3], left_edge[3]
+        cdef int coords[3]
+        cdef np.int64_t sfc
+        cdef np.ndarray[np.float64_t, ndim=1] tarr
+        field_pointers = <np.float64_t**> alloca(sizeof(np.float64_t *) * nf)
+        field_vals = <np.float64_t*>alloca(sizeof(np.float64_t) * nf)
+        for i in range(nf):
+            tarr = fields[i]
+            field_pointers[i] = <np.float64_t *> tarr.data
+        cdef int dims[3]
+        dims[0] = dims[1] = dims[2] = 1
+        cdef np.int64_t offset, moff
+        cdef np.int64_t numpart = positions.shape[0]
+        for i in range(positions.shape[0]):
+            for j in range(nf):
+                field_vals[j] = field_pointers[j][i]
+            for j in range(3):
+                pos[j] = positions[i, j]
+                coords[j] = <int>((pos[j] - self.DLE[j])/self.dds[j])
+            sfc = artio_sfc_index(self.artio_handle.handle, coords)
+            offset = domain_ind[sfc - self.sfc_start]
+            if offset < 0 or sfc < self.sfc_start or sfc > self.sfc_end:
+                continue
+            # Check that we found the oct ...
+            for j in range(3):
+                left_edge[j] = coords[j] * self.dds[j] + self.DLE[j]
+            pdeposit.process(dims, left_edge, self.dds,
+                         offset, pos, field_vals, sfc)
+            if pdeposit.update_values == 1:
+                for j in range(nf):
+                    field_pointers[j][i] = field_vals[j] 
+
 sfc_subset_selector = AlwaysSelector
 

diff -r cb4cb45c581eec6b5d4f5e391fb3c8e915d680dd -r c69bbe6e3b6c4714925343fed02dad742731bdd0 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -39,6 +39,7 @@
 from yt.funcs import *
 from yt.geometry.geometry_handler import \
     GeometryHandler, YTDataChunk
+import yt.geometry.particle_deposit as particle_deposit
 from yt.data_objects.static_output import \
     StaticOutput
 from yt.data_objects.octree_subset import \
@@ -162,6 +163,24 @@
         tr = dict((field, v) for field, v in zip(fields, tr))
         return tr
 
+    def deposit(self, positions, fields = None, method = None):
+        # Here we perform our particle deposition.
+        cls = getattr(particle_deposit, "deposit_%s" % method, None)
+        if cls is None:
+            raise YTParticleDepositionNotImplemented(method)
+        nz = self.nz
+        nvals = (nz, nz, nz, self.ires.size)
+        op = cls(nvals) # We allocate number of zones, not number of octs
+        op.initialize()
+        mylog.debug("Depositing %s (%s^3) particles into %s Root Mesh",
+            positions.shape[0], positions.shape[0]**0.3333333, nvals[-1])
+        pos = np.array(positions, dtype="float64")
+        f64 = [np.array(f, dtype="float64") for f in fields]
+        self.oct_handler.deposit(op, self.base_selector, pos, f64)
+        vals = op.finalize()
+        if vals is None: return
+        return np.asfortranarray(vals)
+
 class ARTIOChunk(object):
 
     def __init__(self, pf, sfc_start, sfc_end):


https://bitbucket.org/yt_analysis/yt-3.0/commits/bec55041e10c/
Changeset:   bec55041e10c
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-16 23:36:13
Summary:     Split up the offset/sfc check.
Affected #:  1 file

diff -r c69bbe6e3b6c4714925343fed02dad742731bdd0 -r bec55041e10c10f8c8a8d5da04c6d24d06d900f0 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -1267,9 +1267,9 @@
                 pos[j] = positions[i, j]
                 coords[j] = <int>((pos[j] - self.DLE[j])/self.dds[j])
             sfc = artio_sfc_index(self.artio_handle.handle, coords)
+            if sfc < self.sfc_start or sfc > self.sfc_end: continue
             offset = domain_ind[sfc - self.sfc_start]
-            if offset < 0 or sfc < self.sfc_start or sfc > self.sfc_end:
-                continue
+            if offset < 0: continue
             # Check that we found the oct ...
             for j in range(3):
                 left_edge[j] = coords[j] * self.dds[j] + self.DLE[j]


https://bitbucket.org/yt_analysis/yt-3.0/commits/dc6b40e449d7/
Changeset:   dc6b40e449d7
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 02:37:26
Summary:     Fixing some unit tests and leaving a substantial comment.

Also removed some unnecessarily verbose info about field type guessing and
added some checks on the field type guessing.
Affected #:  4 files

diff -r bec55041e10c10f8c8a8d5da04c6d24d06d900f0 -r dc6b40e449d74b96f6ef148d3dc7e6b630b79bb0 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -460,7 +460,9 @@
         for field in itertools.cycle(fields_to_get):
             if inspected >= len(fields_to_get): break
             inspected += 1
-            if field not in self.pf.field_dependencies: continue
+            fd = self.pf.field_dependencies.get(field, None) or \
+                 self.pf.field_dependencies.get(field[1], None)
+            if fd is None: continue
             fd = self.pf.field_dependencies[field]
             requested = self._determine_fields(list(set(fd.requested)))
             deps = [d for d in requested if d not in fields_to_get]

diff -r bec55041e10c10f8c8a8d5da04c6d24d06d900f0 -r dc6b40e449d74b96f6ef148d3dc7e6b630b79bb0 yt/data_objects/field_info_container.py
--- a/yt/data_objects/field_info_container.py
+++ b/yt/data_objects/field_info_container.py
@@ -280,6 +280,8 @@
             # need to re-update -- otherwise, our item will always not have the
             # field type.  This can lead to, for instance, "unknown" particle
             # types not getting correctly identified.
+            # Note that the *only* way this works is if we also fix our field
+            # dependencies during checking.  Bug #627 talks about this.
             item = self.pf._last_freq
         else:
             FI = getattr(self.pf, "field_info", FieldInfo)

diff -r bec55041e10c10f8c8a8d5da04c6d24d06d900f0 -r dc6b40e449d74b96f6ef148d3dc7e6b630b79bb0 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -295,20 +295,25 @@
             self._last_finfo = self.field_info[(ftype, fname)]
             return self._last_finfo
         if fname == self._last_freq[1]:
-            mylog.debug("Guessing field %s is (%s, %s)", fname,
-                        self._last_freq[0], self._last_freq[1])
             return self._last_finfo
         if fname in self.field_info:
+            # Sometimes, if guessing_type == True, this will be switched for
+            # the type of field it is.  So we look at the field type and
+            # determine if we need to change the type.
+            fi = self._last_finfo = self.field_info[fname]
+            if fi.particle_type and self._last_freq[0] \
+                not in self.particle_types:
+                    field = "all", field[1]
+            elif not fi.particle_type and self._last_freq[0] \
+                not in self.fluid_types:
+                    field = self.default_fluid_type, field[1]
             self._last_freq = field
-            self._last_finfo = self.field_info[fname]
             return self._last_finfo
         # We also should check "all" for particles, which can show up if you're
         # mixing deposition/gas fields with particle fields.
         if guessing_type and ("all", fname) in self.field_info:
             self._last_freq = ("all", fname)
             self._last_finfo = self.field_info["all", fname]
-            mylog.debug("Guessing field %s is (%s, %s)", fname,
-                        "all", fname)
             return self._last_finfo
         raise YTFieldNotFound((ftype, fname), self)
 

diff -r bec55041e10c10f8c8a8d5da04c6d24d06d900f0 -r dc6b40e449d74b96f6ef148d3dc7e6b630b79bb0 yt/geometry/geometry_handler.py
--- a/yt/geometry/geometry_handler.py
+++ b/yt/geometry/geometry_handler.py
@@ -251,6 +251,8 @@
                     requested.append( (field[0], f) )
                 elif f in self.field_list:
                     requested.append( f )
+                elif isinstance(f, tuple) and f[1] in self.field_list:
+                    requested.append( f )
                 else:
                     missing = True
                     break


https://bitbucket.org/yt_analysis/yt-3.0/commits/94a623c55612/
Changeset:   94a623c55612
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 03:12:29
Summary:     Careless calls to np.array resulted in duplicated array values.
Affected #:  2 files

diff -r dc6b40e449d74b96f6ef148d3dc7e6b630b79bb0 -r 94a623c5561291e621cb984d6716493aa9535478 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -136,8 +136,10 @@
         mylog.debug("Depositing %s (%s^3) particles into %s Octs",
             positions.shape[0], positions.shape[0]**0.3333333, nvals[-1])
         pos = np.array(positions, dtype="float64")
-        f64 = [np.array(f, dtype="float64") for f in fields]
-        op.process_octree(self.oct_handler, self.domain_ind, pos, f64,
+        # We should not need the following if we know in advance all our fields
+        # need no casting.
+        fields = [np.asarray(f, dtype="float64") for f in fields]
+        op.process_octree(self.oct_handler, self.domain_ind, pos, fields,
             self.domain_id, self._domain_offset)
         vals = op.finalize()
         if vals is None: return

diff -r dc6b40e449d74b96f6ef148d3dc7e6b630b79bb0 -r 94a623c5561291e621cb984d6716493aa9535478 yt/geometry/particle_deposit.pxd
--- a/yt/geometry/particle_deposit.pxd
+++ b/yt/geometry/particle_deposit.pxd
@@ -63,7 +63,7 @@
     # We assume each will allocate and define their own temporary storage
     cdef public object nvals
     cdef public int bad_indices
-    cdef int update_values
+    cdef public int update_values
     cdef void process(self, int dim[3], np.float64_t left_edge[3],
                       np.float64_t dds[3], np.int64_t offset,
                       np.float64_t ppos[3], np.float64_t *fields,


https://bitbucket.org/yt_analysis/yt-3.0/commits/b223a97c5b59/
Changeset:   b223a97c5b59
Branch:      yt
User:        ngoldbaum
Date:        2013-07-10 06:15:06
Summary:     Updating physical constants to reflect 2010 CODATA data.
Affected #:  1 file

diff -r 0f59ef0d7dc696a4c8fdab557eb544ca87942b6c -r b223a97c5b598ea841b0e25ad538a42bd78d2ad4 yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -1,15 +1,16 @@
 #
 # Physical Constants and Units Conversion Factors
 #
-# Values for these constants are drawn from IAU and IUPAC data 
-# unless otherwise noted:
+# Values for these constants, unless otherwise noted, are drawn from IAU,
+# IUPAC, and NIST data, whichever is newer.
 # http://maia.usno.navy.mil/NSFA/IAU2009_consts.html
 # http://goldbook.iupac.org/list_goldbook_phys_constants_defs.html
+# http://physics.nist.gov/cuu/Constants/index.html
 
 # Masses
-mass_hydrogen_cgs = 1.674534e-24  # g
-mass_electron_cgs = 9.1093898e-28  # g
-amu_cgs           = 1.6605402e-24  # g
+mass_electron_cgs = 9.109382-28  # g
+amu_cgs           = 1.660538921e-24  # g
+mass_hydrogen_cgs = 1.007947*amu_cgs  # g
 mass_sun_cgs = 1.98841586e33  # g
 # Velocities
 speed_of_light_cgs = 2.99792458e10  # cm/s, exact
@@ -22,10 +23,10 @@
 charge_proton_cgs = 4.8032056e-10  # esu = 1.602176487e-19  Coulombs
 
 # Physical Constants
-boltzmann_constant_cgs = 1.3806504e-16  # erg K^-1
-gravitational_constant_cgs  = 6.67428e-8  # cm^3 g^-1 s^-2
-planck_constant_cgs   = 6.62606896e-27  # erg s
-stefan_boltzmann_constant_cgs = 5.67051e-5 # erg cm^-2 s^-1 K^-4
+boltzmann_constant_cgs = 1.3806488e-16  # erg K^-1
+gravitational_constant_cgs  = 6.67384e-8  # cm^3 g^-1 s^-2
+planck_constant_cgs   = 6.62606957e-27  # erg s
+stefan_boltzmann_constant_cgs = 5.670373e-5 # erg cm^-2 s^-1 K^-4
 # The following value was calcualted assuming H = 100 km/s/Mpc.
 # To get the correct value for your cosmological parameters, 
 # you'll need to multiply through by h^2
@@ -69,16 +70,17 @@
 cm_per_pc     = 1.0 / pc_per_cm
 
 # time
+# "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 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_year = 31.5576e6   
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25
 
 # temperature / energy
-erg_per_eV = 1.602176487e-12 # http://goldbook.iupac.org/E02014.html
+erg_per_eV = 1.602176562e-12
 erg_per_keV = erg_per_eV * 1.0e3
 K_per_keV = erg_per_keV / boltzmann_constant_cgs
 keV_per_K = 1.0 / K_per_keV


https://bitbucket.org/yt_analysis/yt-3.0/commits/c709becee6a2/
Changeset:   c709becee6a2
Branch:      yt
User:        ngoldbaum
Date:        2013-07-10 06:17:15
Summary:     Deleting some useless whitespace.
Affected #:  1 file

diff -r b223a97c5b598ea841b0e25ad538a42bd78d2ad4 -r c709becee6a2723c85452f8ce7b49e3c2c4ba54f yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -74,7 +74,7 @@
 sec_per_Gyr  = 31.5576e15
 sec_per_Myr  = 31.5576e12
 sec_per_kyr  = 31.5576e9
-sec_per_year = 31.5576e6   
+sec_per_year = 31.5576e6
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25


https://bitbucket.org/yt_analysis/yt-3.0/commits/f59d39a2ef53/
Changeset:   f59d39a2ef53
Branch:      yt
User:        ngoldbaum
Date:        2013-07-16 06:32:01
Summary:     Merging with development tip.
Affected #:  1 file

diff -r 2303e938a22ace1beb284d56b4ab719472cabcb5 -r f59d39a2ef5320dd6cfa72c21697ba3d18b8cf3e yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -1,15 +1,16 @@
 #
 # Physical Constants and Units Conversion Factors
 #
-# Values for these constants are drawn from IAU and IUPAC data 
-# unless otherwise noted:
+# Values for these constants, unless otherwise noted, are drawn from IAU,
+# IUPAC, and NIST data, whichever is newer.
 # http://maia.usno.navy.mil/NSFA/IAU2009_consts.html
 # http://goldbook.iupac.org/list_goldbook_phys_constants_defs.html
+# http://physics.nist.gov/cuu/Constants/index.html
 
 # Masses
-mass_hydrogen_cgs = 1.674534e-24  # g
-mass_electron_cgs = 9.1093898e-28  # g
-amu_cgs           = 1.6605402e-24  # g
+mass_electron_cgs = 9.109382-28  # g
+amu_cgs           = 1.660538921e-24  # g
+mass_hydrogen_cgs = 1.007947*amu_cgs  # g
 mass_sun_cgs = 1.98841586e33  # g
 # Velocities
 speed_of_light_cgs = 2.99792458e10  # cm/s, exact
@@ -22,10 +23,10 @@
 charge_proton_cgs = 4.8032056e-10  # esu = 1.602176487e-19  Coulombs
 
 # Physical Constants
-boltzmann_constant_cgs = 1.3806504e-16  # erg K^-1
-gravitational_constant_cgs  = 6.67428e-8  # cm^3 g^-1 s^-2
-planck_constant_cgs   = 6.62606896e-27  # erg s
-stefan_boltzmann_constant_cgs = 5.67051e-5 # erg cm^-2 s^-1 K^-4
+boltzmann_constant_cgs = 1.3806488e-16  # erg K^-1
+gravitational_constant_cgs  = 6.67384e-8  # cm^3 g^-1 s^-2
+planck_constant_cgs   = 6.62606957e-27  # erg s
+stefan_boltzmann_constant_cgs = 5.670373e-5 # erg cm^-2 s^-1 K^-4
 # The following value was calcualted assuming H = 100 km/s/Mpc.
 # To get the correct value for your cosmological parameters, 
 # you'll need to multiply through by h^2
@@ -69,16 +70,17 @@
 cm_per_pc     = 1.0 / pc_per_cm
 
 # time
+# "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 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_year = 31.5576e6
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25
 
 # temperature / energy
-erg_per_eV = 1.602176487e-12 # http://goldbook.iupac.org/E02014.html
+erg_per_eV = 1.602176562e-12
 erg_per_keV = erg_per_eV * 1.0e3
 K_per_keV = erg_per_keV / boltzmann_constant_cgs
 keV_per_K = 1.0 / K_per_keV


https://bitbucket.org/yt_analysis/yt-3.0/commits/5f323e7a7be2/
Changeset:   5f323e7a7be2
Branch:      yt
User:        ngoldbaum
Date:        2013-07-16 06:36:31
Summary:     Updating the gold standard to gold009.
Affected #:  1 file

diff -r f59d39a2ef5320dd6cfa72c21697ba3d18b8cf3e -r 5f323e7a7be2d202c4d653a5e5f5e0eff57a41a8 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -62,7 +62,7 @@
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
-    gold_standard_filename = 'gold008',
+    gold_standard_filename = 'gold009',
     local_standard_filename = 'local001',
     sketchfab_api_key = 'None'
     )


https://bitbucket.org/yt_analysis/yt-3.0/commits/f15815e18208/
Changeset:   f15815e18208
Branch:      yt
User:        MatthewTurk
Date:        2013-07-17 15:47:53
Summary:     Updating .hgchurn file.
Affected #:  1 file

diff -r 5f323e7a7be2d202c4d653a5e5f5e0eff57a41a8 -r f15815e182080e8619efd2636cce42bc6e598b7c .hgchurn
--- a/.hgchurn
+++ b/.hgchurn
@@ -4,8 +4,16 @@
 juxtaposicion at gmail.com = cemoody at ucsc.edu
 chummels at gmail.com = chummels at astro.columbia.edu
 jwise at astro.princeton.edu = jwise at physics.gatech.edu
-atmyers = atmyers at berkeley.edu
 sam.skillman at gmail.com = samskillman at gmail.com
 casey at thestarkeffect.com = caseywstark at gmail.com
 chiffre = chiffre at posteo.de
 Christian Karch = chiffre at posteo.de
+atmyers at berkeley.edu = atmyers2 at gmail.com
+atmyers = atmyers2 at gmail.com
+drudd = drudd at uchicago.edu
+awetzel = andrew.wetzel at yale.edu
+David Collins (dcollins4096 at gmail.com) = dcollins4096 at gmail.com
+dcollins at physics.ucsd.edu = dcollins4096 at gmail.com
+tabel = tabel at slac.stanford.edu
+sername=kayleanelson = kaylea.nelson at yale.edu
+kayleanelson = kaylea.nelson at yale.edu


https://bitbucket.org/yt_analysis/yt-3.0/commits/4432c4c71f3a/
Changeset:   4432c4c71f3a
Branch:      yt
User:        John Forbes
Date:        2013-07-10 04:53:00
Summary:     Add NumberDensity field to FLASH frontend
Affected #:  1 file

diff -r 0f59ef0d7dc696a4c8fdab557eb544ca87942b6c -r 4432c4c71f3a0856d4627933b0b28945d1208b52 yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -368,3 +368,15 @@
 def _abar(field, data):
     return 1.0 / data['sumy']
 add_field('abar', function=_abar, take_log=False)
+	
+
+def _NumberDensity(fields,data) :
+    try:
+        return data["nele"]+data["nion"]
+    except:
+        pass
+    return data['pres']/(data['temp']*Na*kboltz*mh)
+add_field("NumberDensity", function=_NumberDensity,
+        units=r'\rm{cm}^{-3}')
+
+


https://bitbucket.org/yt_analysis/yt-3.0/commits/e0adb33d174b/
Changeset:   e0adb33d174b
Branch:      yt
User:        John Forbes
Date:        2013-07-10 04:59:32
Summary:     Use correct proton mass to calculate NumberDensity.
Affected #:  1 file

diff -r 4432c4c71f3a0856d4627933b0b28945d1208b52 -r e0adb33d174bad2a9283fbb642a404f96e910834 yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -375,7 +375,7 @@
         return data["nele"]+data["nion"]
     except:
         pass
-    return data['pres']/(data['temp']*Na*kboltz*mh)
+    return data['pres']/(data['temp']*Na*kboltz*mh/1.00794)
 add_field("NumberDensity", function=_NumberDensity,
         units=r'\rm{cm}^{-3}')
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/695225600c5b/
Changeset:   695225600c5b
Branch:      yt
User:        John Forbes
Date:        2013-07-10 06:14:03
Summary:     Eliminate unexplained numerical constant from NumberDensity calculation.
Affected #:  1 file

diff -r e0adb33d174bad2a9283fbb642a404f96e910834 -r 695225600c5b10177bedecbe44e04e36ad425d26 yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -375,7 +375,7 @@
         return data["nele"]+data["nion"]
     except:
         pass
-    return data['pres']/(data['temp']*Na*kboltz*mh/1.00794)
+    return data['pres']/(data['temp']*kboltz)
 add_field("NumberDensity", function=_NumberDensity,
         units=r'\rm{cm}^{-3}')
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/c9739ccc55d3/
Changeset:   c9739ccc55d3
Branch:      yt
User:        jforbes
Date:        2013-07-16 19:04:14
Summary:     Merged yt_analysis/yt into yt
Affected #:  5 files

diff -r 695225600c5b10177bedecbe44e04e36ad425d26 -r c9739ccc55d3b5e3154886b32791a085782941fe yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -62,7 +62,7 @@
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
-    gold_standard_filename = 'gold008',
+    gold_standard_filename = 'gold009',
     local_standard_filename = 'local001',
     sketchfab_api_key = 'None'
     )

diff -r 695225600c5b10177bedecbe44e04e36ad425d26 -r c9739ccc55d3b5e3154886b32791a085782941fe yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -57,7 +57,12 @@
     def __new__(cls, filename=None, *args, **kwargs):
         if not isinstance(filename, types.StringTypes):
             obj = object.__new__(cls)
-            obj.__init__(filename, *args, **kwargs)
+            # The Stream frontend uses a StreamHandler object to pass metadata
+            # to __init__.
+            is_stream = (hasattr(filename, 'get_fields') and
+                         hasattr(filename, 'get_particle_type'))
+            if not is_stream:
+                obj.__init__(filename, *args, **kwargs)
             return obj
         apath = os.path.abspath(filename)
         if not os.path.exists(apath): raise IOError(filename)

diff -r 695225600c5b10177bedecbe44e04e36ad425d26 -r c9739ccc55d3b5e3154886b32791a085782941fe yt/utilities/lib/misc_utilities.pyx
--- a/yt/utilities/lib/misc_utilities.pyx
+++ b/yt/utilities/lib/misc_utilities.pyx
@@ -127,7 +127,7 @@
     cdef int nx = image.shape[0]
     cdef int ny = image.shape[1]
     cdef int nl = xs.shape[0]
-    cdef np.float64_t alpha[4]
+    cdef np.float64_t alpha[4], outa
     cdef int i, j
     cdef int dx, dy, sx, sy, e2, err
     cdef np.int64_t x0, x1, y0, y1
@@ -158,17 +158,21 @@
             elif (x0 >= nx-thick+1 and sx == 1): break
             elif (y0 < thick and sy == -1): break
             elif (y0 >= ny-thick+1 and sy == 1): break
-            if (x0 >=thick and x0 < nx-thick and y0 >= thick and y0 < ny-thick):
-                if has_alpha:
-                    for i in range(4):
-                        image[x0-thick/2:x0+(1+thick)/2, 
-                              y0-thick/2:y0+(1+thick)/2,i] = \
-                                (1.-alpha[3])*image[x0,y0,i] + alpha[i]
-                else:
-                    for i in range(3):
-                        image[x0-thick/2:x0+(1+thick)/2, 
-                              y0-thick/2:y0+(1+thick)/2,i] = \
-                                (1.-alpha[i])*image[x0,y0,i] + alpha[i]
+            if x0 >= thick and x0 < nx-thick and y0 >= thick and y0 < ny-thick:
+                for xi in range(x0-thick/2, x0+(1+thick)/2):
+                    for yi in range(y0-thick/2, y0+(1+thick)/2):
+                        if has_alpha:
+                            image[xi, yi, 3] = outa = alpha[3] + image[xi, yi, 3]*(1-alpha[3])
+                            if outa != 0.0:
+                                outa = 1.0/outa
+                            for i in range(3):
+                                image[xi, yi, i] = \
+                                        ((1.-alpha[3])*image[xi, yi, i]*image[xi, yi, 3]
+                                         + alpha[3]*alpha[i])*outa
+                        else:
+                            for i in range(3):
+                                image[xi, yi, i] = \
+                                        (1.-alpha[i])*image[xi,yi,i] + alpha[i]
 
             if (x0 == x1 and y0 == y1):
                 break

diff -r 695225600c5b10177bedecbe44e04e36ad425d26 -r c9739ccc55d3b5e3154886b32791a085782941fe yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -1,15 +1,16 @@
 #
 # Physical Constants and Units Conversion Factors
 #
-# Values for these constants are drawn from IAU and IUPAC data 
-# unless otherwise noted:
+# Values for these constants, unless otherwise noted, are drawn from IAU,
+# IUPAC, and NIST data, whichever is newer.
 # http://maia.usno.navy.mil/NSFA/IAU2009_consts.html
 # http://goldbook.iupac.org/list_goldbook_phys_constants_defs.html
+# http://physics.nist.gov/cuu/Constants/index.html
 
 # Masses
-mass_hydrogen_cgs = 1.674534e-24  # g
-mass_electron_cgs = 9.1093898e-28  # g
-amu_cgs           = 1.6605402e-24  # g
+mass_electron_cgs = 9.109382-28  # g
+amu_cgs           = 1.660538921e-24  # g
+mass_hydrogen_cgs = 1.007947*amu_cgs  # g
 mass_sun_cgs = 1.98841586e33  # g
 # Velocities
 speed_of_light_cgs = 2.99792458e10  # cm/s, exact
@@ -22,10 +23,10 @@
 charge_proton_cgs = 4.8032056e-10  # esu = 1.602176487e-19  Coulombs
 
 # Physical Constants
-boltzmann_constant_cgs = 1.3806504e-16  # erg K^-1
-gravitational_constant_cgs  = 6.67428e-8  # cm^3 g^-1 s^-2
-planck_constant_cgs   = 6.62606896e-27  # erg s
-stefan_boltzmann_constant_cgs = 5.67051e-5 # erg cm^-2 s^-1 K^-4
+boltzmann_constant_cgs = 1.3806488e-16  # erg K^-1
+gravitational_constant_cgs  = 6.67384e-8  # cm^3 g^-1 s^-2
+planck_constant_cgs   = 6.62606957e-27  # erg s
+stefan_boltzmann_constant_cgs = 5.670373e-5 # erg cm^-2 s^-1 K^-4
 # The following value was calcualted assuming H = 100 km/s/Mpc.
 # To get the correct value for your cosmological parameters, 
 # you'll need to multiply through by h^2
@@ -69,16 +70,17 @@
 cm_per_pc     = 1.0 / pc_per_cm
 
 # time
+# "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 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_year = 31.5576e6
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25
 
 # temperature / energy
-erg_per_eV = 1.602176487e-12 # http://goldbook.iupac.org/E02014.html
+erg_per_eV = 1.602176562e-12
 erg_per_keV = erg_per_eV * 1.0e3
 K_per_keV = erg_per_keV / boltzmann_constant_cgs
 keV_per_K = 1.0 / K_per_keV

diff -r 695225600c5b10177bedecbe44e04e36ad425d26 -r c9739ccc55d3b5e3154886b32791a085782941fe yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -37,11 +37,9 @@
 from functools import wraps
 from numbers import Number
 
-from ._mpl_imports import \
-    FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
+from ._mpl_imports import FigureCanvasAgg
 from .color_maps import yt_colormaps, is_colormap
-from .image_writer import \
-    write_image, apply_colormap
+from .image_writer import apply_colormap
 from .fixed_resolution import \
     FixedResolutionBuffer, \
     ObliqueFixedResolutionBuffer, \
@@ -52,21 +50,20 @@
 from .base_plot_types import ImagePlotMPL
 
 from yt.utilities.delaunay.triangulate import Triangulation as triang
-from yt.config import ytcfg
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
     fix_axis, get_image_suffix
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
-    x_dict, x_names, \
-    y_dict, y_names, \
+    x_dict, y_dict, \
     axis_names, axis_labels, \
     formatted_length_unit_names
 from yt.utilities.math_utils import \
     ortho_find
-from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    GroupOwnership
-from yt.utilities.exceptions import YTUnitNotRecognized, YTInvalidWidthError
+from yt.utilities.exceptions import \
+     YTUnitNotRecognized, YTInvalidWidthError, YTCannotParseUnitDisplayName, \
+     YTNotInsideNotebook
+
 from yt.data_objects.time_series import \
     TimeSeriesData
 
@@ -539,12 +536,6 @@
             self.center = new_center
         self.set_window(self.bounds)
 
-    @property
-    def width(self):
-        Wx = self.xlim[1] - self.xlim[0]
-        Wy = self.ylim[1] - self.ylim[0]
-        return (Wx, Wy)
-
     @invalidate_data
     def set_antialias(self,aa):
         self.antialias = aa
@@ -839,10 +830,6 @@
         return xc, yc
 
     def _setup_plots(self):
-        if self._current_field is not None:
-            fields = [self._current_field]
-        else:
-            fields = self._frb.keys()
         self._colorbar_valid = True
         for f in self.fields:
             axis_index = self.data_source.axis
@@ -1081,13 +1068,15 @@
 
     def _send_zmq(self):
         try:
-            # pre-IPython v0.14
+            # pre-IPython v1.0
             from IPython.zmq.pylab.backend_inline import send_figure as display
         except ImportError:
-            # IPython v0.14+
+            # IPython v1.0+
             from IPython.core.display import display
         for k, v in sorted(self.plots.iteritems()):
-            canvas = FigureCanvasAgg(v.figure)
+            # Due to a quirk in the matplotlib API, we need to create
+            # a dummy canvas variable here that is never used.
+            canvas = FigureCanvasAgg(v.figure)  # NOQA
             display(v.figure)
 
     def show(self):


https://bitbucket.org/yt_analysis/yt-3.0/commits/8d7f5c67ba8e/
Changeset:   8d7f5c67ba8e
Branch:      yt
User:        John Forbes
Date:        2013-07-16 19:17:44
Summary:     Making abar slightly more robust.
Affected #:  1 file

diff -r 695225600c5b10177bedecbe44e04e36ad425d26 -r 8d7f5c67ba8ee7743618e07d6a1cd63cbd3dacef yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -366,7 +366,11 @@
 add_field('nion', function=_nion, take_log=True, units=r"\rm{cm}^{-3}")
 
 def _abar(field, data):
-    return 1.0 / data['sumy']
+    try:
+        return 1.0 / data['sumy']
+    except:
+        pass
+    return data['dens']*Na*kboltz*data['temp']/data['pres']
 add_field('abar', function=_abar, take_log=False)
 	
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/27125ca05478/
Changeset:   27125ca05478
Branch:      yt
User:        John Forbes
Date:        2013-07-16 19:18:44
Summary:     Merging
Affected #:  5 files

diff -r 8d7f5c67ba8ee7743618e07d6a1cd63cbd3dacef -r 27125ca054789df6869c96f378085486f39c58dc yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -62,7 +62,7 @@
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
-    gold_standard_filename = 'gold008',
+    gold_standard_filename = 'gold009',
     local_standard_filename = 'local001',
     sketchfab_api_key = 'None'
     )

diff -r 8d7f5c67ba8ee7743618e07d6a1cd63cbd3dacef -r 27125ca054789df6869c96f378085486f39c58dc yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -57,7 +57,12 @@
     def __new__(cls, filename=None, *args, **kwargs):
         if not isinstance(filename, types.StringTypes):
             obj = object.__new__(cls)
-            obj.__init__(filename, *args, **kwargs)
+            # The Stream frontend uses a StreamHandler object to pass metadata
+            # to __init__.
+            is_stream = (hasattr(filename, 'get_fields') and
+                         hasattr(filename, 'get_particle_type'))
+            if not is_stream:
+                obj.__init__(filename, *args, **kwargs)
             return obj
         apath = os.path.abspath(filename)
         if not os.path.exists(apath): raise IOError(filename)

diff -r 8d7f5c67ba8ee7743618e07d6a1cd63cbd3dacef -r 27125ca054789df6869c96f378085486f39c58dc yt/utilities/lib/misc_utilities.pyx
--- a/yt/utilities/lib/misc_utilities.pyx
+++ b/yt/utilities/lib/misc_utilities.pyx
@@ -127,7 +127,7 @@
     cdef int nx = image.shape[0]
     cdef int ny = image.shape[1]
     cdef int nl = xs.shape[0]
-    cdef np.float64_t alpha[4]
+    cdef np.float64_t alpha[4], outa
     cdef int i, j
     cdef int dx, dy, sx, sy, e2, err
     cdef np.int64_t x0, x1, y0, y1
@@ -158,17 +158,21 @@
             elif (x0 >= nx-thick+1 and sx == 1): break
             elif (y0 < thick and sy == -1): break
             elif (y0 >= ny-thick+1 and sy == 1): break
-            if (x0 >=thick and x0 < nx-thick and y0 >= thick and y0 < ny-thick):
-                if has_alpha:
-                    for i in range(4):
-                        image[x0-thick/2:x0+(1+thick)/2, 
-                              y0-thick/2:y0+(1+thick)/2,i] = \
-                                (1.-alpha[3])*image[x0,y0,i] + alpha[i]
-                else:
-                    for i in range(3):
-                        image[x0-thick/2:x0+(1+thick)/2, 
-                              y0-thick/2:y0+(1+thick)/2,i] = \
-                                (1.-alpha[i])*image[x0,y0,i] + alpha[i]
+            if x0 >= thick and x0 < nx-thick and y0 >= thick and y0 < ny-thick:
+                for xi in range(x0-thick/2, x0+(1+thick)/2):
+                    for yi in range(y0-thick/2, y0+(1+thick)/2):
+                        if has_alpha:
+                            image[xi, yi, 3] = outa = alpha[3] + image[xi, yi, 3]*(1-alpha[3])
+                            if outa != 0.0:
+                                outa = 1.0/outa
+                            for i in range(3):
+                                image[xi, yi, i] = \
+                                        ((1.-alpha[3])*image[xi, yi, i]*image[xi, yi, 3]
+                                         + alpha[3]*alpha[i])*outa
+                        else:
+                            for i in range(3):
+                                image[xi, yi, i] = \
+                                        (1.-alpha[i])*image[xi,yi,i] + alpha[i]
 
             if (x0 == x1 and y0 == y1):
                 break

diff -r 8d7f5c67ba8ee7743618e07d6a1cd63cbd3dacef -r 27125ca054789df6869c96f378085486f39c58dc yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -1,15 +1,16 @@
 #
 # Physical Constants and Units Conversion Factors
 #
-# Values for these constants are drawn from IAU and IUPAC data 
-# unless otherwise noted:
+# Values for these constants, unless otherwise noted, are drawn from IAU,
+# IUPAC, and NIST data, whichever is newer.
 # http://maia.usno.navy.mil/NSFA/IAU2009_consts.html
 # http://goldbook.iupac.org/list_goldbook_phys_constants_defs.html
+# http://physics.nist.gov/cuu/Constants/index.html
 
 # Masses
-mass_hydrogen_cgs = 1.674534e-24  # g
-mass_electron_cgs = 9.1093898e-28  # g
-amu_cgs           = 1.6605402e-24  # g
+mass_electron_cgs = 9.109382-28  # g
+amu_cgs           = 1.660538921e-24  # g
+mass_hydrogen_cgs = 1.007947*amu_cgs  # g
 mass_sun_cgs = 1.98841586e33  # g
 # Velocities
 speed_of_light_cgs = 2.99792458e10  # cm/s, exact
@@ -22,10 +23,10 @@
 charge_proton_cgs = 4.8032056e-10  # esu = 1.602176487e-19  Coulombs
 
 # Physical Constants
-boltzmann_constant_cgs = 1.3806504e-16  # erg K^-1
-gravitational_constant_cgs  = 6.67428e-8  # cm^3 g^-1 s^-2
-planck_constant_cgs   = 6.62606896e-27  # erg s
-stefan_boltzmann_constant_cgs = 5.67051e-5 # erg cm^-2 s^-1 K^-4
+boltzmann_constant_cgs = 1.3806488e-16  # erg K^-1
+gravitational_constant_cgs  = 6.67384e-8  # cm^3 g^-1 s^-2
+planck_constant_cgs   = 6.62606957e-27  # erg s
+stefan_boltzmann_constant_cgs = 5.670373e-5 # erg cm^-2 s^-1 K^-4
 # The following value was calcualted assuming H = 100 km/s/Mpc.
 # To get the correct value for your cosmological parameters, 
 # you'll need to multiply through by h^2
@@ -69,16 +70,17 @@
 cm_per_pc     = 1.0 / pc_per_cm
 
 # time
+# "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 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_year = 31.5576e6
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25
 
 # temperature / energy
-erg_per_eV = 1.602176487e-12 # http://goldbook.iupac.org/E02014.html
+erg_per_eV = 1.602176562e-12
 erg_per_keV = erg_per_eV * 1.0e3
 K_per_keV = erg_per_keV / boltzmann_constant_cgs
 keV_per_K = 1.0 / K_per_keV

diff -r 8d7f5c67ba8ee7743618e07d6a1cd63cbd3dacef -r 27125ca054789df6869c96f378085486f39c58dc yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -37,11 +37,9 @@
 from functools import wraps
 from numbers import Number
 
-from ._mpl_imports import \
-    FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
+from ._mpl_imports import FigureCanvasAgg
 from .color_maps import yt_colormaps, is_colormap
-from .image_writer import \
-    write_image, apply_colormap
+from .image_writer import apply_colormap
 from .fixed_resolution import \
     FixedResolutionBuffer, \
     ObliqueFixedResolutionBuffer, \
@@ -52,21 +50,20 @@
 from .base_plot_types import ImagePlotMPL
 
 from yt.utilities.delaunay.triangulate import Triangulation as triang
-from yt.config import ytcfg
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
     fix_axis, get_image_suffix
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
-    x_dict, x_names, \
-    y_dict, y_names, \
+    x_dict, y_dict, \
     axis_names, axis_labels, \
     formatted_length_unit_names
 from yt.utilities.math_utils import \
     ortho_find
-from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    GroupOwnership
-from yt.utilities.exceptions import YTUnitNotRecognized, YTInvalidWidthError
+from yt.utilities.exceptions import \
+     YTUnitNotRecognized, YTInvalidWidthError, YTCannotParseUnitDisplayName, \
+     YTNotInsideNotebook
+
 from yt.data_objects.time_series import \
     TimeSeriesData
 
@@ -539,12 +536,6 @@
             self.center = new_center
         self.set_window(self.bounds)
 
-    @property
-    def width(self):
-        Wx = self.xlim[1] - self.xlim[0]
-        Wy = self.ylim[1] - self.ylim[0]
-        return (Wx, Wy)
-
     @invalidate_data
     def set_antialias(self,aa):
         self.antialias = aa
@@ -839,10 +830,6 @@
         return xc, yc
 
     def _setup_plots(self):
-        if self._current_field is not None:
-            fields = [self._current_field]
-        else:
-            fields = self._frb.keys()
         self._colorbar_valid = True
         for f in self.fields:
             axis_index = self.data_source.axis
@@ -1081,13 +1068,15 @@
 
     def _send_zmq(self):
         try:
-            # pre-IPython v0.14
+            # pre-IPython v1.0
             from IPython.zmq.pylab.backend_inline import send_figure as display
         except ImportError:
-            # IPython v0.14+
+            # IPython v1.0+
             from IPython.core.display import display
         for k, v in sorted(self.plots.iteritems()):
-            canvas = FigureCanvasAgg(v.figure)
+            # Due to a quirk in the matplotlib API, we need to create
+            # a dummy canvas variable here that is never used.
+            canvas = FigureCanvasAgg(v.figure)  # NOQA
             display(v.figure)
 
     def show(self):


https://bitbucket.org/yt_analysis/yt-3.0/commits/fe5d507ced3d/
Changeset:   fe5d507ced3d
Branch:      yt
User:        jzuhone
Date:        2013-07-19 03:36:14
Summary:     Merged in jforbes/yt (pull request #551)

Add a NumberDensity field to FLASH frontend.
Affected #:  1 file

diff -r f15815e182080e8619efd2636cce42bc6e598b7c -r fe5d507ced3db8b97fe29249b1f3ff2f0055fc3c yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -366,5 +366,21 @@
 add_field('nion', function=_nion, take_log=True, units=r"\rm{cm}^{-3}")
 
 def _abar(field, data):
-    return 1.0 / data['sumy']
+    try:
+        return 1.0 / data['sumy']
+    except:
+        pass
+    return data['dens']*Na*kboltz*data['temp']/data['pres']
 add_field('abar', function=_abar, take_log=False)
+	
+
+def _NumberDensity(fields,data) :
+    try:
+        return data["nele"]+data["nion"]
+    except:
+        pass
+    return data['pres']/(data['temp']*kboltz)
+add_field("NumberDensity", function=_NumberDensity,
+        units=r'\rm{cm}^{-3}')
+
+


https://bitbucket.org/yt_analysis/yt-3.0/commits/16973ce6a078/
Changeset:   16973ce6a078
Branch:      yt
User:        ngoldbaum
Date:        2013-07-16 02:32:08
Summary:     Fixing imports for IPython 1.0.
Affected #:  3 files

diff -r 2303e938a22ace1beb284d56b4ab719472cabcb5 -r 16973ce6a0786ec30009c7ba6c4aa879c8e6a088 scripts/iyt
--- a/scripts/iyt
+++ b/scripts/iyt
@@ -1,6 +1,6 @@
 #!python
 import os, re
-from distutils import version
+from distutils.version import LooseVersion
 from yt.mods import *
 from yt.data_objects.data_containers import AMRData
 namespace = locals().copy()
@@ -23,10 +23,12 @@
     code.interact(doc, None, namespace)
     sys.exit()
 
-if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
     api_version = '0.10'
+elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+    api_version = '0.11'
 else:
-    api_version = '0.11'
+    api_version = '1.0'
 
 if api_version == "0.10" and "DISPLAY" in os.environ:
     from matplotlib import rcParams
@@ -42,13 +44,18 @@
         ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
 elif api_version == "0.10":
     ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
-elif api_version == "0.11":
-    from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
+else:
+    if api_version == "0.11":
+        from IPython.frontend.terminal.interactiveshell import \
+            TerminalInteractiveShell
+    elif api_version == "1.0":
+        from IPython.terminal.interactiveshell import TerminalInteractiveShell
+    else:
+        raise RuntimeError
     ip_shell = TerminalInteractiveShell(user_ns=namespace, banner1 = doc,
                     display_banner = True)
     if "DISPLAY" in os.environ: ip_shell.enable_pylab(import_all=False)
-else:
-    raise RuntimeError
+
 
 # The rest is a modified version of the IPython default profile code
 
@@ -77,7 +84,7 @@
     ip = ip_shell.IP.getapi()
     try_next = IPython.ipapi.TryNext
     kwargs = dict(sys_exit=1, banner=doc)
-elif api_version == "0.11":
+elif api_version in ("0.11", "1.0"):
     ip = ip_shell
     try_next = IPython.core.error.TryNext
     kwargs = dict()

diff -r 2303e938a22ace1beb284d56b4ab719472cabcb5 -r 16973ce6a0786ec30009c7ba6c4aa879c8e6a088 yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -28,7 +28,7 @@
 import contextlib
 import warnings, struct, subprocess
 import numpy as np
-from distutils import version
+from distutils.version import LooseVersion
 from math import floor, ceil
 
 from yt.utilities.exceptions import *
@@ -260,10 +260,12 @@
     """
 
     import IPython
-    if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
         api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
     else:
-        api_version = '0.11'
+        api_version = '1.0'
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]
@@ -281,7 +283,10 @@
         cfg.InteractiveShellEmbed.local_ns = loc
         cfg.InteractiveShellEmbed.global_ns = glo
         IPython.embed(config=cfg, banner2 = __header % dd)
-        from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        if api_version == '0.11':
+            from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        else:
+            from IPython.terminal.embed import InteractiveShellEmbed
         ipshell = InteractiveShellEmbed(config=cfg)
 
     del ipshell

diff -r 2303e938a22ace1beb284d56b4ab719472cabcb5 -r 16973ce6a0786ec30009c7ba6c4aa879c8e6a088 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1456,7 +1456,12 @@
         """
     def __call__(self, args):
         kwargs = {}
-        from IPython.frontend.html.notebook.notebookapp import NotebookApp
+        try:
+            # IPython 1.0+
+            from IPython.html.notebookapp import NotebookApp
+        except ImportError:
+            # pre-IPython v1.0
+            from IPython.frontend.html.notebook.notebookapp import NotebookApp
         pw = ytcfg.get("yt", "notebook_password")
         if len(pw) == 0 and not args.no_password:
             import IPython.lib


https://bitbucket.org/yt_analysis/yt-3.0/commits/c8ce7b6481b2/
Changeset:   c8ce7b6481b2
Branch:      yt
User:        ngoldbaum
Date:        2013-07-16 02:34:23
Summary:     Modifying PWViewrMPL.__repr__ so things work more nicele in the notebook.
Affected #:  1 file

diff -r 16973ce6a0786ec30009c7ba6c4aa879c8e6a088 -r c8ce7b6481b2aac4f43a0986da59f00caaebaab6 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -394,7 +394,7 @@
         nWx, nWy = Wx/factor, Wy/factor
         self.xlim = (centerx - nWx*0.5, centerx + nWx*0.5)
         self.ylim = (centery - nWy*0.5, centery + nWy*0.5)
-
+        return self
 
     @invalidate_data
     def pan(self, deltas):
@@ -408,6 +408,7 @@
         """
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
+        return self
 
     @invalidate_data
     def pan_rel(self, deltas):
@@ -422,6 +423,7 @@
         Wx, Wy = self.width
         self.xlim = (self.xlim[0] + Wx*deltas[0], self.xlim[1] + Wx*deltas[0])
         self.ylim = (self.ylim[0] + Wy*deltas[1], self.ylim[1] + Wy*deltas[1])
+        return self
 
     @invalidate_data
     def set_window(self, bounds):
@@ -1110,6 +1112,11 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def __repr__(self):
+        if "__IPYTHON__" in dir(__builtin__):
+            self.show()
+        return super(PWViewerMPL, self).__repr__()
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/e3e4f4578504/
Changeset:   e3e4f4578504
Branch:      yt
User:        MatthewTurk
Date:        2013-07-19 15:37:39
Summary:     Merged in ngoldbaum/yt (pull request #555)

IPython 1.0 support and improved plotting inside the notebook.
Affected #:  4 files

diff -r fe5d507ced3db8b97fe29249b1f3ff2f0055fc3c -r e3e4f4578504b7eb2e929275ad8441ef3900572c scripts/iyt
--- a/scripts/iyt
+++ b/scripts/iyt
@@ -1,6 +1,6 @@
 #!python
 import os, re
-from distutils import version
+from distutils.version import LooseVersion
 from yt.mods import *
 from yt.data_objects.data_containers import AMRData
 namespace = locals().copy()
@@ -23,10 +23,12 @@
     code.interact(doc, None, namespace)
     sys.exit()
 
-if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
     api_version = '0.10'
+elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+    api_version = '0.11'
 else:
-    api_version = '0.11'
+    api_version = '1.0'
 
 if api_version == "0.10" and "DISPLAY" in os.environ:
     from matplotlib import rcParams
@@ -42,13 +44,18 @@
         ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
 elif api_version == "0.10":
     ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
-elif api_version == "0.11":
-    from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
+else:
+    if api_version == "0.11":
+        from IPython.frontend.terminal.interactiveshell import \
+            TerminalInteractiveShell
+    elif api_version == "1.0":
+        from IPython.terminal.interactiveshell import TerminalInteractiveShell
+    else:
+        raise RuntimeError
     ip_shell = TerminalInteractiveShell(user_ns=namespace, banner1 = doc,
                     display_banner = True)
     if "DISPLAY" in os.environ: ip_shell.enable_pylab(import_all=False)
-else:
-    raise RuntimeError
+
 
 # The rest is a modified version of the IPython default profile code
 
@@ -77,7 +84,7 @@
     ip = ip_shell.IP.getapi()
     try_next = IPython.ipapi.TryNext
     kwargs = dict(sys_exit=1, banner=doc)
-elif api_version == "0.11":
+elif api_version in ("0.11", "1.0"):
     ip = ip_shell
     try_next = IPython.core.error.TryNext
     kwargs = dict()

diff -r fe5d507ced3db8b97fe29249b1f3ff2f0055fc3c -r e3e4f4578504b7eb2e929275ad8441ef3900572c yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -28,7 +28,7 @@
 import contextlib
 import warnings, struct, subprocess
 import numpy as np
-from distutils import version
+from distutils.version import LooseVersion
 from math import floor, ceil
 
 from yt.utilities.exceptions import *
@@ -260,10 +260,12 @@
     """
 
     import IPython
-    if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
         api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
     else:
-        api_version = '0.11'
+        api_version = '1.0'
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]
@@ -281,7 +283,10 @@
         cfg.InteractiveShellEmbed.local_ns = loc
         cfg.InteractiveShellEmbed.global_ns = glo
         IPython.embed(config=cfg, banner2 = __header % dd)
-        from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        if api_version == '0.11':
+            from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        else:
+            from IPython.terminal.embed import InteractiveShellEmbed
         ipshell = InteractiveShellEmbed(config=cfg)
 
     del ipshell

diff -r fe5d507ced3db8b97fe29249b1f3ff2f0055fc3c -r e3e4f4578504b7eb2e929275ad8441ef3900572c yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1456,7 +1456,12 @@
         """
     def __call__(self, args):
         kwargs = {}
-        from IPython.frontend.html.notebook.notebookapp import NotebookApp
+        try:
+            # IPython 1.0+
+            from IPython.html.notebookapp import NotebookApp
+        except ImportError:
+            # pre-IPython v1.0
+            from IPython.frontend.html.notebook.notebookapp import NotebookApp
         pw = ytcfg.get("yt", "notebook_password")
         if len(pw) == 0 and not args.no_password:
             import IPython.lib

diff -r fe5d507ced3db8b97fe29249b1f3ff2f0055fc3c -r e3e4f4578504b7eb2e929275ad8441ef3900572c yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -394,7 +394,7 @@
         nWx, nWy = Wx/factor, Wy/factor
         self.xlim = (centerx - nWx*0.5, centerx + nWx*0.5)
         self.ylim = (centery - nWy*0.5, centery + nWy*0.5)
-
+        return self
 
     @invalidate_data
     def pan(self, deltas):
@@ -408,6 +408,7 @@
         """
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
+        return self
 
     @invalidate_data
     def pan_rel(self, deltas):
@@ -422,6 +423,7 @@
         Wx, Wy = self.width
         self.xlim = (self.xlim[0] + Wx*deltas[0], self.xlim[1] + Wx*deltas[0])
         self.ylim = (self.ylim[0] + Wy*deltas[1], self.ylim[1] + Wy*deltas[1])
+        return self
 
     @invalidate_data
     def set_window(self, bounds):
@@ -1110,6 +1112,11 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def __repr__(self):
+        if "__IPYTHON__" in dir(__builtin__):
+            self.show()
+        return super(PWViewerMPL, self).__repr__()
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/f6b83a026bb9/
Changeset:   f6b83a026bb9
Branch:      yt
User:        atmyers
Date:        2013-07-23 02:57:07
Summary:     small correction to some plot_window docstrings
Affected #:  1 file

diff -r e3e4f4578504b7eb2e929275ad8441ef3900572c -r f6b83a026bb98e369da718e3c959174243d7d04e yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -702,7 +702,7 @@
                             'ParticleCallback','ClumpContourCallback',
                             'GridBoundaryCallback']
             if self._plot_type == 'OffAxisProjection':
-                ignored += ['VelocityCallback','MagFieldCallback',
+                ignored += ['MagFieldCallback',
                             'QuiverCallback','CuttingQuiverCallback',
                             'StreamlineCallback']
             if key in ignored:
@@ -1137,12 +1137,10 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'.
+         The coordinate of the center of the image. If set to 'c' or 'center' or 
+         left blank, the plot is centered on the middle of the domain.  If set to 'max', 
+         the center 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:
@@ -1247,12 +1245,10 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'.
+         The coordinate of the center of the image. If set to 'c' or 'center' or 
+         left blank, the plot is centered on the middle of the domain.  If set to 'max', 
+         the center 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:
@@ -1366,10 +1362,8 @@
     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 blank,
-        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 coordinate of the center of the image. If set to 'c' or 'center' or 
+        left blank, the plot is centered on the middle of the domain.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1429,6 +1423,13 @@
         self.re = re
         self.north_vector = north_vector
 
+    def __getitem__(self, item):
+        lo = self.center - 0.5*self.width
+        hi = self.center + 0.5*self.width
+        bounds = [lo[0], hi[0], lo[1], hi[1], lo[2], hi[2]]
+        frb = OffAxisProjectionFixedResolutionBuffer(self, bounds, self.resolution)
+        return frb[item]
+
 class OffAxisProjectionPlot(PWViewerMPL):
     r"""Creates an off axis projection plot from a parameter file
 
@@ -1449,10 +1450,8 @@
     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 blank,
-        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 coordinate of the center of the image. If set to 'c' or 'center' or 
+        left blank, the plot is centered on the middle of the domain.
     width : tuple or a float.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:


https://bitbucket.org/yt_analysis/yt-3.0/commits/4f24028ef60c/
Changeset:   4f24028ef60c
Branch:      yt
User:        atmyers
Date:        2013-07-23 03:00:13
Summary:     reverting out a change I made by mistake
Affected #:  1 file

diff -r f6b83a026bb98e369da718e3c959174243d7d04e -r 4f24028ef60cf24792e3263d316cbcf6436c8328 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -702,7 +702,7 @@
                             'ParticleCallback','ClumpContourCallback',
                             'GridBoundaryCallback']
             if self._plot_type == 'OffAxisProjection':
-                ignored += ['MagFieldCallback',
+                ignored += ['VelocityCallback','MagFieldCallback',
                             'QuiverCallback','CuttingQuiverCallback',
                             'StreamlineCallback']
             if key in ignored:


https://bitbucket.org/yt_analysis/yt-3.0/commits/437303af3687/
Changeset:   437303af3687
Branch:      yt
User:        atmyers
Date:        2013-07-23 03:01:51
Summary:     pointless fiddling
Affected #:  1 file

diff -r 4f24028ef60cf24792e3263d316cbcf6436c8328 -r 437303af368711f854c79ba98b0b3d42dbbccdb2 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1138,7 +1138,7 @@
     fields : string
          The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'.
-         The coordinate of the center of the image. If set to 'c' or 'center' or 
+         The coordinate of the center of the image. If set to 'c', 'center' or 
          left blank, the plot is centered on the middle of the domain.  If set to 'max', 
          the center will be at the point of highest density.
     width : tuple or a float.
@@ -1246,7 +1246,7 @@
     fields : string
         The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'.
-         The coordinate of the center of the image. If set to 'c' or 'center' or 
+         The coordinate of the center of the image. If set to 'c', 'center' or 
          left blank, the plot is centered on the middle of the domain.  If set to 'max', 
          the center will be at the point of highest density.
     width : tuple or a float.
@@ -1362,7 +1362,7 @@
     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 set to 'c' or 'center' or 
+        The coordinate of the center of the image. If set to 'c', 'center' or 
         left blank, the plot is centered on the middle of the domain.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
@@ -1450,7 +1450,7 @@
     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 set to 'c' or 'center' or 
+        The coordinate of the center of the image. If set to 'c', 'center' or 
         left blank, the plot is centered on the middle of the domain.
     width : tuple or a float.
          Width can have four different formats to support windows with variable


https://bitbucket.org/yt_analysis/yt-3.0/commits/32c7b44cfa83/
Changeset:   32c7b44cfa83
Branch:      yt
User:        atmyers
Date:        2013-07-23 04:28:46
Summary:     removing __getitem__ from OffAxisProjectionDummyDataSource, which I included in this PR by mistake
Affected #:  1 file

diff -r 437303af368711f854c79ba98b0b3d42dbbccdb2 -r 32c7b44cfa837a0c39962bde10900d0707fbe4aa yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1423,13 +1423,6 @@
         self.re = re
         self.north_vector = north_vector
 
-    def __getitem__(self, item):
-        lo = self.center - 0.5*self.width
-        hi = self.center + 0.5*self.width
-        bounds = [lo[0], hi[0], lo[1], hi[1], lo[2], hi[2]]
-        frb = OffAxisProjectionFixedResolutionBuffer(self, bounds, self.resolution)
-        return frb[item]
-
 class OffAxisProjectionPlot(PWViewerMPL):
     r"""Creates an off axis projection plot from a parameter file
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/e1234dcf6e2f/
Changeset:   e1234dcf6e2f
Branch:      yt
User:        atmyers
Date:        2013-07-23 04:32:08
Summary:     adding explanations of the 'max' and 'm' options to the docs
Affected #:  1 file

diff -r 32c7b44cfa837a0c39962bde10900d0707fbe4aa -r e1234dcf6e2f1a5a1f2f85e7522c2e8d61056bf7 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1139,8 +1139,8 @@
          The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'.
          The coordinate of the center of the image. If set to 'c', 'center' or 
-         left blank, the plot is centered on the middle of the domain.  If set to 'max', 
-         the center will be at the point of highest density.
+         left blank, the plot is centered on the middle of the domain. If set to 'max' 
+         or 'm', the center 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:
@@ -1247,8 +1247,8 @@
         The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center', or 'max'.
          The coordinate of the center of the image. If set to 'c', 'center' or 
-         left blank, the plot is centered on the middle of the domain.  If set to 'max', 
-         the center will be at the point of highest density.
+         left blank, the plot is centered on the middle of the domain. If set to 'max' 
+         or 'm', the center 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:
@@ -1363,7 +1363,8 @@
         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 set to 'c', 'center' or 
-        left blank, the plot is centered on the middle of the domain.
+        left blank, the plot is centered on the middle of the domain. If set to
+        'max' or 'm', the center will be at the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1444,7 +1445,8 @@
         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 set to 'c', 'center' or 
-        left blank, the plot is centered on the middle of the domain.
+        left blank, the plot is centered on the middle of the domain. If set to
+        'max' or 'm', the center 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:


https://bitbucket.org/yt_analysis/yt-3.0/commits/f8fbed2bf4fa/
Changeset:   f8fbed2bf4fa
Branch:      yt
User:        atmyers
Date:        2013-07-23 04:35:31
Summary:     one more change to the docs
Affected #:  1 file

diff -r e1234dcf6e2f1a5a1f2f85e7522c2e8d61056bf7 -r f8fbed2bf4fa4d2dcc28d3ae407aea6efc880bcf yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1137,10 +1137,11 @@
          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', or 'max'.
-         The coordinate of the center of the image. If set to 'c', 'center' or 
-         left blank, the plot is centered on the middle of the domain. If set to 'max' 
-         or 'm', the center will be at the point of highest density.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1245,11 +1246,11 @@
          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', or 'max'.
-         The coordinate of the center of the image. If set to 'c', 'center' or 
-         left blank, the plot is centered on the middle of the domain. If set to 'max' 
-         or 'm', the center will be at the point of highest density.
-    width : tuple or a float.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:
 
@@ -1361,10 +1362,11 @@
         The vector normal to the slicing plane.
     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 set to 'c', 'center' or 
-        left blank, the plot is centered on the middle of the domain. If set to
-        'max' or 'm', the center will be at the point of highest density.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1443,10 +1445,11 @@
         The vector normal to the slicing plane.
     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 set to 'c', 'center' or 
-        left blank, the plot is centered on the middle of the domain. If set to
-        'max' or 'm', the center will be at the point of highest density.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:


https://bitbucket.org/yt_analysis/yt-3.0/commits/30d7d5046213/
Changeset:   30d7d5046213
Branch:      yt
User:        MatthewTurk
Date:        2013-07-24 19:09:35
Summary:     Quick fix for gids array being passed to Cython.
Affected #:  1 file

diff -r f8fbed2bf4fa4d2dcc28d3ae407aea6efc880bcf -r 30d7d50462133455ee81d6dec3f7da5b37c5c31e yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -107,7 +107,8 @@
         for lvl in lvl_range:
             gles = np.array([g.LeftEdge for g in grids if g.Level == lvl])
             gres = np.array([g.RightEdge for g in grids if g.Level == lvl])
-            gids = np.array([g.id for g in grids if g.Level == lvl])
+            gids = np.array([g.id for g in grids if g.Level == lvl],
+                            dtype="int64")
 
             add_pygrids(self.trunk, len(gids), gles, gres, gids, self.comm_rank, self.comm_size)
             del gles, gres, gids


https://bitbucket.org/yt_analysis/yt-3.0/commits/a871c3ae20da/
Changeset:   a871c3ae20da
Branch:      yt
User:        ngoldbaum
Date:        2013-07-20 23:49:35
Summary:     Persisting the figure and axes if they've already been created.
Affected #:  2 files

diff -r e3e4f4578504b7eb2e929275ad8441ef3900572c -r a871c3ae20dafcfc363cf5eb8e4afebeed89bce3 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -33,12 +33,15 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            self.figure = figure
+            self.axes = axes
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -67,9 +70,9 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
         self.cax = self.figure.add_axes(caxrect)
 

diff -r e3e4f4578504b7eb2e929275ad8441ef3900572c -r a871c3ae20dafcfc363cf5eb8e4afebeed89bce3 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -878,9 +878,15 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            if self.plots.has_key(f):
+                fig = self.plots[f].figure
+                axes = self.plots[f].axes
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -1751,7 +1757,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size, fontsize):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+            figure, axes):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             mylog.warning('The axis ratio of the requested plot is very narrow.  '
@@ -1760,7 +1768,7 @@
                           'and matplotlib.')
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim, figure, axes)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':


https://bitbucket.org/yt_analysis/yt-3.0/commits/aafaf5e05853/
Changeset:   aafaf5e05853
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 00:28:34
Summary:     Only persist plots if the plot bounds are the same in plot coordinates.
Affected #:  1 file

diff -r a871c3ae20dafcfc363cf5eb8e4afebeed89bce3 -r aafaf5e058537af917624886e4bf10cf9de18fb7 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -881,8 +881,10 @@
             fig = None
             axes = None
             if self.plots.has_key(f):
-                fig = self.plots[f].figure
-                axes = self.plots[f].axes
+                if extent == list(self.plots[f].figure.axes[0].get_xlim() +
+                                  self.plots[f].figure.axes[0].get_ylim()):
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
 
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,


https://bitbucket.org/yt_analysis/yt-3.0/commits/d64966317aa5/
Changeset:   d64966317aa5
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 02:05:17
Summary:     Updates to fix failing answer tests.
Affected #:  2 files

diff -r aafaf5e058537af917624886e4bf10cf9de18fb7 -r d64966317aa572ce73ea06e2e06b565cd59d1d34 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -74,9 +74,11 @@
         """Initialize ImagePlotMPL class object"""
         PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
+        if figure is not None:
+            self.figure.delaxes(self.figure.axes[1])
         self.cax = self.figure.add_axes(caxrect)
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r aafaf5e058537af917624886e4bf10cf9de18fb7 -r d64966317aa572ce73ea06e2e06b565cd59d1d34 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -90,6 +90,16 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -558,6 +568,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -881,10 +892,11 @@
             fig = None
             axes = None
             if self.plots.has_key(f):
-                if extent == list(self.plots[f].figure.axes[0].get_xlim() +
-                                  self.plots[f].figure.axes[0].get_ylim()):
-                    fig = self.plots[f].figure
-                    axes = self.plots[f].axes
+                if self.plots[f].figure is not None:
+                    if extent == list(self.plots[f].figure.axes[0].get_xlim() +
+                                      self.plots[f].figure.axes[0].get_ylim()):
+                        fig = self.plots[f].figure
+                        axes = self.plots[f].axes
 
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
@@ -955,6 +967,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/53372213b579/
Changeset:   53372213b579
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 02:05:32
Summary:     Adding a missing autogenerated c routine yt .hgignore.
Affected #:  1 file

diff -r d64966317aa572ce73ea06e2e06b565cd59d1d34 -r 53372213b5798fd605bcb39f4fdfa6c2fcf1b039 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,6 +12,7 @@
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c


https://bitbucket.org/yt_analysis/yt-3.0/commits/47800a937ca8/
Changeset:   47800a937ca8
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 02:36:44
Summary:     One last fix for the failing answer tests.
Affected #:  1 file

diff -r 53372213b5798fd605bcb39f4fdfa6c2fcf1b039 -r 47800a937ca80f510f3456dca1ad97e31d6f87c3 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -41,6 +41,7 @@
             self.axes = self.figure.add_axes(axrect)
         else:
             self.figure = figure
+            axes.cla()
             self.axes = axes
 
     def save(self, name, mpl_kwargs, canvas=None):


https://bitbucket.org/yt_analysis/yt-3.0/commits/6f91fb293726/
Changeset:   6f91fb293726
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 02:52:36
Summary:     Only create a new figure if the aspect ratio changes.
Affected #:  1 file

diff -r 47800a937ca80f510f3456dca1ad97e31d6f87c3 -r 6f91fb293726757ee36a21dafdc5cd60bf45da5c yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -893,8 +893,10 @@
             axes = None
             if self.plots.has_key(f):
                 if self.plots[f].figure is not None:
-                    if extent == list(self.plots[f].figure.axes[0].get_xlim() +
-                                      self.plots[f].figure.axes[0].get_ylim()):
+                    oe = list(self.plots[f].figure.axes[0].get_xlim() +
+                              self.plots[f].figure.axes[0].get_ylim())
+                    if (oe[1] - oe[0]) / (oe[3] - oe[2]) == \
+                       (extent[1] - extent[0]) / (extent[3] - extent[2]):
                         fig = self.plots[f].figure
                         axes = self.plots[f].axes
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/2777bdca59ab/
Changeset:   2777bdca59ab
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 21:56:10
Summary:     Setting the default canvas a bit earlier.  This makes animations easier.
Affected #:  1 file

diff -r 6f91fb293726757ee36a21dafdc5cd60bf45da5c -r 2777bdca59abb3e8a15a64d4c22a4a482c5a0191 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -39,6 +39,7 @@
         if figure is None:
             self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
             self.axes = self.figure.add_axes(axrect)
+            self.canvas = FigureCanvasAgg(self.figure)
         else:
             self.figure = figure
             axes.cla()
@@ -61,7 +62,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name


https://bitbucket.org/yt_analysis/yt-3.0/commits/335b1c181f8e/
Changeset:   335b1c181f8e
Branch:      yt
User:        ngoldbaum
Date:        2013-07-21 22:05:23
Summary:     Setting the canvas outside a conditional to avoid doing it twice.
Affected #:  1 file

diff -r 2777bdca59abb3e8a15a64d4c22a4a482c5a0191 -r 335b1c181f8e62d4dab32d89db46e8f8feb084be yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -39,11 +39,11 @@
         if figure is None:
             self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
             self.axes = self.figure.add_axes(axrect)
-            self.canvas = FigureCanvasAgg(self.figure)
         else:
             self.figure = figure
             axes.cla()
             self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""


https://bitbucket.org/yt_analysis/yt-3.0/commits/683e4ea8530e/
Changeset:   683e4ea8530e
Branch:      yt
User:        ngoldbaum
Date:        2013-07-22 06:46:53
Summary:     Simplifying things.  Treating colorbar axes just like the image other axes.
Affected #:  2 files

diff -r 335b1c181f8e62d4dab32d89db46e8f8feb084be -r 683e4ea8530e74b19b830301d067f7479feaaeec yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -38,9 +38,12 @@
         self._plot_valid = True
         if figure is None:
             self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
             self.axes = self.figure.add_axes(axrect)
         else:
-            self.figure = figure
             axes.cla()
             self.axes = axes
         self.canvas = FigureCanvasAgg(self.figure)
@@ -72,13 +75,16 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
         PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        if figure is not None:
-            self.figure.delaxes(self.figure.axes[1])
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
     def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""

diff -r 335b1c181f8e62d4dab32d89db46e8f8feb084be -r 683e4ea8530e74b19b830301d067f7479feaaeec yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -97,6 +97,7 @@
         for field in args[0].fields:
             args[0].plots[field].figure = None
             args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
         return rv
     return newfunc
 
@@ -891,18 +892,17 @@
 
             fig = None
             axes = None
+            cax = None
             if self.plots.has_key(f):
                 if self.plots[f].figure is not None:
-                    oe = list(self.plots[f].figure.axes[0].get_xlim() +
-                              self.plots[f].figure.axes[0].get_ylim())
-                    if (oe[1] - oe[0]) / (oe[3] - oe[2]) == \
-                       (extent[1] - extent[0]) / (extent[3] - extent[2]):
-                        fig = self.plots[f].figure
-                        axes = self.plots[f].axes
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
 
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size(), fig, axes)
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -1776,7 +1776,7 @@
 class WindowPlotMPL(ImagePlotMPL):
     def __init__(
             self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
-            figure, axes):
+            figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             mylog.warning('The axis ratio of the requested plot is very narrow.  '
@@ -1785,7 +1785,8 @@
                           'and matplotlib.')
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim, figure, axes)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':


https://bitbucket.org/yt_analysis/yt-3.0/commits/0fa3092155e5/
Changeset:   0fa3092155e5
Branch:      yt
User:        xarthisius
Date:        2013-07-25 08:28:35
Summary:     Merged in ngoldbaum/yt (pull request #556)

Persist matplotlib figure and axes as PlotWindow plots are modified.
Affected #:  3 files

diff -r 30d7d50462133455ee81d6dec3f7da5b37c5c31e -r 0fa3092155e585ba80513dd8f153d70186f2b67f .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,6 +12,7 @@
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c

diff -r 30d7d50462133455ee81d6dec3f7da5b37c5c31e -r 0fa3092155e585ba80513dd8f153d70186f2b67f yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -33,12 +33,20 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            axes.cla()
+            self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -57,7 +65,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name
@@ -67,13 +75,18 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r 30d7d50462133455ee81d6dec3f7da5b37c5c31e -r 0fa3092155e585ba80513dd8f153d70186f2b67f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -90,6 +90,17 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -558,6 +569,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -878,9 +890,19 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            cax = None
+            if self.plots.has_key(f):
+                if self.plots[f].figure is not None:
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -947,6 +969,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 
@@ -1748,7 +1771,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size, fontsize):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+            figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             mylog.warning('The axis ratio of the requested plot is very narrow.  '
@@ -1757,7 +1782,8 @@
                           'and matplotlib.')
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':


https://bitbucket.org/yt_analysis/yt-3.0/commits/3bc43f5f4675/
Changeset:   3bc43f5f4675
Branch:      yt
User:        samskillman
Date:        2013-07-25 19:39:35
Summary:     Explicitly cast width to float64. Fixes when widths are specified in int/long.
Affected #:  1 file

diff -r f15815e182080e8619efd2636cce42bc6e598b7c -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -582,7 +582,7 @@
                 (-self.width[0]/2.0, self.width[0]/2.0,
                  -self.width[1]/2.0, self.width[1]/2.0),
                 image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.transfer_function, self.sub_samples)
+                np.array(self.width, dtype='float64'), self.transfer_function, self.sub_samples)
         return args
 
     star_trees = None
@@ -2192,10 +2192,10 @@
     def get_sampler_args(self, image):
         rotp = np.concatenate([self.orienter.inv_mat.ravel('F'), self.back_center.ravel()])
         args = (rotp, self.box_vectors[2], self.back_center,
-            (-self.width[0]/2, self.width[0]/2,
-             -self.width[1]/2, self.width[1]/2),
+            (-self.width[0]/2., self.width[0]/2.,
+             -self.width[1]/2., self.width[1]/2.),
             image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.sub_samples)
+                np.array(self.width, dtype='float64'), self.sub_samples)
         return args
 
     def finalize_image(self,image):


https://bitbucket.org/yt_analysis/yt-3.0/commits/3f48788e6dbd/
Changeset:   3f48788e6dbd
Branch:      yt
User:        samskillman
Date:        2013-07-25 19:40:21
Summary:     Merging
Affected #:  8 files

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,6 +12,7 @@
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 scripts/iyt
--- a/scripts/iyt
+++ b/scripts/iyt
@@ -1,6 +1,6 @@
 #!python
 import os, re
-from distutils import version
+from distutils.version import LooseVersion
 from yt.mods import *
 from yt.data_objects.data_containers import AMRData
 namespace = locals().copy()
@@ -23,10 +23,12 @@
     code.interact(doc, None, namespace)
     sys.exit()
 
-if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
     api_version = '0.10'
+elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+    api_version = '0.11'
 else:
-    api_version = '0.11'
+    api_version = '1.0'
 
 if api_version == "0.10" and "DISPLAY" in os.environ:
     from matplotlib import rcParams
@@ -42,13 +44,18 @@
         ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
 elif api_version == "0.10":
     ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
-elif api_version == "0.11":
-    from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
+else:
+    if api_version == "0.11":
+        from IPython.frontend.terminal.interactiveshell import \
+            TerminalInteractiveShell
+    elif api_version == "1.0":
+        from IPython.terminal.interactiveshell import TerminalInteractiveShell
+    else:
+        raise RuntimeError
     ip_shell = TerminalInteractiveShell(user_ns=namespace, banner1 = doc,
                     display_banner = True)
     if "DISPLAY" in os.environ: ip_shell.enable_pylab(import_all=False)
-else:
-    raise RuntimeError
+
 
 # The rest is a modified version of the IPython default profile code
 
@@ -77,7 +84,7 @@
     ip = ip_shell.IP.getapi()
     try_next = IPython.ipapi.TryNext
     kwargs = dict(sys_exit=1, banner=doc)
-elif api_version == "0.11":
+elif api_version in ("0.11", "1.0"):
     ip = ip_shell
     try_next = IPython.core.error.TryNext
     kwargs = dict()

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -366,5 +366,21 @@
 add_field('nion', function=_nion, take_log=True, units=r"\rm{cm}^{-3}")
 
 def _abar(field, data):
-    return 1.0 / data['sumy']
+    try:
+        return 1.0 / data['sumy']
+    except:
+        pass
+    return data['dens']*Na*kboltz*data['temp']/data['pres']
 add_field('abar', function=_abar, take_log=False)
+	
+
+def _NumberDensity(fields,data) :
+    try:
+        return data["nele"]+data["nion"]
+    except:
+        pass
+    return data['pres']/(data['temp']*kboltz)
+add_field("NumberDensity", function=_NumberDensity,
+        units=r'\rm{cm}^{-3}')
+
+

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -28,7 +28,7 @@
 import contextlib
 import warnings, struct, subprocess
 import numpy as np
-from distutils import version
+from distutils.version import LooseVersion
 from math import floor, ceil
 
 from yt.utilities.exceptions import *
@@ -260,10 +260,12 @@
     """
 
     import IPython
-    if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
         api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
     else:
-        api_version = '0.11'
+        api_version = '1.0'
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]
@@ -281,7 +283,10 @@
         cfg.InteractiveShellEmbed.local_ns = loc
         cfg.InteractiveShellEmbed.global_ns = glo
         IPython.embed(config=cfg, banner2 = __header % dd)
-        from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        if api_version == '0.11':
+            from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        else:
+            from IPython.terminal.embed import InteractiveShellEmbed
         ipshell = InteractiveShellEmbed(config=cfg)
 
     del ipshell

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -107,7 +107,8 @@
         for lvl in lvl_range:
             gles = np.array([g.LeftEdge for g in grids if g.Level == lvl])
             gres = np.array([g.RightEdge for g in grids if g.Level == lvl])
-            gids = np.array([g.id for g in grids if g.Level == lvl])
+            gids = np.array([g.id for g in grids if g.Level == lvl],
+                            dtype="int64")
 
             add_pygrids(self.trunk, len(gids), gles, gres, gids, self.comm_rank, self.comm_size)
             del gles, gres, gids

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1456,7 +1456,12 @@
         """
     def __call__(self, args):
         kwargs = {}
-        from IPython.frontend.html.notebook.notebookapp import NotebookApp
+        try:
+            # IPython 1.0+
+            from IPython.html.notebookapp import NotebookApp
+        except ImportError:
+            # pre-IPython v1.0
+            from IPython.frontend.html.notebook.notebookapp import NotebookApp
         pw = ytcfg.get("yt", "notebook_password")
         if len(pw) == 0 and not args.no_password:
             import IPython.lib

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -33,12 +33,20 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            axes.cla()
+            self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -57,7 +65,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name
@@ -67,13 +75,18 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r 3bc43f5f46752272783fb6d3d606ecb61b34dbd3 -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -90,6 +90,17 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -394,7 +405,7 @@
         nWx, nWy = Wx/factor, Wy/factor
         self.xlim = (centerx - nWx*0.5, centerx + nWx*0.5)
         self.ylim = (centery - nWy*0.5, centery + nWy*0.5)
-
+        return self
 
     @invalidate_data
     def pan(self, deltas):
@@ -408,6 +419,7 @@
         """
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
+        return self
 
     @invalidate_data
     def pan_rel(self, deltas):
@@ -422,6 +434,7 @@
         Wx, Wy = self.width
         self.xlim = (self.xlim[0] + Wx*deltas[0], self.xlim[1] + Wx*deltas[0])
         self.ylim = (self.ylim[0] + Wy*deltas[1], self.ylim[1] + Wy*deltas[1])
+        return self
 
     @invalidate_data
     def set_window(self, bounds):
@@ -556,6 +569,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -876,9 +890,19 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            cax = None
+            if self.plots.has_key(f):
+                if self.plots[f].figure is not None:
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -945,6 +969,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 
@@ -1110,6 +1135,11 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def __repr__(self):
+        if "__IPYTHON__" in dir(__builtin__):
+            self.show()
+        return super(PWViewerMPL, self).__repr__()
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 
@@ -1130,12 +1160,11 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1240,13 +1269,11 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:
 
@@ -1358,11 +1385,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1441,11 +1468,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1744,7 +1771,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size, fontsize):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+            figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             mylog.warning('The axis ratio of the requested plot is very narrow.  '
@@ -1753,7 +1782,8 @@
                           'and matplotlib.')
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':


https://bitbucket.org/yt_analysis/yt-3.0/commits/4b4597c8648a/
Changeset:   4b4597c8648a
Branch:      yt
User:        jzuhone
Date:        2013-07-26 18:04:01
Summary:     The definitions for the Gas_Energy and Pressure fields (in conserved variable outputs) incorrectly assumed that the magnetic fields would always be present. The convert function for the Gas_Energy field was also not being passed to add_field.
Affected #:  1 file

diff -r 3f48788e6dbd75afaeb49e9c180cd69273feabc1 -r 4b4597c8648ad49189012024b1782154d44ba195 yt/frontends/athena/fields.py
--- a/yt/frontends/athena/fields.py
+++ b/yt/frontends/athena/fields.py
@@ -128,15 +128,16 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]/(data.pf["Gamma"]-1.0)/data["density"]
     else:
-        return (data["total_energy"] - 
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) - 
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])/data["density"]
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint/data["density"]
 add_field("Gas_Energy", function=_gasenergy, take_log=False,
-          units=r"\rm{erg}/\rm{g}")
+          convert_function=_convertEnergy, units=r"\rm{erg}/\rm{g}")
 
 def _convertPressure(data) :
     return data.convert("Density")*data.convert("x-velocity")**2
@@ -144,15 +145,17 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]
     else:
-        return (data["total_energy"] -
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) -
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])*(data.pf["Gamma"]-1.0)
-add_field("Pressure", function=_pressure, take_log=False, convert_function=_convertPressure,
-          units=r"\rm{erg}/\rm{cm}^3", projected_units=r"\rm{erg}/\rm{cm}^2")
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint*(data.pf["Gamma"]-1.0)
+add_field("Pressure", function=_pressure, take_log=False,
+          convert_function=_convertPressure, units=r"\rm{erg}/\rm{cm}^3",
+          projected_units=r"\rm{erg}/\rm{cm}^2")
 
 def _temperature(field, data):
     if data.has_field_parameter("mu"):


https://bitbucket.org/yt_analysis/yt-3.0/commits/5c2cc712fed1/
Changeset:   5c2cc712fed1
Branch:      yt
User:        jzuhone
Date:        2013-07-26 19:03:21
Summary:     Fixing grid_right_edge for datasets with dimensionality less than 3.
Affected #:  1 file

diff -r 4b4597c8648ad49189012024b1782154d44ba195 -r 5c2cc712fed1bbfe423d7a0a9cbcbcc3dfe19da7 yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -309,6 +309,10 @@
         self.grid_left_edge = np.round(self.parameter_file.domain_left_edge + dx*glis, decimals=6)
         self.grid_dimensions = gdims.astype("int32")
         self.grid_right_edge = np.round(self.grid_left_edge + dx*self.grid_dimensions, decimals=6)
+        if self.parameter_file.dimensionality <= 2:
+            self.grid_right_edge[:,2] = self.parameter_file.domain_right_edge[2]
+        if self.parameter_file.dimensionality == 1:
+            self.grid_right_edge[:,1:] = self.parameter_file.domain_right_edge[1:]
         self.grid_particle_count = np.zeros([self.num_grids, 1], dtype='int64')
 
     def _populate_grid_objects(self):


https://bitbucket.org/yt_analysis/yt-3.0/commits/5b8b7fa01e98/
Changeset:   5b8b7fa01e98
Branch:      yt
User:        ngoldbaum
Date:        2013-07-30 03:56:05
Summary:     Turning off caching for athena and stream.  Closes #612.

Also fixing a mutable as default argument bug.
Affected #:  4 files

diff -r 5c2cc712fed1bbfe423d7a0a9cbcbcc3dfe19da7 -r 5b8b7fa01e981e2f56de57d988f0d03cabbcdc46 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -68,8 +68,9 @@
         if not os.path.exists(apath): raise IOError(filename)
         if apath not in _cached_pfs:
             obj = object.__new__(cls)
-            _cached_pfs[apath] = obj
-        return _cached_pfs[apath]
+            if obj._skip_cache is False:
+                _cached_pfs[apath] = obj
+        return obj
 
     def __init__(self, filename, data_style=None, file_style=None):
         """
@@ -137,6 +138,10 @@
     def _mrep(self):
         return MinimalStaticOutput(self)
 
+    @property
+    def _skip_cache(self):
+        return False
+
     def hub_upload(self):
         self._mrep.upload()
 

diff -r 5c2cc712fed1bbfe423d7a0a9cbcbcc3dfe19da7 -r 5b8b7fa01e981e2f56de57d988f0d03cabbcdc46 yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -339,7 +339,9 @@
     _data_style = "athena"
 
     def __init__(self, filename, data_style='athena',
-                 storage_filename=None, parameters={}):
+                 storage_filename=None, parameters=None):
+        if parameters is None:
+            parameters = {}
         self.specified_parameters = parameters
         StaticOutput.__init__(self, filename, data_style)
         self.filename = filename
@@ -471,6 +473,10 @@
             pass
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
     def __repr__(self):
         return self.basename.rsplit(".", 1)[0]
 

diff -r 5c2cc712fed1bbfe423d7a0a9cbcbcc3dfe19da7 -r 5b8b7fa01e981e2f56de57d988f0d03cabbcdc46 yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -339,6 +339,10 @@
     def _is_valid(cls, *args, **kwargs):
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
 class StreamDictFieldHandler(dict):
 
     @property

diff -r 5c2cc712fed1bbfe423d7a0a9cbcbcc3dfe19da7 -r 5b8b7fa01e981e2f56de57d988f0d03cabbcdc46 yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -67,7 +67,7 @@
     np.float64_t idds[3]
     int dims[3]
 
-ctypedef void sample_function(
+ctypedef void sample_function1(
                 VolumeContainer *vc,
                 np.float64_t v_pos[3],
                 np.float64_t v_dir[3],
@@ -235,7 +235,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function *sampler
+    cdef sample_function1 *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -929,7 +929,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function *sampler,
+                     sample_function1 *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:


https://bitbucket.org/yt_analysis/yt-3.0/commits/f86552af1439/
Changeset:   f86552af1439
Branch:      yt
User:        ngoldbaum
Date:        2013-07-30 04:04:14
Summary:     Accidentally checked in some irrelevant changes.
Affected #:  1 file

diff -r 5b8b7fa01e981e2f56de57d988f0d03cabbcdc46 -r f86552af1439224bc5598c71f063fa237a85a271 yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -67,7 +67,7 @@
     np.float64_t idds[3]
     int dims[3]
 
-ctypedef void sample_function1(
+ctypedef void sample_function(
                 VolumeContainer *vc,
                 np.float64_t v_pos[3],
                 np.float64_t v_dir[3],
@@ -235,7 +235,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function1 *sampler
+    cdef sample_function *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -929,7 +929,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function1 *sampler,
+                     sample_function *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:


https://bitbucket.org/yt_analysis/yt-3.0/commits/3bf3e6debda2/
Changeset:   3bf3e6debda2
Branch:      yt
User:        ngoldbaum
Date:        2013-07-30 09:09:00
Summary:     Fixing two errors in universal fields.
Affected #:  1 file

diff -r f86552af1439224bc5598c71f063fa237a85a271 -r 3bf3e6debda2772f6cd0026fe71b787a64f5ada9 yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -800,6 +800,8 @@
     if any(data.pf.periodicity):
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
+        if data.pf.dimensionality < i+1:
+            break
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
@@ -1013,7 +1015,8 @@
     units of Gauss. If you use MKS, make sure to write your own
     MagneticEnergy field to deal with non-unitary \mu_0.
     """
-    return (data["Bx"]**2 + data["By"]**2 + data["Bz"]**2)/(8*np.pi)
+    return data['CellVolume'] * \
+        (data["Bx"]**2 + data["By"]**2 + data["Bz"]**2)/(8*np.pi)
 add_field("MagneticEnergy",function=_MagneticEnergy,
           units=r"\rm{ergs}\/\rm{cm}^{-3}",
           display_name=r"\rm{Magnetic}\/\rm{Energy}")


https://bitbucket.org/yt_analysis/yt-3.0/commits/9095ffb28958/
Changeset:   9095ffb28958
Branch:      yt
User:        ngoldbaum
Date:        2013-07-30 17:47:26
Summary:     Backed out changeset 3bf3e6debda2
Affected #:  1 file

diff -r 3bf3e6debda2772f6cd0026fe71b787a64f5ada9 -r 9095ffb28958788842dcbe76bcf61070dab6df8d yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -800,8 +800,6 @@
     if any(data.pf.periodicity):
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
-        if data.pf.dimensionality < i+1:
-            break
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
@@ -1015,8 +1013,7 @@
     units of Gauss. If you use MKS, make sure to write your own
     MagneticEnergy field to deal with non-unitary \mu_0.
     """
-    return data['CellVolume'] * \
-        (data["Bx"]**2 + data["By"]**2 + data["Bz"]**2)/(8*np.pi)
+    return (data["Bx"]**2 + data["By"]**2 + data["Bz"]**2)/(8*np.pi)
 add_field("MagneticEnergy",function=_MagneticEnergy,
           units=r"\rm{ergs}\/\rm{cm}^{-3}",
           display_name=r"\rm{Magnetic}\/\rm{Energy}")


https://bitbucket.org/yt_analysis/yt-3.0/commits/3990dd43ecce/
Changeset:   3990dd43ecce
Branch:      yt
User:        ngoldbaum
Date:        2013-07-30 18:26:16
Summary:     Fixing Radius and ParticleRadius for reduced dimensionality datasets.
Affected #:  1 file

diff -r 9095ffb28958788842dcbe76bcf61070dab6df8d -r 3990dd43ecce97cb7a3e6a02ec87da260cd2e540 yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -801,6 +801,8 @@
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
+        if data.pf.dimensionality < i+1:
+            break
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
             np.subtract(r, DW[i], rdw)


https://bitbucket.org/yt_analysis/yt-3.0/commits/df46c35356ce/
Changeset:   df46c35356ce
Branch:      yt
User:        ngoldbaum
Date:        2013-07-23 23:46:51
Summary:     Turn data serialization off by default.
Affected #:  1 file

diff -r e3e4f4578504b7eb2e929275ad8441ef3900572c -r df46c35356ceff7107fe37a98f67e56e1fd32d99 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -28,7 +28,7 @@
 import ConfigParser, os, os.path, types
 
 ytcfgDefaults = dict(
-    serialize = 'True',
+    serialize = 'False',
     onlydeserialize = 'False',
     timefunctions = 'False',
     logfile = 'False',


https://bitbucket.org/yt_analysis/yt-3.0/commits/f936432ed45d/
Changeset:   f936432ed45d
Branch:      yt
User:        MatthewTurk
Date:        2013-07-30 19:08:24
Summary:     Merged in ngoldbaum/yt (pull request #558)

Turn data serialization off by default.
Affected #:  1 file

diff -r 3990dd43ecce97cb7a3e6a02ec87da260cd2e540 -r f936432ed45df5f59f1691ec56f64ee31bb85a46 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -28,7 +28,7 @@
 import ConfigParser, os, os.path, types
 
 ytcfgDefaults = dict(
-    serialize = 'True',
+    serialize = 'False',
     onlydeserialize = 'False',
     timefunctions = 'False',
     logfile = 'False',


https://bitbucket.org/yt_analysis/yt-3.0/commits/697fea292672/
Changeset:   697fea292672
Branch:      yt
User:        jzuhone
Date:        2013-08-07 21:40:59
Summary:     Bug fix for reading datasets that aren't conserved or primitive variables.
Affected #:  1 file

diff -r 5c2cc712fed1bbfe423d7a0a9cbcbcc3dfe19da7 -r 697fea2926724910a0de7cbd1910f00789db46c7 yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    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 "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:


https://bitbucket.org/yt_analysis/yt-3.0/commits/8bf918bc58e7/
Changeset:   8bf918bc58e7
Branch:      yt
User:        ngoldbaum
Date:        2013-08-08 00:39:13
Summary:     Merged in jzuhone/yt-athena (pull request #564)

Bug fix for reading datasets that aren't conserved or primitive variables.
Affected #:  1 file

diff -r f936432ed45df5f59f1691ec56f64ee31bb85a46 -r 8bf918bc58e76b48ea57073ecbcea1cb951dd617 yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    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 "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:


https://bitbucket.org/yt_analysis/yt-3.0/commits/b8fc059c3d6c/
Changeset:   b8fc059c3d6c
Branch:      yt
User:        ngoldbaum
Date:        2013-08-06 23:54:12
Summary:     Fixing an error that breaks source distributions.  Closes #620.
Affected #:  1 file

diff -r f936432ed45df5f59f1691ec56f64ee31bb85a46 -r b8fc059c3d6c20925944980dc7f74bb75e5ddaa1 yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -8,7 +8,7 @@
 def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
-    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config


https://bitbucket.org/yt_analysis/yt-3.0/commits/7807ae08ea91/
Changeset:   7807ae08ea91
Branch:      yt
User:        ngoldbaum
Date:        2013-08-07 09:46:51
Summary:     Adding missing empty __init__.py files.
Affected #:  5 files



https://bitbucket.org/yt_analysis/yt-3.0/commits/aac8c2b8ff0b/
Changeset:   aac8c2b8ff0b
Branch:      yt
User:        ngoldbaum
Date:        2013-08-07 18:36:13
Summary:     Need to include fortran kdtree sources in MANIFEST.in
Affected #:  1 file

diff -r 7807ae08ea91b29e9f71ae428f81354561be23f0 -r aac8c2b8ff0b537fda042bc908163312063f8aba MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include distribute_setup.py README* CREDITS FUNDING LICENSE.txt
 recursive-include yt/gui/reason/html *.html *.png *.ico *.js
 recursive-include yt *.pyx *.pxd *.hh *.h README*
+recursive-include yt/utilities/kdtree *.f90 *.v Makefile LICENSE
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt-3.0/commits/d33be33da703/
Changeset:   d33be33da703
Branch:      yt
User:        xarthisius
Date:        2013-08-08 09:27:13
Summary:     Merged in ngoldbaum/yt (pull request #563)

Fixing an error that breaks source distributions.  Closes #620.
Affected #:  7 files

diff -r 8bf918bc58e76b48ea57073ecbcea1cb951dd617 -r d33be33da703510aa9cf4e85da906bcf0ac61229 MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include distribute_setup.py README* CREDITS FUNDING LICENSE.txt
 recursive-include yt/gui/reason/html *.html *.png *.ico *.js
 recursive-include yt *.pyx *.pxd *.hh *.h README*
+recursive-include yt/utilities/kdtree *.f90 *.v Makefile LICENSE
\ No newline at end of file

diff -r 8bf918bc58e76b48ea57073ecbcea1cb951dd617 -r d33be33da703510aa9cf4e85da906bcf0ac61229 yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -8,7 +8,7 @@
 def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
-    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config


https://bitbucket.org/yt_analysis/yt-3.0/commits/6c210dc42c5b/
Changeset:   6c210dc42c5b
Branch:      yt
User:        ngoldbaum
Date:        2013-08-09 09:33:23
Summary:     Fixing an issue with load() that was causing the answer tests to behave incorrectly.
Affected #:  2 files

diff -r d33be33da703510aa9cf4e85da906bcf0ac61229 -r 6c210dc42c5b750d31235ddefbc6bb78c1183009 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -70,6 +70,8 @@
             obj = object.__new__(cls)
             if obj._skip_cache is False:
                 _cached_pfs[apath] = obj
+        else:
+            obj = _cached_pfs[apath]
         return obj
 
     def __init__(self, filename, data_style=None, file_style=None):

diff -r d33be33da703510aa9cf4e85da906bcf0ac61229 -r 6c210dc42c5b750d31235ddefbc6bb78c1183009 yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -270,7 +270,7 @@
     with temp_cwd(path):
         try:
             load(pf_fn)
-        except:
+        except YTOutputNotIdentified:
             return False
     return AnswerTestingTest.result_storage is not None
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/1740292423d4/
Changeset:   1740292423d4
Branch:      yt
User:        ngoldbaum
Date:        2013-08-11 04:54:47
Summary:     Fixing a misuse of ConfigParser in yt.run_nose()
Affected #:  1 file

diff -r d33be33da703510aa9cf4e85da906bcf0ac61229 -r 1740292423d4cf558981f52d1303287342c76a87 yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -96,7 +96,7 @@
     if answer_big_data:
         nose_argv.append('--answer-big-data')
     log_suppress = ytcfg.getboolean("yt","suppressStreamLogging")
-    ytcfg["yt","suppressStreamLogging"] = 'True'
+    ytcfg.set("yt","suppressStreamLogging", 'True')
     initial_dir = os.getcwd()
     yt_file = os.path.abspath(__file__)
     yt_dir = os.path.dirname(yt_file)
@@ -105,4 +105,4 @@
         nose.run(argv=nose_argv)
     finally:
         os.chdir(initial_dir)
-        ytcfg["yt","suppressStreamLogging"] = log_suppress
+        ytcfg.set("yt","suppressStreamLogging", str(log_suppress))


https://bitbucket.org/yt_analysis/yt-3.0/commits/43730c73a2de/
Changeset:   43730c73a2de
Branch:      yt
User:        MatthewTurk
Date:        2013-08-14 14:46:31
Summary:     Merged in ngoldbaum/yt (pull request #567)

Fixing a misuse of ConfigParser in yt.run_nose()
Affected #:  1 file

diff -r 6c210dc42c5b750d31235ddefbc6bb78c1183009 -r 43730c73a2de006b6412380da341761d510c5646 yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -96,7 +96,7 @@
     if answer_big_data:
         nose_argv.append('--answer-big-data')
     log_suppress = ytcfg.getboolean("yt","suppressStreamLogging")
-    ytcfg["yt","suppressStreamLogging"] = 'True'
+    ytcfg.set("yt","suppressStreamLogging", 'True')
     initial_dir = os.getcwd()
     yt_file = os.path.abspath(__file__)
     yt_dir = os.path.dirname(yt_file)
@@ -105,4 +105,4 @@
         nose.run(argv=nose_argv)
     finally:
         os.chdir(initial_dir)
-        ytcfg["yt","suppressStreamLogging"] = log_suppress
+        ytcfg.set("yt","suppressStreamLogging", str(log_suppress))


https://bitbucket.org/yt_analysis/yt-3.0/commits/82d8da3063aa/
Changeset:   82d8da3063aa
Branch:      yt
User:        samskillman
Date:        2013-08-05 23:16:56
Summary:     Better error handling when the user is attempting to use parallelism without
mpi4py installed.
Affected #:  1 file

diff -r f936432ed45df5f59f1691ec56f64ee31bb85a46 -r 82d8da3063aa4afb60e70068e98ced72a99bca23 yt/startup_tasks.py
--- a/yt/startup_tasks.py
+++ b/yt/startup_tasks.py
@@ -36,9 +36,11 @@
 def turn_on_parallelism():
     try:
         from mpi4py import MPI
-        parallel_capable = (MPI.COMM_WORLD.size > 1)
-    except ImportError:
-        parallel_capable = False
+    except ImportError as e:
+        mylog.error("Warning: Attempting to turn on parallelism, " +
+                    "but mpi4py import failed. Try pip install mpi4py.")
+        raise e
+    parallel_capable = (MPI.COMM_WORLD.size > 1)
     if parallel_capable:
         mylog.info("Global parallel computation enabled: %s / %s",
                    MPI.COMM_WORLD.rank, MPI.COMM_WORLD.size)


https://bitbucket.org/yt_analysis/yt-3.0/commits/d4505b36d9ce/
Changeset:   d4505b36d9ce
Branch:      yt
User:        MatthewTurk
Date:        2013-08-14 14:47:01
Summary:     Merged in samskillman/yt (pull request #562)

Better parallelism error handling
Affected #:  1 file

diff -r 43730c73a2de006b6412380da341761d510c5646 -r d4505b36d9ce03074b8a4a7df32b639268936a86 yt/startup_tasks.py
--- a/yt/startup_tasks.py
+++ b/yt/startup_tasks.py
@@ -36,9 +36,11 @@
 def turn_on_parallelism():
     try:
         from mpi4py import MPI
-        parallel_capable = (MPI.COMM_WORLD.size > 1)
-    except ImportError:
-        parallel_capable = False
+    except ImportError as e:
+        mylog.error("Warning: Attempting to turn on parallelism, " +
+                    "but mpi4py import failed. Try pip install mpi4py.")
+        raise e
+    parallel_capable = (MPI.COMM_WORLD.size > 1)
     if parallel_capable:
         mylog.info("Global parallel computation enabled: %s / %s",
                    MPI.COMM_WORLD.rank, MPI.COMM_WORLD.size)


https://bitbucket.org/yt_analysis/yt-3.0/commits/c8e7045e0f14/
Changeset:   c8e7045e0f14
Branch:      yt
User:        samskillman
Date:        2013-08-14 00:59:04
Summary:     Changing sample_function to sampler_function to avoid strange behavoir seen
in issue #501.  While that issue was later deemed invalid because it can be
avoided by keeping yt-2.x and yt-3.0 repos in different directories, this will
save headaches.
Affected #:  1 file

diff -r 6c210dc42c5b750d31235ddefbc6bb78c1183009 -r c8e7045e0f1452e6926819eb5de02960ee8034ab yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -67,7 +67,7 @@
     np.float64_t idds[3]
     int dims[3]
 
-ctypedef void sample_function(
+ctypedef void sampler_function(
                 VolumeContainer *vc,
                 np.float64_t v_pos[3],
                 np.float64_t v_dir[3],
@@ -235,7 +235,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function *sampler
+    cdef sampler_function *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -929,7 +929,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function *sampler,
+                     sampler_function *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:


https://bitbucket.org/yt_analysis/yt-3.0/commits/b4963f863671/
Changeset:   b4963f863671
Branch:      yt
User:        MatthewTurk
Date:        2013-08-14 15:27:21
Summary:     Merged in samskillman/yt (pull request #569)

Changing sample_function to sampler_function to avoid strange behavoir
Affected #:  1 file

diff -r d4505b36d9ce03074b8a4a7df32b639268936a86 -r b4963f863671c0b7f5aeb63eff3b857491b28e78 yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -67,7 +67,7 @@
     np.float64_t idds[3]
     int dims[3]
 
-ctypedef void sample_function(
+ctypedef void sampler_function(
                 VolumeContainer *vc,
                 np.float64_t v_pos[3],
                 np.float64_t v_dir[3],
@@ -235,7 +235,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function *sampler
+    cdef sampler_function *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -929,7 +929,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function *sampler,
+                     sampler_function *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:


https://bitbucket.org/yt_analysis/yt-3.0/commits/3e995dc1cd34/
Changeset:   3e995dc1cd34
Branch:      yt
User:        ngoldbaum
Date:        2013-08-12 06:40:25
Summary:     Trying to use _repr_png_ without overriding __repr__
Affected #:  2 files

diff -r d33be33da703510aa9cf4e85da906bcf0ac61229 -r 3e995dc1cd340e536e5ba800b3fedf418a8cb682 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -96,3 +96,10 @@
                                       norm=norm, vmin=self.zmin, aspect=aspect,
                                       vmax=self.zmax, cmap=cmap)
         self.cb = self.figure.colorbar(self.image, self.cax)
+
+    def _repr_png_(self):
+        canvas = FigureCanvasAgg(self.figure)
+        f = cStringIO.StringIO()
+        canvas.print_figure(f)
+        f.seek(0)
+        return f.read()

diff -r d33be33da703510aa9cf4e85da906bcf0ac61229 -r 3e995dc1cd340e536e5ba800b3fedf418a8cb682 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1135,11 +1135,6 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
-    def __repr__(self):
-        if "__IPYTHON__" in dir(__builtin__):
-            self.show()
-        return super(PWViewerMPL, self).__repr__()
-
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/6045463f3239/
Changeset:   6045463f3239
Branch:      yt
User:        ngoldbaum
Date:        2013-08-12 07:21:41
Summary:     Using _repr_html() to display a list of images.
Affected #:  2 files

diff -r 3e995dc1cd340e536e5ba800b3fedf418a8cb682 -r 6045463f32397dcfe7eec028e6c62ce60d7ab3ef yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -23,6 +23,7 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 import matplotlib
+import cStringIO
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \

diff -r 3e995dc1cd340e536e5ba800b3fedf418a8cb682 -r 6045463f32397dcfe7eec028e6c62ce60d7ab3ef yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1135,6 +1135,15 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        ret = ''
+        for field in self.plots:
+            img = base64.b64encode(self.plots[field]._repr_png_())
+            ret += '<img src="data:image/png;base64,%s"><br>' % img
+        return ret
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/74f8e7bd76d7/
Changeset:   74f8e7bd76d7
Branch:      yt
User:        ngoldbaum
Date:        2013-08-12 19:33:07
Summary:     Merging with my plotting PR.
Affected #:  2 files

diff -r 6c210dc42c5b750d31235ddefbc6bb78c1183009 -r 74f8e7bd76d73269551a56490d416b20029d43a6 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -23,6 +23,7 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 import matplotlib
+import cStringIO
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
@@ -96,3 +97,10 @@
                                       norm=norm, vmin=self.zmin, aspect=aspect,
                                       vmax=self.zmax, cmap=cmap)
         self.cb = self.figure.colorbar(self.image, self.cax)
+
+    def _repr_png_(self):
+        canvas = FigureCanvasAgg(self.figure)
+        f = cStringIO.StringIO()
+        canvas.print_figure(f)
+        f.seek(0)
+        return f.read()

diff -r 6c210dc42c5b750d31235ddefbc6bb78c1183009 -r 74f8e7bd76d73269551a56490d416b20029d43a6 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1135,10 +1135,14 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
-    def __repr__(self):
-        if "__IPYTHON__" in dir(__builtin__):
-            self.show()
-        return super(PWViewerMPL, self).__repr__()
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        ret = ''
+        for field in self.plots:
+            img = base64.b64encode(self.plots[field]._repr_png_())
+            ret += '<img src="data:image/png;base64,%s"><br>' % img
+        return ret
 
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file


https://bitbucket.org/yt_analysis/yt-3.0/commits/2464e8f034b1/
Changeset:   2464e8f034b1
Branch:      yt
User:        ngoldbaum
Date:        2013-08-12 20:28:01
Summary:     Fixing PlotWindow.show() to work correctly with IPython 1.0.
Affected #:  2 files

diff -r 74f8e7bd76d73269551a56490d416b20029d43a6 -r 2464e8f034b1b1165e0943f4758603a7a05d057f yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -250,6 +250,17 @@
      %(filename)s:%(lineno)s
 """
 
+def get_ipython_api_version():
+    import IPython
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
+        api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
+    else:
+        api_version = '1.0'
+
+    return api_version
+
 def insert_ipython(num_up=1):
     """
     Placed inside a function, this will insert an IPython interpreter at that
@@ -259,13 +270,7 @@
     defaults to 1 so that this function itself is stripped off.
     """
 
-    import IPython
-    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
-        api_version = '0.10'
-    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
-        api_version = '0.11'
-    else:
-        api_version = '1.0'
+    api_version = get_ipython_api_version()
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]

diff -r 74f8e7bd76d73269551a56490d416b20029d43a6 -r 2464e8f034b1b1165e0943f4758603a7a05d057f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -52,7 +52,7 @@
 from yt.utilities.delaunay.triangulate import Triangulation as triang
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
-    fix_axis, get_image_suffix
+    fix_axis, get_image_suffix, get_ipython_api_version
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
     x_dict, y_dict, \
@@ -1123,7 +1123,11 @@
 
         """
         if "__IPYTHON__" in dir(__builtin__):
-            self._send_zmq()
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                return self
         else:
             raise YTNotInsideNotebook
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/ed0606519b9e/
Changeset:   ed0606519b9e
Branch:      yt
User:        MatthewTurk
Date:        2013-08-14 15:39:59
Summary:     Merged in ngoldbaum/yt (pull request #568)

Formatting plots for the notebook in a display independent manner
Affected #:  3 files

diff -r b4963f863671c0b7f5aeb63eff3b857491b28e78 -r ed0606519b9e3ba18ccf5724517f2785860c68ea yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -250,6 +250,17 @@
      %(filename)s:%(lineno)s
 """
 
+def get_ipython_api_version():
+    import IPython
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
+        api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
+    else:
+        api_version = '1.0'
+
+    return api_version
+
 def insert_ipython(num_up=1):
     """
     Placed inside a function, this will insert an IPython interpreter at that
@@ -259,13 +270,7 @@
     defaults to 1 so that this function itself is stripped off.
     """
 
-    import IPython
-    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
-        api_version = '0.10'
-    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
-        api_version = '0.11'
-    else:
-        api_version = '1.0'
+    api_version = get_ipython_api_version()
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]

diff -r b4963f863671c0b7f5aeb63eff3b857491b28e78 -r ed0606519b9e3ba18ccf5724517f2785860c68ea yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -23,6 +23,7 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 import matplotlib
+import cStringIO
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
@@ -96,3 +97,10 @@
                                       norm=norm, vmin=self.zmin, aspect=aspect,
                                       vmax=self.zmax, cmap=cmap)
         self.cb = self.figure.colorbar(self.image, self.cax)
+
+    def _repr_png_(self):
+        canvas = FigureCanvasAgg(self.figure)
+        f = cStringIO.StringIO()
+        canvas.print_figure(f)
+        f.seek(0)
+        return f.read()

diff -r b4963f863671c0b7f5aeb63eff3b857491b28e78 -r ed0606519b9e3ba18ccf5724517f2785860c68ea yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -52,7 +52,7 @@
 from yt.utilities.delaunay.triangulate import Triangulation as triang
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
-    fix_axis, get_image_suffix
+    fix_axis, get_image_suffix, get_ipython_api_version
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
     x_dict, y_dict, \
@@ -1123,7 +1123,11 @@
 
         """
         if "__IPYTHON__" in dir(__builtin__):
-            self._send_zmq()
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                return self
         else:
             raise YTNotInsideNotebook
 
@@ -1135,10 +1139,14 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
-    def __repr__(self):
-        if "__IPYTHON__" in dir(__builtin__):
-            self.show()
-        return super(PWViewerMPL, self).__repr__()
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        ret = ''
+        for field in self.plots:
+            img = base64.b64encode(self.plots[field]._repr_png_())
+            ret += '<img src="data:image/png;base64,%s"><br>' % img
+        return ret
 
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file


https://bitbucket.org/yt_analysis/yt-3.0/commits/02fe877276dc/
Changeset:   02fe877276dc
Branch:      yt
User:        hegan
Date:        2013-07-23 20:37:21
Summary:     Added fit
Affected #:  2 files

diff -r f15815e182080e8619efd2636cce42bc6e598b7c -r 02fe877276dc48a3d0caa54a3caf957fd735db86 yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
--- /dev/null
+++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
@@ -0,0 +1,808 @@
+from scipy import optimize
+import numpy as na
+import h5py
+from yt.analysis_modules.absorption_spectrum.absorption_line \
+        import voigt
+
+
+def generate_total_fit(x, fluxData, orderFits, speciesDicts, 
+        minError=1E-5, complexLim=.999,
+        fitLim=.99, minLength=3, 
+        maxLength=1000, splitLim=.99,
+        output_file=None):
+
+    """
+    This function is designed to fit an absorption spectrum by breaking 
+    the spectrum up into absorption complexes, and iteratively adding
+    and optimizing voigt profiles to each complex.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        1d array of wavelengths
+    fluxData : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    orderFits : list
+        list of the names of the species in the order that they 
+        should be fit. Names should correspond to the names of the species
+        given in speciesDicts. (ex: ['lya','OVI'])
+    speciesDicts : dictionary
+        Dictionary of dictionaries (I'm addicted to dictionaries, I
+        confess). Top level keys should be the names of all the species given
+        in orderFits. The entries should be dictionaries containing all 
+        relevant parameters needed to create an absorption line of a given 
+        species (f,Gamma,lambda0) as well as max and min values for parameters
+        to be fit
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+    output_file : string, optional
+        location to save the results of the fit. 
+
+    Returns
+    -------
+    allSpeciesLines : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. (ie: N[0],b[0],z[0] will create a line that
+        fits some part of the absorption spectrum). 'group#' is a similar list
+        but identifies which absorbing complex each line belongs to. Lines
+        with the same group# were fit at the same time. group#'s do not
+        correlate between species (ie: an lya line with group number 1 and
+        an OVI line with group number 1 were not fit together and do
+        not necessarily correspond to the same region)
+    yFit : (N) ndarray
+        array of flux corresponding to the combination of all fitted
+        absorption profiles. Same size as x.
+    """
+
+    #Empty dictionary for fitted lines
+    allSpeciesLines = {}
+
+    #Wavelength of beginning of array, wavelength resolution
+    x0,xRes=x[0],x[1]-x[0]
+
+    #Empty fit without any lines
+    yFit = na.ones(len(fluxData))
+
+    #Find all regions where lines/groups of lines are present
+    cBounds = _find_complexes(x, fluxData, fitLim=fitLim,
+            complexLim=complexLim, minLength=minLength,
+            maxLength=maxLength, splitLim=splitLim)
+
+    #Fit all species one at a time in given order from low to high wavelength
+    for species in orderFits:
+        speciesDict = speciesDicts[species]
+        speciesLines = {'N':na.array([]),
+                        'b':na.array([]),
+                        'z':na.array([]),
+                        'group#':na.array([])}
+
+        #Set up wavelengths for species
+        initWl = speciesDict['wavelength'][0]
+
+        for b_i,b in enumerate(cBounds):
+            xBounded=x[b[1]:b[2]]
+            yDatBounded=fluxData[b[1]:b[2]]
+            yFitBounded=yFit[b[1]:b[2]]
+
+            #Find init redshift
+            z=(xBounded[yDatBounded.argmin()]-initWl)/initWl
+
+            #Check if any flux at partner sites
+            if not _line_exists(speciesDict['wavelength'],
+                    fluxData,z,x0,xRes,fitLim): 
+                continue 
+
+            #Fit Using complex tools
+            newLinesP,flag=_complex_fit(xBounded,yDatBounded,yFitBounded,
+                    z,fitLim,minError*(b[2]-b[1]),speciesDict)
+
+            #Check existence of partner lines if applicable
+            newLinesP = _remove_unaccepted_partners(newLinesP, x, fluxData, 
+                    b, minError*(b[2]-b[1]),
+                    x0, xRes, speciesDict)
+
+            #If flagged as a bad fit, species is lyman alpha,
+            #   and it may be a saturated line, use special tools
+            if flag and species=='lya' and min(yDatBounded)<.1:
+                newLinesP=_large_flag_fit(xBounded,yDatBounded,
+                        yFitBounded,z,speciesDict,
+                        minSize,minError*(b[2]-b[1]))
+
+            #Adjust total current fit
+            yFit=yFit*_gen_flux_lines(x,newLinesP,speciesDict)
+
+            #Add new group to all fitted lines
+            if na.size(newLinesP)>0:
+                speciesLines['N']=na.append(speciesLines['N'],newLinesP[:,0])
+                speciesLines['b']=na.append(speciesLines['b'],newLinesP[:,1])
+                speciesLines['z']=na.append(speciesLines['z'],newLinesP[:,2])
+                speciesLines['group#']=na.append(speciesLines['group#'],b_i)
+
+        allSpeciesLines[species]=speciesLines
+
+    if output_file:
+        _output_fit(allSpeciesLines, output_file)
+
+    return (allSpeciesLines,yFit)
+
+def _complex_fit(x, yDat, yFit, initz, minSize, errBound, speciesDict, 
+        initP=None):
+    """ Fit an absorption complex by iteratively adding and optimizing
+    voigt profiles.
+    
+    A complex is defined as a region where some number of lines may be present,
+    or a region of non zero of absorption. Lines are iteratively added
+    and optimized until the difference between the flux generated using
+    the optimized parameters has a least squares difference between the 
+    desired flux profile less than the error bound.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    initP : (,3,) ndarray
+        initial guess to try for line parameters to fit the region. Used
+        by large_flag_fit. Default = None, and initial guess generated
+        automatically.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        Array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]
+    flag : bool
+        boolean value indicating the success of the fit (True if unsuccessful)
+    """
+
+    #Setup initial line guesses
+    if initP==None: #Regular fit
+        initP = [0,0,0] 
+        if min(yDat)<.5: #Large lines get larger initial guess 
+            initP[0] = 10**16
+        elif min(yDat)>.9: #Small lines get smaller initial guess
+            initP[0] = 10**12.5
+        else:
+            initP[0] = speciesDict['init_N']
+        initP[1] = speciesDict['init_b']
+        initP[2]=initz
+        initP=na.array([initP])
+
+    linesP = initP
+
+    #For generating new z guesses
+    wl0 = speciesDict['wavelength'][0]
+
+    #Check if first line exists still
+    if min(yDat-yFit+1)>minSize: 
+        return [],False
+    
+    #Values to proceed through first run
+    errSq,prevErrSq=1,1000
+
+    while True:
+        #Initial parameter guess from joining parameters from all lines
+        #   in lines into a single array
+        initP = linesP.flatten()
+
+        #Optimize line
+        fitP,success=optimize.leastsq(_voigt_error,initP,
+                args=(x,yDat,yFit,speciesDict),
+                epsfcn=1E-10,maxfev=1000)
+
+        #Set results of optimization
+        linesP = na.reshape(fitP,(-1,3))
+
+        #Generate difference between current best fit and data
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+
+        #Sum to get idea of goodness of fit
+        errSq=sum(dif**2)
+
+        #If good enough, break
+        if errSq < errBound: 
+            break
+
+        #If last fit was worse, reject the last line and revert to last fit
+        if errSq > prevErrSq*10:
+            #If its still pretty damn bad, cut losses and try flag fit tools
+            if prevErrSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                yNewFit=_gen_flux_lines(x,prevLinesP,speciesDict)
+                break
+
+        #If too many lines 
+        if na.shape(linesP)[0]>8 or na.size(linesP)+3>=len(x):
+            #If its fitable by flag tools and still bad, use flag tools
+            if errSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                break 
+
+        #Store previous data in case reject next fit
+        prevErrSq = errSq
+        prevLinesP = linesP
+
+
+        #Set up initial condition for new line
+        newP = [0,0,0] 
+        if min(dif)<.1:
+            newP[0]=10**12
+        elif min(dif)>.9:
+            newP[0]=10**16
+        else:
+            newP[0]=10**14
+        newP[1] = speciesDict['init_b']
+        newP[2]=(x[dif.argmax()]-wl0)/wl0
+        linesP=na.append(linesP,[newP],axis=0)
+
+
+    #Check the parameters of all lines to see if they fall in an
+    #   acceptable range, as given in dict ref
+    remove=[]
+    for i,p in enumerate(linesP):
+        check=_check_params(na.array([p]),speciesDict)
+        if check: 
+            remove.append(i)
+    linesP = na.delete(linesP,remove,axis=0)
+
+    return linesP,False
+
+def _large_flag_fit(x, yDat, yFit, initz, speciesDict, minSize, errBound):
+    """
+    Attempts to more robustly fit saturated lyman alpha regions that have
+    not converged to satisfactory fits using the standard tools.
+
+    Uses a preselected sample of a wide range of initial parameter guesses
+    designed to fit saturated lines (see get_test_lines).
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+
+    Returns
+    -------
+    bestP : (3,) ndarray
+        array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]  
+    """
+
+    #Set up some initial line guesses
+    lineTests = _get_test_lines(initz)
+
+    #Keep track of the lowest achieved error
+    bestError = 1000 
+
+    #Iterate through test line guesses
+    for initLines in lineTests:
+        if initLines[1,0]==0:
+            initLines = na.delete(initLines,1,axis=0)
+
+        #Do fitting with initLines as first guess
+        linesP,flag=_complex_fit(x,yDat,yFit,initz,
+                minSize,errBound,speciesDict,initP=initLines)
+
+        #Find error of last fit
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+        errSq=sum(dif**2)
+
+        #If error lower, keep track of the lines used to make that fit
+        if errSq < bestError:
+            bestError = errSq
+            bestP = linesP
+
+    if bestError>10*errBound*len(x): 
+        return []
+    else:
+        return bestP
+
+def _get_test_lines(initz):
+    """
+    Returns a 3d numpy array of lines to test as initial guesses for difficult
+    to fit lyman alpha absorbers that are saturated. 
+    
+    The array is 3d because
+    the first dimension gives separate initial guesses, the second dimension
+    has multiple lines for the same guess (trying a broad line plus a 
+    saturated line) and the 3d dimension contains the 3 fit parameters (N,b,z)
+
+    Parameters
+    ----------
+    initz : float
+        redshift to give all the test lines
+
+    Returns
+    -------
+    testP : (,3,) ndarray
+        numpy array of the form 
+        [[[N1a,b1a,z1a], [N1b,b1b,z1b]], [[N2a,b2,z2a],...] ...]
+    """
+
+    #Set up a bunch of empty lines
+    testP = na.zeros((10,2,3))
+
+    testP[0,0,:]=[1E18,20,initz]
+    testP[1,0,:]=[1E18,40,initz]
+    testP[2,0,:]=[1E16,5, initz]
+    testP[3,0,:]=[1E16,20,initz]
+    testP[4,0,:]=[1E16,80,initz]
+
+    testP[5,0,:]=[1E18,20,initz]
+    testP[6,0,:]=[1E18,40,initz]
+    testP[7,0,:]=[1E16,5, initz]
+    testP[8,0,:]=[1E16,20,initz]
+    testP[9,0,:]=[1E16,80,initz]
+
+    testP[5,1,:]=[1E13,100,initz]
+    testP[6,1,:]=[1E13,100,initz]
+    testP[7,1,:]=[1E13,100,initz]
+    testP[8,1,:]=[1E13,100,initz]
+    testP[9,1,:]=[1E13,100,initz]
+
+    return testP
+
+def _get_bounds(z, b, wl, x0, xRes):
+    """ 
+    Gets the indices of range of wavelength that the wavelength wl is in 
+    with the size of some initial wavelength range.
+
+    Used for checking if species with multiple lines (as in the OVI doublet)
+    fit all lines appropriately.
+
+    Parameters
+    ----------
+    z : float
+        redshift
+    b : (3) ndarray/list
+        initial bounds in form [i0,i1,i2] where i0 is the index of the 
+        minimum flux for the complex, i1 is index of the lower wavelength 
+        edge of the complex, and i2 is the index of the higher wavelength
+        edge of the complex.
+    wl : float
+        unredshifted wavelength of the peak of the new region 
+    x0 : float
+        wavelength of the index 0
+    xRes : float
+        difference in wavelength for two consecutive indices
+    
+    Returns
+    -------
+    indices : (2) tuple
+        Tuple (i1,i2) where i1 is the index of the lower wavelength bound of 
+        the new region and i2 is the index of the higher wavelength bound of
+        the new region
+    """
+
+    r=[-b[1]+100+b[0],b[2]+100-b[0]]
+    redWl = (z+1)*wl
+    iRedWl=int((redWl-x0)/xRes)
+    indices = (iRedWl-r[0],iRedWl+r[1])
+
+    return indices
+
+def _remove_unaccepted_partners(linesP, x, y, b, errBound, 
+        x0, xRes, speciesDict):
+    """
+    Given a set of parameters [N,b,z] that form multiple lines for a given
+    species (as in the OVI doublet), remove any set of parameters where
+    not all transition wavelengths have a line that matches the fit.
+
+    (ex: if a fit is determined based on the first line of the OVI doublet,
+    but the given parameters give a bad fit of the wavelength space of
+    the second line then that set of parameters is removed from the array
+    of line parameters.)
+
+    Parameters
+    ----------
+    linesP : (3,) ndarray
+        array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    x : (N) ndarray
+        wavelength array [nm]
+    y : (N) ndarray
+        normalized flux array of original data
+    b : (3) tuple/list/ndarray
+        indices that give the bounds of the original region so that another 
+        region of similar size can be used to determine the goodness
+        of fit of the other wavelengths
+    errBound : float
+        size of the error that is appropriate for a given region, 
+        adjusted to account for the size of the region.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        array similar to linesP that only contains lines with
+        appropriate fits of all transition wavelengths.
+    """
+
+    #List of lines to remove
+    removeLines=[]
+
+    #Iterate through all sets of line parameters
+    for i,p in enumerate(linesP):
+
+        #iterate over all transition wavelengths
+        for wl in speciesDict['wavelength']:
+
+            #Get the bounds of a similar sized region around the
+            #   appropriate wavelength, and then get the appropriate
+            #   region of wavelength and flux
+            lb = _get_bounds(p[2],b,wl,x0,xRes)
+            xb,yb=x[lb[0]:lb[1]],y[lb[0]:lb[1]]
+
+            #Generate a fit and find the difference to data
+            yFitb=_gen_flux_lines(xb,na.array([p]),speciesDict)
+            dif =yb-yFitb
+
+            #Only counts as an error if line is too big ---------------<
+            dif = [k for k in dif if k>0]
+            err = sum(dif)
+
+            #If the fit is too bad then add the line to list of removed lines
+            if err > errBound*1E2:
+                removeLines.append(i)
+                break
+
+    #Remove all bad line fits
+    linesP = na.delete(linesP,removeLines,axis=0)
+
+    return linesP 
+
+
+
+def _line_exists(wavelengths, y, z, x0, xRes,fluxMin):
+    """For a group of lines finds if the there is some change in flux greater
+    than some minimum at the same redshift with different initial wavelengths
+
+    Parameters
+    ----------
+    wavelengths : (N) ndarray
+        array of initial wavelengths to check
+    y : (N) ndarray
+        flux array to check
+    x0 : float
+        wavelength of the first value in y
+    xRes : float
+        difference in wavelength between consecutive cells in flux array
+    fluxMin : float
+        maximum flux to count as a line existing. 
+
+    Returns
+    -------
+
+    flag : boolean 
+        value indicating whether all lines exist. True if all lines exist
+    """
+
+    #Iterate through initial wavelengths
+    for wl in wavelengths:
+        #Redshifted wavelength
+        redWl = (z+1)*wl
+
+        #Index of the redshifted wavelength
+        indexRedWl = (redWl-x0)/xRes
+
+        #Check if surpasses minimum absorption bound
+        if y[int(indexRedWl)]>fluxMin:
+            return False
+
+    return True
+
+def _find_complexes(x, yDat, complexLim=.999, fitLim=.99,
+        minLength =3, maxLength=1000, splitLim=.99):
+    """Breaks up the wavelength space into groups
+    where there is some absorption. 
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelengths
+    yDat : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+
+    Returns
+    -------
+    cBounds : (3,) 
+        list of bounds in the form [[i0,i1,i2],...] where i0 is the 
+        index of the maximum flux for a complex, i1 is the index of the
+        beginning of the complex, and i2 is the index of the end of the 
+        complex. Indexes refer to the indices of x and yDat.
+    """
+
+    #Initialize empty list of bounds
+    cBounds=[]
+
+    #Iterate through cells of flux
+    i=0
+    while (i<len(x)):
+
+        #Start tracking at a region that surpasses flux of edge
+        if yDat[i]<complexLim:
+
+            #Iterate through until reach next edge
+            j=0
+            while yDat[i+j]<complexLim: j=j+1
+
+            #Check if the complex is big enough
+            if j >minLength:
+
+                #Check if there is enough absorption for the complex to
+                #   be included
+                cPeak = yDat[i:i+j].argmin()
+                if yDat[cPeak+i]<fitLim:
+                    cBounds.append([cPeak+i,i,i+j])
+
+            i=i+j
+        i=i+1
+
+    i=0
+    #Iterate through the bounds
+    while i < len(cBounds):
+        b=cBounds[i]
+
+        #Check if the region needs to be divided
+        if b[2]-b[1]>maxLength:
+
+            #Find the minimum absorption in the middle two quartiles of
+            #   the large complex
+            q=(b[2]-b[1])/4
+            cut = yDat[b[1]+q:b[2]-q].argmax()+b[1]+q
+
+            #Only break it up if the minimum absorption is actually low enough
+            if yDat[cut]>splitLim:
+
+                #Get the new two peaks
+                b1Peak = yDat[b[1]:cut].argmin()+b[1]
+                b2Peak = yDat[cut:b[2]].argmin()+cut
+
+                #add the two regions separately
+                cBounds.insert(i+1,[b1Peak,b[1],cut])
+                cBounds.insert(i+2,[b2Peak,cut,b[2]])
+
+                #Remove the original region
+                cBounds.pop(i)
+                i=i+1
+        i=i+1
+
+    return cBounds
+
+def _gen_flux_lines(x, linesP, speciesDict):
+    """
+    Calculates the normalized flux for a region of wavelength space
+    generated by a set of absorption lines.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        Array of wavelength
+    linesP: (3,) ndarray
+        Array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    speciesDict : dictionary
+        Dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+
+    Returns
+    -------
+    flux : (N) ndarray
+        Array of normalized flux generated by the line parameters
+        given in linesP over the wavelength space given in x. Same size as x.
+    """
+    y=0
+    for p in linesP:
+        for i in range(speciesDict['numLines']):
+            f=speciesDict['f'][i]
+            g=speciesDict['Gamma'][i]
+            wl=speciesDict['wavelength'][i]
+            y = y+ _gen_tau(x,p,f,g,wl)
+    flux = na.exp(-y)
+    return flux
+
+def _gen_tau(t, p, f, Gamma, lambda_unshifted):
+    """This calculates a flux distribution for given parameters using the yt
+    voigt profile generator"""
+    N,b,z= p
+    
+    #Calculating quantities
+    tau_o = 1.4973614E-15*N*f*lambda_unshifted/b
+    a=7.95774715459E-15*Gamma*lambda_unshifted/b
+    x=299792.458/b*(lambda_unshifted*(1+z)/t-1)
+    
+    H = na.zeros(len(x))
+    H = voigt(a,x)
+    
+    tau = tau_o*H
+
+    return tau
+
+def _voigt_error(pTotal, x, yDat, yFit, speciesDict):
+    """
+    Gives the error of each point  used to optimize the fit of a group
+        of absorption lines to a given flux profile.
+
+        If the parameters are not in the acceptable range as defined
+        in speciesDict, the first value of the error array will
+        contain a large value (999), to prevent the optimizer from running
+        into negative number problems.
+
+    Parameters
+    ----------
+    pTotal : (3,) ndarray 
+        Array with form [[N1, b1, z1], ...] 
+    x : (N) ndarray
+        array of wavelengths [nm]
+    yDat : (N) ndarray
+        desired normalized flux from fits of lines in wavelength
+        space given by x
+    yFit : (N) ndarray
+        previous fit over the wavelength space given by x.
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+
+    Returns
+    -------
+    error : (N) ndarray
+        the difference between the fit generated by the parameters
+        given in pTotal multiplied by the previous fit and the desired
+        flux profile, w/ first index modified appropriately for bad 
+        parameter choices
+    """
+
+    pTotal.shape = (-1,3)
+    yNewFit = _gen_flux_lines(x,pTotal,speciesDict)
+
+    error = yDat-yFit*yNewFit
+    error[0] = _check_params(pTotal,speciesDict)
+
+    return error
+
+def _check_params(p, speciesDict):
+    """
+    Check to see if any of the parameters in p fall outside the range 
+        given in speciesDict.
+
+    Parameters
+    ----------
+    p : (3,) ndarray
+        array with form [[N1, b1, z1], ...] 
+    speciesDict : dictionary
+        dictionary with properties giving the max and min
+        values appropriate for each parameter N,b, and z.
+
+    Returns
+    -------
+    check : int
+        0 if all values are fine
+        999 if any values fall outside acceptable range
+    """
+    check = 0
+    if any(p[:,0] > speciesDict['maxN']) or\
+          any(p[:,0] < speciesDict['minN']) or\
+          any(p[:,1] > speciesDict['maxb']) or\
+          any(p[:,1] < speciesDict['minb']) or\
+          any(p[:,2] > speciesDict['maxz']) or\
+          any(p[:,2] < speciesDict['minz']):
+              check = 999
+    return check
+
+
+def _output_fit(lineDic, file_name = 'spectrum_fit.h5'):
+    """
+    This function is designed to output the parameters of the series
+    of lines used to fit an absorption spectrum. 
+
+    The dataset contains entries in the form species/N, species/b
+    species/z, and species/complex. The ith entry in each of the datasets
+    is the fitted parameter for the ith line fitted to the spectrum for
+    the given species. The species names come from the fitted line
+    dictionary.
+
+    Parameters
+    ----------
+    lineDic : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. 
+    fileName : string, optional
+        Name of the file to output fit to. Default = 'spectrum_fit.h5'
+
+    """
+    f = h5py.File(file_name, 'w')
+    for ion, params in lineDic.iteritems():
+        f.create_dataset("{0}/N".format(ion),data=params['N'])
+        f.create_dataset("{0}/b".format(ion),data=params['b'])
+        f.create_dataset("{0}/z".format(ion),data=params['z'])
+        f.create_dataset("{0}/complex".format(ion),data=params['group#'])
+    print 'Writing spectrum fit to {0}'.format(file_name)
+

diff -r f15815e182080e8619efd2636cce42bc6e598b7c -r 02fe877276dc48a3d0caa54a3caf957fd735db86 yt/analysis_modules/absorption_spectrum/api.py
--- a/yt/analysis_modules/absorption_spectrum/api.py
+++ b/yt/analysis_modules/absorption_spectrum/api.py
@@ -30,3 +30,6 @@
 
 from .absorption_spectrum import \
     AbsorptionSpectrum
+
+from .absorption_spectrum_fit import \
+    generate_total_fit


https://bitbucket.org/yt_analysis/yt-3.0/commits/41cb5fd0c1fb/
Changeset:   41cb5fd0c1fb
Branch:      yt
User:        hegan
Date:        2013-07-23 20:43:44
Summary:     Merged yt_analysis/yt into yt
Affected #:  5 files

diff -r 02fe877276dc48a3d0caa54a3caf957fd735db86 -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 scripts/iyt
--- a/scripts/iyt
+++ b/scripts/iyt
@@ -1,6 +1,6 @@
 #!python
 import os, re
-from distutils import version
+from distutils.version import LooseVersion
 from yt.mods import *
 from yt.data_objects.data_containers import AMRData
 namespace = locals().copy()
@@ -23,10 +23,12 @@
     code.interact(doc, None, namespace)
     sys.exit()
 
-if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
     api_version = '0.10'
+elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+    api_version = '0.11'
 else:
-    api_version = '0.11'
+    api_version = '1.0'
 
 if api_version == "0.10" and "DISPLAY" in os.environ:
     from matplotlib import rcParams
@@ -42,13 +44,18 @@
         ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
 elif api_version == "0.10":
     ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
-elif api_version == "0.11":
-    from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
+else:
+    if api_version == "0.11":
+        from IPython.frontend.terminal.interactiveshell import \
+            TerminalInteractiveShell
+    elif api_version == "1.0":
+        from IPython.terminal.interactiveshell import TerminalInteractiveShell
+    else:
+        raise RuntimeError
     ip_shell = TerminalInteractiveShell(user_ns=namespace, banner1 = doc,
                     display_banner = True)
     if "DISPLAY" in os.environ: ip_shell.enable_pylab(import_all=False)
-else:
-    raise RuntimeError
+
 
 # The rest is a modified version of the IPython default profile code
 
@@ -77,7 +84,7 @@
     ip = ip_shell.IP.getapi()
     try_next = IPython.ipapi.TryNext
     kwargs = dict(sys_exit=1, banner=doc)
-elif api_version == "0.11":
+elif api_version in ("0.11", "1.0"):
     ip = ip_shell
     try_next = IPython.core.error.TryNext
     kwargs = dict()

diff -r 02fe877276dc48a3d0caa54a3caf957fd735db86 -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -366,5 +366,21 @@
 add_field('nion', function=_nion, take_log=True, units=r"\rm{cm}^{-3}")
 
 def _abar(field, data):
-    return 1.0 / data['sumy']
+    try:
+        return 1.0 / data['sumy']
+    except:
+        pass
+    return data['dens']*Na*kboltz*data['temp']/data['pres']
 add_field('abar', function=_abar, take_log=False)
+	
+
+def _NumberDensity(fields,data) :
+    try:
+        return data["nele"]+data["nion"]
+    except:
+        pass
+    return data['pres']/(data['temp']*kboltz)
+add_field("NumberDensity", function=_NumberDensity,
+        units=r'\rm{cm}^{-3}')
+
+

diff -r 02fe877276dc48a3d0caa54a3caf957fd735db86 -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -28,7 +28,7 @@
 import contextlib
 import warnings, struct, subprocess
 import numpy as np
-from distutils import version
+from distutils.version import LooseVersion
 from math import floor, ceil
 
 from yt.utilities.exceptions import *
@@ -260,10 +260,12 @@
     """
 
     import IPython
-    if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
         api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
     else:
-        api_version = '0.11'
+        api_version = '1.0'
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]
@@ -281,7 +283,10 @@
         cfg.InteractiveShellEmbed.local_ns = loc
         cfg.InteractiveShellEmbed.global_ns = glo
         IPython.embed(config=cfg, banner2 = __header % dd)
-        from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        if api_version == '0.11':
+            from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        else:
+            from IPython.terminal.embed import InteractiveShellEmbed
         ipshell = InteractiveShellEmbed(config=cfg)
 
     del ipshell

diff -r 02fe877276dc48a3d0caa54a3caf957fd735db86 -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1456,7 +1456,12 @@
         """
     def __call__(self, args):
         kwargs = {}
-        from IPython.frontend.html.notebook.notebookapp import NotebookApp
+        try:
+            # IPython 1.0+
+            from IPython.html.notebookapp import NotebookApp
+        except ImportError:
+            # pre-IPython v1.0
+            from IPython.frontend.html.notebook.notebookapp import NotebookApp
         pw = ytcfg.get("yt", "notebook_password")
         if len(pw) == 0 and not args.no_password:
             import IPython.lib

diff -r 02fe877276dc48a3d0caa54a3caf957fd735db86 -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -394,7 +394,7 @@
         nWx, nWy = Wx/factor, Wy/factor
         self.xlim = (centerx - nWx*0.5, centerx + nWx*0.5)
         self.ylim = (centery - nWy*0.5, centery + nWy*0.5)
-
+        return self
 
     @invalidate_data
     def pan(self, deltas):
@@ -408,6 +408,7 @@
         """
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
+        return self
 
     @invalidate_data
     def pan_rel(self, deltas):
@@ -422,6 +423,7 @@
         Wx, Wy = self.width
         self.xlim = (self.xlim[0] + Wx*deltas[0], self.xlim[1] + Wx*deltas[0])
         self.ylim = (self.ylim[0] + Wy*deltas[1], self.ylim[1] + Wy*deltas[1])
+        return self
 
     @invalidate_data
     def set_window(self, bounds):
@@ -1110,6 +1112,11 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def __repr__(self):
+        if "__IPYTHON__" in dir(__builtin__):
+            self.show()
+        return super(PWViewerMPL, self).__repr__()
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/e4cf339b7037/
Changeset:   e4cf339b7037
Branch:      yt
User:        hegan
Date:        2013-08-08 02:41:21
Summary:     Merged yt_analysis/yt into yt
Affected #:  12 files

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,6 +12,7 @@
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -28,7 +28,7 @@
 import ConfigParser, os, os.path, types
 
 ytcfgDefaults = dict(
-    serialize = 'True',
+    serialize = 'False',
     onlydeserialize = 'False',
     timefunctions = 'False',
     logfile = 'False',

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -68,8 +68,9 @@
         if not os.path.exists(apath): raise IOError(filename)
         if apath not in _cached_pfs:
             obj = object.__new__(cls)
-            _cached_pfs[apath] = obj
-        return _cached_pfs[apath]
+            if obj._skip_cache is False:
+                _cached_pfs[apath] = obj
+        return obj
 
     def __init__(self, filename, data_style=None, file_style=None):
         """
@@ -137,6 +138,10 @@
     def _mrep(self):
         return MinimalStaticOutput(self)
 
+    @property
+    def _skip_cache(self):
+        return False
+
     def hub_upload(self):
         self._mrep.upload()
 

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -801,6 +801,8 @@
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
+        if data.pf.dimensionality < i+1:
+            break
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
             np.subtract(r, DW[i], rdw)

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    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 "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:
@@ -309,6 +308,10 @@
         self.grid_left_edge = np.round(self.parameter_file.domain_left_edge + dx*glis, decimals=6)
         self.grid_dimensions = gdims.astype("int32")
         self.grid_right_edge = np.round(self.grid_left_edge + dx*self.grid_dimensions, decimals=6)
+        if self.parameter_file.dimensionality <= 2:
+            self.grid_right_edge[:,2] = self.parameter_file.domain_right_edge[2]
+        if self.parameter_file.dimensionality == 1:
+            self.grid_right_edge[:,1:] = self.parameter_file.domain_right_edge[1:]
         self.grid_particle_count = np.zeros([self.num_grids, 1], dtype='int64')
 
     def _populate_grid_objects(self):
@@ -335,7 +338,9 @@
     _data_style = "athena"
 
     def __init__(self, filename, data_style='athena',
-                 storage_filename=None, parameters={}):
+                 storage_filename=None, parameters=None):
+        if parameters is None:
+            parameters = {}
         self.specified_parameters = parameters
         StaticOutput.__init__(self, filename, data_style)
         self.filename = filename
@@ -467,6 +472,10 @@
             pass
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
     def __repr__(self):
         return self.basename.rsplit(".", 1)[0]
 

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/frontends/athena/fields.py
--- a/yt/frontends/athena/fields.py
+++ b/yt/frontends/athena/fields.py
@@ -128,15 +128,16 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]/(data.pf["Gamma"]-1.0)/data["density"]
     else:
-        return (data["total_energy"] - 
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) - 
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])/data["density"]
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint/data["density"]
 add_field("Gas_Energy", function=_gasenergy, take_log=False,
-          units=r"\rm{erg}/\rm{g}")
+          convert_function=_convertEnergy, units=r"\rm{erg}/\rm{g}")
 
 def _convertPressure(data) :
     return data.convert("Density")*data.convert("x-velocity")**2
@@ -144,15 +145,17 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]
     else:
-        return (data["total_energy"] -
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) -
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])*(data.pf["Gamma"]-1.0)
-add_field("Pressure", function=_pressure, take_log=False, convert_function=_convertPressure,
-          units=r"\rm{erg}/\rm{cm}^3", projected_units=r"\rm{erg}/\rm{cm}^2")
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint*(data.pf["Gamma"]-1.0)
+add_field("Pressure", function=_pressure, take_log=False,
+          convert_function=_convertPressure, units=r"\rm{erg}/\rm{cm}^3",
+          projected_units=r"\rm{erg}/\rm{cm}^2")
 
 def _temperature(field, data):
     if data.has_field_parameter("mu"):

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -339,6 +339,10 @@
     def _is_valid(cls, *args, **kwargs):
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
 class StreamDictFieldHandler(dict):
 
     @property

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -107,7 +107,8 @@
         for lvl in lvl_range:
             gles = np.array([g.LeftEdge for g in grids if g.Level == lvl])
             gres = np.array([g.RightEdge for g in grids if g.Level == lvl])
-            gids = np.array([g.id for g in grids if g.Level == lvl])
+            gids = np.array([g.id for g in grids if g.Level == lvl],
+                            dtype="int64")
 
             add_pygrids(self.trunk, len(gids), gles, gres, gids, self.comm_rank, self.comm_size)
             del gles, gres, gids

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -33,12 +33,20 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            axes.cla()
+            self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -57,7 +65,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name
@@ -67,13 +75,18 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -90,6 +90,17 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -558,6 +569,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -878,9 +890,19 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            cax = None
+            if self.plots.has_key(f):
+                if self.plots[f].figure is not None:
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -947,6 +969,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 
@@ -1137,12 +1160,11 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1247,13 +1269,11 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:
 
@@ -1365,11 +1385,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1448,11 +1468,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1751,7 +1771,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size, fontsize):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+            figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             mylog.warning('The axis ratio of the requested plot is very narrow.  '
@@ -1760,7 +1782,8 @@
                           'and matplotlib.')
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r e4cf339b7037394db6412775bf50a3da59184cda yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -582,7 +582,7 @@
                 (-self.width[0]/2.0, self.width[0]/2.0,
                  -self.width[1]/2.0, self.width[1]/2.0),
                 image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.transfer_function, self.sub_samples)
+                np.array(self.width, dtype='float64'), self.transfer_function, self.sub_samples)
         return args
 
     star_trees = None
@@ -2192,10 +2192,10 @@
     def get_sampler_args(self, image):
         rotp = np.concatenate([self.orienter.inv_mat.ravel('F'), self.back_center.ravel()])
         args = (rotp, self.box_vectors[2], self.back_center,
-            (-self.width[0]/2, self.width[0]/2,
-             -self.width[1]/2, self.width[1]/2),
+            (-self.width[0]/2., self.width[0]/2.,
+             -self.width[1]/2., self.width[1]/2.),
             image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.sub_samples)
+                np.array(self.width, dtype='float64'), self.sub_samples)
         return args
 
     def finalize_image(self,image):


https://bitbucket.org/yt_analysis/yt-3.0/commits/25d422083d69/
Changeset:   25d422083d69
Branch:      yt
User:        hegan
Date:        2013-08-13 17:56:11
Summary:     Fixed length mismatch of group# in outputs
Affected #:  1 file

diff -r 41cb5fd0c1fb05ecf4c58a62a6a12acf47020b15 -r 25d422083d69e55927b5961a9994dfd246ddab1c yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
--- a/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
+++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
@@ -139,7 +139,8 @@
                 speciesLines['N']=na.append(speciesLines['N'],newLinesP[:,0])
                 speciesLines['b']=na.append(speciesLines['b'],newLinesP[:,1])
                 speciesLines['z']=na.append(speciesLines['z'],newLinesP[:,2])
-                speciesLines['group#']=na.append(speciesLines['group#'],b_i)
+                groupNums = b_i*na.ones(na.size(newLinesP[:,0]))
+                speciesLines['group#']=na.append(speciesLines['group#'],groupNums)
 
         allSpeciesLines[species]=speciesLines
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/818df2c5ef23/
Changeset:   818df2c5ef23
Branch:      yt
User:        hegan
Date:        2013-08-13 17:56:53
Summary:     merged
Affected #:  12 files

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,6 +12,7 @@
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -28,7 +28,7 @@
 import ConfigParser, os, os.path, types
 
 ytcfgDefaults = dict(
-    serialize = 'True',
+    serialize = 'False',
     onlydeserialize = 'False',
     timefunctions = 'False',
     logfile = 'False',

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -68,8 +68,9 @@
         if not os.path.exists(apath): raise IOError(filename)
         if apath not in _cached_pfs:
             obj = object.__new__(cls)
-            _cached_pfs[apath] = obj
-        return _cached_pfs[apath]
+            if obj._skip_cache is False:
+                _cached_pfs[apath] = obj
+        return obj
 
     def __init__(self, filename, data_style=None, file_style=None):
         """
@@ -137,6 +138,10 @@
     def _mrep(self):
         return MinimalStaticOutput(self)
 
+    @property
+    def _skip_cache(self):
+        return False
+
     def hub_upload(self):
         self._mrep.upload()
 

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -801,6 +801,8 @@
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
+        if data.pf.dimensionality < i+1:
+            break
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
             np.subtract(r, DW[i], rdw)

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    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 "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:
@@ -309,6 +308,10 @@
         self.grid_left_edge = np.round(self.parameter_file.domain_left_edge + dx*glis, decimals=6)
         self.grid_dimensions = gdims.astype("int32")
         self.grid_right_edge = np.round(self.grid_left_edge + dx*self.grid_dimensions, decimals=6)
+        if self.parameter_file.dimensionality <= 2:
+            self.grid_right_edge[:,2] = self.parameter_file.domain_right_edge[2]
+        if self.parameter_file.dimensionality == 1:
+            self.grid_right_edge[:,1:] = self.parameter_file.domain_right_edge[1:]
         self.grid_particle_count = np.zeros([self.num_grids, 1], dtype='int64')
 
     def _populate_grid_objects(self):
@@ -335,7 +338,9 @@
     _data_style = "athena"
 
     def __init__(self, filename, data_style='athena',
-                 storage_filename=None, parameters={}):
+                 storage_filename=None, parameters=None):
+        if parameters is None:
+            parameters = {}
         self.specified_parameters = parameters
         StaticOutput.__init__(self, filename, data_style)
         self.filename = filename
@@ -467,6 +472,10 @@
             pass
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
     def __repr__(self):
         return self.basename.rsplit(".", 1)[0]
 

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/frontends/athena/fields.py
--- a/yt/frontends/athena/fields.py
+++ b/yt/frontends/athena/fields.py
@@ -128,15 +128,16 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]/(data.pf["Gamma"]-1.0)/data["density"]
     else:
-        return (data["total_energy"] - 
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) - 
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])/data["density"]
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint/data["density"]
 add_field("Gas_Energy", function=_gasenergy, take_log=False,
-          units=r"\rm{erg}/\rm{g}")
+          convert_function=_convertEnergy, units=r"\rm{erg}/\rm{g}")
 
 def _convertPressure(data) :
     return data.convert("Density")*data.convert("x-velocity")**2
@@ -144,15 +145,17 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]
     else:
-        return (data["total_energy"] -
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) -
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])*(data.pf["Gamma"]-1.0)
-add_field("Pressure", function=_pressure, take_log=False, convert_function=_convertPressure,
-          units=r"\rm{erg}/\rm{cm}^3", projected_units=r"\rm{erg}/\rm{cm}^2")
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint*(data.pf["Gamma"]-1.0)
+add_field("Pressure", function=_pressure, take_log=False,
+          convert_function=_convertPressure, units=r"\rm{erg}/\rm{cm}^3",
+          projected_units=r"\rm{erg}/\rm{cm}^2")
 
 def _temperature(field, data):
     if data.has_field_parameter("mu"):

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -339,6 +339,10 @@
     def _is_valid(cls, *args, **kwargs):
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
 class StreamDictFieldHandler(dict):
 
     @property

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -107,7 +107,8 @@
         for lvl in lvl_range:
             gles = np.array([g.LeftEdge for g in grids if g.Level == lvl])
             gres = np.array([g.RightEdge for g in grids if g.Level == lvl])
-            gids = np.array([g.id for g in grids if g.Level == lvl])
+            gids = np.array([g.id for g in grids if g.Level == lvl],
+                            dtype="int64")
 
             add_pygrids(self.trunk, len(gids), gles, gres, gids, self.comm_rank, self.comm_size)
             del gles, gres, gids

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -33,12 +33,20 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            axes.cla()
+            self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -57,7 +65,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name
@@ -67,13 +75,18 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -90,6 +90,17 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -558,6 +569,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -878,9 +890,19 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            cax = None
+            if self.plots.has_key(f):
+                if self.plots[f].figure is not None:
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -947,6 +969,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 
@@ -1137,12 +1160,11 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1247,13 +1269,11 @@
          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', or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+    center : two or three-element vector of sequence floats, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:
 
@@ -1365,11 +1385,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1448,11 +1468,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1751,7 +1771,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size, fontsize):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+            figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             mylog.warning('The axis ratio of the requested plot is very narrow.  '
@@ -1760,7 +1782,8 @@
                           'and matplotlib.')
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':

diff -r 25d422083d69e55927b5961a9994dfd246ddab1c -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -582,7 +582,7 @@
                 (-self.width[0]/2.0, self.width[0]/2.0,
                  -self.width[1]/2.0, self.width[1]/2.0),
                 image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.transfer_function, self.sub_samples)
+                np.array(self.width, dtype='float64'), self.transfer_function, self.sub_samples)
         return args
 
     star_trees = None
@@ -2192,10 +2192,10 @@
     def get_sampler_args(self, image):
         rotp = np.concatenate([self.orienter.inv_mat.ravel('F'), self.back_center.ravel()])
         args = (rotp, self.box_vectors[2], self.back_center,
-            (-self.width[0]/2, self.width[0]/2,
-             -self.width[1]/2, self.width[1]/2),
+            (-self.width[0]/2., self.width[0]/2.,
+             -self.width[1]/2., self.width[1]/2.),
             image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.sub_samples)
+                np.array(self.width, dtype='float64'), self.sub_samples)
         return args
 
     def finalize_image(self,image):


https://bitbucket.org/yt_analysis/yt-3.0/commits/82ea31a9edbc/
Changeset:   82ea31a9edbc
Branch:      yt
User:        hegan
Date:        2013-08-13 17:57:54
Summary:     Merged yt_analysis/yt into yt
Affected #:  9 files

diff -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c -r 82ea31a9edbcd16cb57a57c67af5e78b14b12b38 MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include distribute_setup.py README* CREDITS FUNDING LICENSE.txt
 recursive-include yt/gui/reason/html *.html *.png *.ico *.js
 recursive-include yt *.pyx *.pxd *.hh *.h README*
+recursive-include yt/utilities/kdtree *.f90 *.v Makefile LICENSE
\ No newline at end of file

diff -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c -r 82ea31a9edbcd16cb57a57c67af5e78b14b12b38 yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -8,7 +8,7 @@
 def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
-    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config

diff -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c -r 82ea31a9edbcd16cb57a57c67af5e78b14b12b38 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -70,6 +70,8 @@
             obj = object.__new__(cls)
             if obj._skip_cache is False:
                 _cached_pfs[apath] = obj
+        else:
+            obj = _cached_pfs[apath]
         return obj
 
     def __init__(self, filename, data_style=None, file_style=None):

diff -r 818df2c5ef23aa9b9b6a6e57a105218b4c6b1e7c -r 82ea31a9edbcd16cb57a57c67af5e78b14b12b38 yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -270,7 +270,7 @@
     with temp_cwd(path):
         try:
             load(pf_fn)
-        except:
+        except YTOutputNotIdentified:
             return False
     return AnswerTestingTest.result_storage is not None
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/9f33ef8332b7/
Changeset:   9f33ef8332b7
Branch:      yt
User:        brittonsmith
Date:        2013-08-15 00:25:32
Summary:     Merged in hegan/yt (pull request #565)

Added absorption spectrum fitting
Affected #:  2 files

diff -r ed0606519b9e3ba18ccf5724517f2785860c68ea -r 9f33ef8332b7678e69cb9e41f02747a1a057597a yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
--- /dev/null
+++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
@@ -0,0 +1,809 @@
+from scipy import optimize
+import numpy as na
+import h5py
+from yt.analysis_modules.absorption_spectrum.absorption_line \
+        import voigt
+
+
+def generate_total_fit(x, fluxData, orderFits, speciesDicts, 
+        minError=1E-5, complexLim=.999,
+        fitLim=.99, minLength=3, 
+        maxLength=1000, splitLim=.99,
+        output_file=None):
+
+    """
+    This function is designed to fit an absorption spectrum by breaking 
+    the spectrum up into absorption complexes, and iteratively adding
+    and optimizing voigt profiles to each complex.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        1d array of wavelengths
+    fluxData : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    orderFits : list
+        list of the names of the species in the order that they 
+        should be fit. Names should correspond to the names of the species
+        given in speciesDicts. (ex: ['lya','OVI'])
+    speciesDicts : dictionary
+        Dictionary of dictionaries (I'm addicted to dictionaries, I
+        confess). Top level keys should be the names of all the species given
+        in orderFits. The entries should be dictionaries containing all 
+        relevant parameters needed to create an absorption line of a given 
+        species (f,Gamma,lambda0) as well as max and min values for parameters
+        to be fit
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+    output_file : string, optional
+        location to save the results of the fit. 
+
+    Returns
+    -------
+    allSpeciesLines : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. (ie: N[0],b[0],z[0] will create a line that
+        fits some part of the absorption spectrum). 'group#' is a similar list
+        but identifies which absorbing complex each line belongs to. Lines
+        with the same group# were fit at the same time. group#'s do not
+        correlate between species (ie: an lya line with group number 1 and
+        an OVI line with group number 1 were not fit together and do
+        not necessarily correspond to the same region)
+    yFit : (N) ndarray
+        array of flux corresponding to the combination of all fitted
+        absorption profiles. Same size as x.
+    """
+
+    #Empty dictionary for fitted lines
+    allSpeciesLines = {}
+
+    #Wavelength of beginning of array, wavelength resolution
+    x0,xRes=x[0],x[1]-x[0]
+
+    #Empty fit without any lines
+    yFit = na.ones(len(fluxData))
+
+    #Find all regions where lines/groups of lines are present
+    cBounds = _find_complexes(x, fluxData, fitLim=fitLim,
+            complexLim=complexLim, minLength=minLength,
+            maxLength=maxLength, splitLim=splitLim)
+
+    #Fit all species one at a time in given order from low to high wavelength
+    for species in orderFits:
+        speciesDict = speciesDicts[species]
+        speciesLines = {'N':na.array([]),
+                        'b':na.array([]),
+                        'z':na.array([]),
+                        'group#':na.array([])}
+
+        #Set up wavelengths for species
+        initWl = speciesDict['wavelength'][0]
+
+        for b_i,b in enumerate(cBounds):
+            xBounded=x[b[1]:b[2]]
+            yDatBounded=fluxData[b[1]:b[2]]
+            yFitBounded=yFit[b[1]:b[2]]
+
+            #Find init redshift
+            z=(xBounded[yDatBounded.argmin()]-initWl)/initWl
+
+            #Check if any flux at partner sites
+            if not _line_exists(speciesDict['wavelength'],
+                    fluxData,z,x0,xRes,fitLim): 
+                continue 
+
+            #Fit Using complex tools
+            newLinesP,flag=_complex_fit(xBounded,yDatBounded,yFitBounded,
+                    z,fitLim,minError*(b[2]-b[1]),speciesDict)
+
+            #Check existence of partner lines if applicable
+            newLinesP = _remove_unaccepted_partners(newLinesP, x, fluxData, 
+                    b, minError*(b[2]-b[1]),
+                    x0, xRes, speciesDict)
+
+            #If flagged as a bad fit, species is lyman alpha,
+            #   and it may be a saturated line, use special tools
+            if flag and species=='lya' and min(yDatBounded)<.1:
+                newLinesP=_large_flag_fit(xBounded,yDatBounded,
+                        yFitBounded,z,speciesDict,
+                        minSize,minError*(b[2]-b[1]))
+
+            #Adjust total current fit
+            yFit=yFit*_gen_flux_lines(x,newLinesP,speciesDict)
+
+            #Add new group to all fitted lines
+            if na.size(newLinesP)>0:
+                speciesLines['N']=na.append(speciesLines['N'],newLinesP[:,0])
+                speciesLines['b']=na.append(speciesLines['b'],newLinesP[:,1])
+                speciesLines['z']=na.append(speciesLines['z'],newLinesP[:,2])
+                groupNums = b_i*na.ones(na.size(newLinesP[:,0]))
+                speciesLines['group#']=na.append(speciesLines['group#'],groupNums)
+
+        allSpeciesLines[species]=speciesLines
+
+    if output_file:
+        _output_fit(allSpeciesLines, output_file)
+
+    return (allSpeciesLines,yFit)
+
+def _complex_fit(x, yDat, yFit, initz, minSize, errBound, speciesDict, 
+        initP=None):
+    """ Fit an absorption complex by iteratively adding and optimizing
+    voigt profiles.
+    
+    A complex is defined as a region where some number of lines may be present,
+    or a region of non zero of absorption. Lines are iteratively added
+    and optimized until the difference between the flux generated using
+    the optimized parameters has a least squares difference between the 
+    desired flux profile less than the error bound.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    initP : (,3,) ndarray
+        initial guess to try for line parameters to fit the region. Used
+        by large_flag_fit. Default = None, and initial guess generated
+        automatically.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        Array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]
+    flag : bool
+        boolean value indicating the success of the fit (True if unsuccessful)
+    """
+
+    #Setup initial line guesses
+    if initP==None: #Regular fit
+        initP = [0,0,0] 
+        if min(yDat)<.5: #Large lines get larger initial guess 
+            initP[0] = 10**16
+        elif min(yDat)>.9: #Small lines get smaller initial guess
+            initP[0] = 10**12.5
+        else:
+            initP[0] = speciesDict['init_N']
+        initP[1] = speciesDict['init_b']
+        initP[2]=initz
+        initP=na.array([initP])
+
+    linesP = initP
+
+    #For generating new z guesses
+    wl0 = speciesDict['wavelength'][0]
+
+    #Check if first line exists still
+    if min(yDat-yFit+1)>minSize: 
+        return [],False
+    
+    #Values to proceed through first run
+    errSq,prevErrSq=1,1000
+
+    while True:
+        #Initial parameter guess from joining parameters from all lines
+        #   in lines into a single array
+        initP = linesP.flatten()
+
+        #Optimize line
+        fitP,success=optimize.leastsq(_voigt_error,initP,
+                args=(x,yDat,yFit,speciesDict),
+                epsfcn=1E-10,maxfev=1000)
+
+        #Set results of optimization
+        linesP = na.reshape(fitP,(-1,3))
+
+        #Generate difference between current best fit and data
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+
+        #Sum to get idea of goodness of fit
+        errSq=sum(dif**2)
+
+        #If good enough, break
+        if errSq < errBound: 
+            break
+
+        #If last fit was worse, reject the last line and revert to last fit
+        if errSq > prevErrSq*10:
+            #If its still pretty damn bad, cut losses and try flag fit tools
+            if prevErrSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                yNewFit=_gen_flux_lines(x,prevLinesP,speciesDict)
+                break
+
+        #If too many lines 
+        if na.shape(linesP)[0]>8 or na.size(linesP)+3>=len(x):
+            #If its fitable by flag tools and still bad, use flag tools
+            if errSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                break 
+
+        #Store previous data in case reject next fit
+        prevErrSq = errSq
+        prevLinesP = linesP
+
+
+        #Set up initial condition for new line
+        newP = [0,0,0] 
+        if min(dif)<.1:
+            newP[0]=10**12
+        elif min(dif)>.9:
+            newP[0]=10**16
+        else:
+            newP[0]=10**14
+        newP[1] = speciesDict['init_b']
+        newP[2]=(x[dif.argmax()]-wl0)/wl0
+        linesP=na.append(linesP,[newP],axis=0)
+
+
+    #Check the parameters of all lines to see if they fall in an
+    #   acceptable range, as given in dict ref
+    remove=[]
+    for i,p in enumerate(linesP):
+        check=_check_params(na.array([p]),speciesDict)
+        if check: 
+            remove.append(i)
+    linesP = na.delete(linesP,remove,axis=0)
+
+    return linesP,False
+
+def _large_flag_fit(x, yDat, yFit, initz, speciesDict, minSize, errBound):
+    """
+    Attempts to more robustly fit saturated lyman alpha regions that have
+    not converged to satisfactory fits using the standard tools.
+
+    Uses a preselected sample of a wide range of initial parameter guesses
+    designed to fit saturated lines (see get_test_lines).
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+
+    Returns
+    -------
+    bestP : (3,) ndarray
+        array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]  
+    """
+
+    #Set up some initial line guesses
+    lineTests = _get_test_lines(initz)
+
+    #Keep track of the lowest achieved error
+    bestError = 1000 
+
+    #Iterate through test line guesses
+    for initLines in lineTests:
+        if initLines[1,0]==0:
+            initLines = na.delete(initLines,1,axis=0)
+
+        #Do fitting with initLines as first guess
+        linesP,flag=_complex_fit(x,yDat,yFit,initz,
+                minSize,errBound,speciesDict,initP=initLines)
+
+        #Find error of last fit
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+        errSq=sum(dif**2)
+
+        #If error lower, keep track of the lines used to make that fit
+        if errSq < bestError:
+            bestError = errSq
+            bestP = linesP
+
+    if bestError>10*errBound*len(x): 
+        return []
+    else:
+        return bestP
+
+def _get_test_lines(initz):
+    """
+    Returns a 3d numpy array of lines to test as initial guesses for difficult
+    to fit lyman alpha absorbers that are saturated. 
+    
+    The array is 3d because
+    the first dimension gives separate initial guesses, the second dimension
+    has multiple lines for the same guess (trying a broad line plus a 
+    saturated line) and the 3d dimension contains the 3 fit parameters (N,b,z)
+
+    Parameters
+    ----------
+    initz : float
+        redshift to give all the test lines
+
+    Returns
+    -------
+    testP : (,3,) ndarray
+        numpy array of the form 
+        [[[N1a,b1a,z1a], [N1b,b1b,z1b]], [[N2a,b2,z2a],...] ...]
+    """
+
+    #Set up a bunch of empty lines
+    testP = na.zeros((10,2,3))
+
+    testP[0,0,:]=[1E18,20,initz]
+    testP[1,0,:]=[1E18,40,initz]
+    testP[2,0,:]=[1E16,5, initz]
+    testP[3,0,:]=[1E16,20,initz]
+    testP[4,0,:]=[1E16,80,initz]
+
+    testP[5,0,:]=[1E18,20,initz]
+    testP[6,0,:]=[1E18,40,initz]
+    testP[7,0,:]=[1E16,5, initz]
+    testP[8,0,:]=[1E16,20,initz]
+    testP[9,0,:]=[1E16,80,initz]
+
+    testP[5,1,:]=[1E13,100,initz]
+    testP[6,1,:]=[1E13,100,initz]
+    testP[7,1,:]=[1E13,100,initz]
+    testP[8,1,:]=[1E13,100,initz]
+    testP[9,1,:]=[1E13,100,initz]
+
+    return testP
+
+def _get_bounds(z, b, wl, x0, xRes):
+    """ 
+    Gets the indices of range of wavelength that the wavelength wl is in 
+    with the size of some initial wavelength range.
+
+    Used for checking if species with multiple lines (as in the OVI doublet)
+    fit all lines appropriately.
+
+    Parameters
+    ----------
+    z : float
+        redshift
+    b : (3) ndarray/list
+        initial bounds in form [i0,i1,i2] where i0 is the index of the 
+        minimum flux for the complex, i1 is index of the lower wavelength 
+        edge of the complex, and i2 is the index of the higher wavelength
+        edge of the complex.
+    wl : float
+        unredshifted wavelength of the peak of the new region 
+    x0 : float
+        wavelength of the index 0
+    xRes : float
+        difference in wavelength for two consecutive indices
+    
+    Returns
+    -------
+    indices : (2) tuple
+        Tuple (i1,i2) where i1 is the index of the lower wavelength bound of 
+        the new region and i2 is the index of the higher wavelength bound of
+        the new region
+    """
+
+    r=[-b[1]+100+b[0],b[2]+100-b[0]]
+    redWl = (z+1)*wl
+    iRedWl=int((redWl-x0)/xRes)
+    indices = (iRedWl-r[0],iRedWl+r[1])
+
+    return indices
+
+def _remove_unaccepted_partners(linesP, x, y, b, errBound, 
+        x0, xRes, speciesDict):
+    """
+    Given a set of parameters [N,b,z] that form multiple lines for a given
+    species (as in the OVI doublet), remove any set of parameters where
+    not all transition wavelengths have a line that matches the fit.
+
+    (ex: if a fit is determined based on the first line of the OVI doublet,
+    but the given parameters give a bad fit of the wavelength space of
+    the second line then that set of parameters is removed from the array
+    of line parameters.)
+
+    Parameters
+    ----------
+    linesP : (3,) ndarray
+        array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    x : (N) ndarray
+        wavelength array [nm]
+    y : (N) ndarray
+        normalized flux array of original data
+    b : (3) tuple/list/ndarray
+        indices that give the bounds of the original region so that another 
+        region of similar size can be used to determine the goodness
+        of fit of the other wavelengths
+    errBound : float
+        size of the error that is appropriate for a given region, 
+        adjusted to account for the size of the region.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        array similar to linesP that only contains lines with
+        appropriate fits of all transition wavelengths.
+    """
+
+    #List of lines to remove
+    removeLines=[]
+
+    #Iterate through all sets of line parameters
+    for i,p in enumerate(linesP):
+
+        #iterate over all transition wavelengths
+        for wl in speciesDict['wavelength']:
+
+            #Get the bounds of a similar sized region around the
+            #   appropriate wavelength, and then get the appropriate
+            #   region of wavelength and flux
+            lb = _get_bounds(p[2],b,wl,x0,xRes)
+            xb,yb=x[lb[0]:lb[1]],y[lb[0]:lb[1]]
+
+            #Generate a fit and find the difference to data
+            yFitb=_gen_flux_lines(xb,na.array([p]),speciesDict)
+            dif =yb-yFitb
+
+            #Only counts as an error if line is too big ---------------<
+            dif = [k for k in dif if k>0]
+            err = sum(dif)
+
+            #If the fit is too bad then add the line to list of removed lines
+            if err > errBound*1E2:
+                removeLines.append(i)
+                break
+
+    #Remove all bad line fits
+    linesP = na.delete(linesP,removeLines,axis=0)
+
+    return linesP 
+
+
+
+def _line_exists(wavelengths, y, z, x0, xRes,fluxMin):
+    """For a group of lines finds if the there is some change in flux greater
+    than some minimum at the same redshift with different initial wavelengths
+
+    Parameters
+    ----------
+    wavelengths : (N) ndarray
+        array of initial wavelengths to check
+    y : (N) ndarray
+        flux array to check
+    x0 : float
+        wavelength of the first value in y
+    xRes : float
+        difference in wavelength between consecutive cells in flux array
+    fluxMin : float
+        maximum flux to count as a line existing. 
+
+    Returns
+    -------
+
+    flag : boolean 
+        value indicating whether all lines exist. True if all lines exist
+    """
+
+    #Iterate through initial wavelengths
+    for wl in wavelengths:
+        #Redshifted wavelength
+        redWl = (z+1)*wl
+
+        #Index of the redshifted wavelength
+        indexRedWl = (redWl-x0)/xRes
+
+        #Check if surpasses minimum absorption bound
+        if y[int(indexRedWl)]>fluxMin:
+            return False
+
+    return True
+
+def _find_complexes(x, yDat, complexLim=.999, fitLim=.99,
+        minLength =3, maxLength=1000, splitLim=.99):
+    """Breaks up the wavelength space into groups
+    where there is some absorption. 
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelengths
+    yDat : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+
+    Returns
+    -------
+    cBounds : (3,) 
+        list of bounds in the form [[i0,i1,i2],...] where i0 is the 
+        index of the maximum flux for a complex, i1 is the index of the
+        beginning of the complex, and i2 is the index of the end of the 
+        complex. Indexes refer to the indices of x and yDat.
+    """
+
+    #Initialize empty list of bounds
+    cBounds=[]
+
+    #Iterate through cells of flux
+    i=0
+    while (i<len(x)):
+
+        #Start tracking at a region that surpasses flux of edge
+        if yDat[i]<complexLim:
+
+            #Iterate through until reach next edge
+            j=0
+            while yDat[i+j]<complexLim: j=j+1
+
+            #Check if the complex is big enough
+            if j >minLength:
+
+                #Check if there is enough absorption for the complex to
+                #   be included
+                cPeak = yDat[i:i+j].argmin()
+                if yDat[cPeak+i]<fitLim:
+                    cBounds.append([cPeak+i,i,i+j])
+
+            i=i+j
+        i=i+1
+
+    i=0
+    #Iterate through the bounds
+    while i < len(cBounds):
+        b=cBounds[i]
+
+        #Check if the region needs to be divided
+        if b[2]-b[1]>maxLength:
+
+            #Find the minimum absorption in the middle two quartiles of
+            #   the large complex
+            q=(b[2]-b[1])/4
+            cut = yDat[b[1]+q:b[2]-q].argmax()+b[1]+q
+
+            #Only break it up if the minimum absorption is actually low enough
+            if yDat[cut]>splitLim:
+
+                #Get the new two peaks
+                b1Peak = yDat[b[1]:cut].argmin()+b[1]
+                b2Peak = yDat[cut:b[2]].argmin()+cut
+
+                #add the two regions separately
+                cBounds.insert(i+1,[b1Peak,b[1],cut])
+                cBounds.insert(i+2,[b2Peak,cut,b[2]])
+
+                #Remove the original region
+                cBounds.pop(i)
+                i=i+1
+        i=i+1
+
+    return cBounds
+
+def _gen_flux_lines(x, linesP, speciesDict):
+    """
+    Calculates the normalized flux for a region of wavelength space
+    generated by a set of absorption lines.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        Array of wavelength
+    linesP: (3,) ndarray
+        Array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    speciesDict : dictionary
+        Dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+
+    Returns
+    -------
+    flux : (N) ndarray
+        Array of normalized flux generated by the line parameters
+        given in linesP over the wavelength space given in x. Same size as x.
+    """
+    y=0
+    for p in linesP:
+        for i in range(speciesDict['numLines']):
+            f=speciesDict['f'][i]
+            g=speciesDict['Gamma'][i]
+            wl=speciesDict['wavelength'][i]
+            y = y+ _gen_tau(x,p,f,g,wl)
+    flux = na.exp(-y)
+    return flux
+
+def _gen_tau(t, p, f, Gamma, lambda_unshifted):
+    """This calculates a flux distribution for given parameters using the yt
+    voigt profile generator"""
+    N,b,z= p
+    
+    #Calculating quantities
+    tau_o = 1.4973614E-15*N*f*lambda_unshifted/b
+    a=7.95774715459E-15*Gamma*lambda_unshifted/b
+    x=299792.458/b*(lambda_unshifted*(1+z)/t-1)
+    
+    H = na.zeros(len(x))
+    H = voigt(a,x)
+    
+    tau = tau_o*H
+
+    return tau
+
+def _voigt_error(pTotal, x, yDat, yFit, speciesDict):
+    """
+    Gives the error of each point  used to optimize the fit of a group
+        of absorption lines to a given flux profile.
+
+        If the parameters are not in the acceptable range as defined
+        in speciesDict, the first value of the error array will
+        contain a large value (999), to prevent the optimizer from running
+        into negative number problems.
+
+    Parameters
+    ----------
+    pTotal : (3,) ndarray 
+        Array with form [[N1, b1, z1], ...] 
+    x : (N) ndarray
+        array of wavelengths [nm]
+    yDat : (N) ndarray
+        desired normalized flux from fits of lines in wavelength
+        space given by x
+    yFit : (N) ndarray
+        previous fit over the wavelength space given by x.
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+
+    Returns
+    -------
+    error : (N) ndarray
+        the difference between the fit generated by the parameters
+        given in pTotal multiplied by the previous fit and the desired
+        flux profile, w/ first index modified appropriately for bad 
+        parameter choices
+    """
+
+    pTotal.shape = (-1,3)
+    yNewFit = _gen_flux_lines(x,pTotal,speciesDict)
+
+    error = yDat-yFit*yNewFit
+    error[0] = _check_params(pTotal,speciesDict)
+
+    return error
+
+def _check_params(p, speciesDict):
+    """
+    Check to see if any of the parameters in p fall outside the range 
+        given in speciesDict.
+
+    Parameters
+    ----------
+    p : (3,) ndarray
+        array with form [[N1, b1, z1], ...] 
+    speciesDict : dictionary
+        dictionary with properties giving the max and min
+        values appropriate for each parameter N,b, and z.
+
+    Returns
+    -------
+    check : int
+        0 if all values are fine
+        999 if any values fall outside acceptable range
+    """
+    check = 0
+    if any(p[:,0] > speciesDict['maxN']) or\
+          any(p[:,0] < speciesDict['minN']) or\
+          any(p[:,1] > speciesDict['maxb']) or\
+          any(p[:,1] < speciesDict['minb']) or\
+          any(p[:,2] > speciesDict['maxz']) or\
+          any(p[:,2] < speciesDict['minz']):
+              check = 999
+    return check
+
+
+def _output_fit(lineDic, file_name = 'spectrum_fit.h5'):
+    """
+    This function is designed to output the parameters of the series
+    of lines used to fit an absorption spectrum. 
+
+    The dataset contains entries in the form species/N, species/b
+    species/z, and species/complex. The ith entry in each of the datasets
+    is the fitted parameter for the ith line fitted to the spectrum for
+    the given species. The species names come from the fitted line
+    dictionary.
+
+    Parameters
+    ----------
+    lineDic : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. 
+    fileName : string, optional
+        Name of the file to output fit to. Default = 'spectrum_fit.h5'
+
+    """
+    f = h5py.File(file_name, 'w')
+    for ion, params in lineDic.iteritems():
+        f.create_dataset("{0}/N".format(ion),data=params['N'])
+        f.create_dataset("{0}/b".format(ion),data=params['b'])
+        f.create_dataset("{0}/z".format(ion),data=params['z'])
+        f.create_dataset("{0}/complex".format(ion),data=params['group#'])
+    print 'Writing spectrum fit to {0}'.format(file_name)
+

diff -r ed0606519b9e3ba18ccf5724517f2785860c68ea -r 9f33ef8332b7678e69cb9e41f02747a1a057597a yt/analysis_modules/absorption_spectrum/api.py
--- a/yt/analysis_modules/absorption_spectrum/api.py
+++ b/yt/analysis_modules/absorption_spectrum/api.py
@@ -30,3 +30,6 @@
 
 from .absorption_spectrum import \
     AbsorptionSpectrum
+
+from .absorption_spectrum_fit import \
+    generate_total_fit


https://bitbucket.org/yt_analysis/yt-3.0/commits/7d2a2985e72d/
Changeset:   7d2a2985e72d
Branch:      yt
User:        ngoldbaum
Date:        2013-08-16 00:45:25
Summary:     Making show() invoke IPython.display.display on IPython 1.0
Affected #:  1 file

diff -r 9f33ef8332b7678e69cb9e41f02747a1a057597a -r 7d2a2985e72d6bba38bd37bea3db5d64d60c9fd5 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1127,7 +1127,8 @@
             if api_version in ('0.10', '0.11'):
                 self._send_zmq()
             else:
-                return self
+                from IPython.display import display
+                display(self)
         else:
             raise YTNotInsideNotebook
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/5c4c13506b7b/
Changeset:   5c4c13506b7b
Branch:      yt-3.0
User:        ngoldbaum
Date:        2013-08-16 22:17:19
Summary:     Merging from yt-2.X.
Affected #:  30 files

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 .hgchurn
--- a/.hgchurn
+++ b/.hgchurn
@@ -4,8 +4,16 @@
 juxtaposicion at gmail.com = cemoody at ucsc.edu
 chummels at gmail.com = chummels at astro.columbia.edu
 jwise at astro.princeton.edu = jwise at physics.gatech.edu
-atmyers = atmyers at berkeley.edu
 sam.skillman at gmail.com = samskillman at gmail.com
 casey at thestarkeffect.com = caseywstark at gmail.com
 chiffre = chiffre at posteo.de
 Christian Karch = chiffre at posteo.de
+atmyers at berkeley.edu = atmyers2 at gmail.com
+atmyers = atmyers2 at gmail.com
+drudd = drudd at uchicago.edu
+awetzel = andrew.wetzel at yale.edu
+David Collins (dcollins4096 at gmail.com) = dcollins4096 at gmail.com
+dcollins at physics.ucsd.edu = dcollins4096 at gmail.com
+tabel = tabel at slac.stanford.edu
+sername=kayleanelson = kaylea.nelson at yale.edu
+kayleanelson = kaylea.nelson at yale.edu

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include distribute_setup.py README* CREDITS FUNDING LICENSE.txt
 recursive-include yt/gui/reason/html *.html *.png *.ico *.js
 recursive-include yt *.pyx *.pxd *.hh *.h README*
+recursive-include yt/utilities/kdtree *.f90 *.v Makefile LICENSE
\ No newline at end of file

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 scripts/iyt
--- a/scripts/iyt
+++ b/scripts/iyt
@@ -1,6 +1,6 @@
 #!python
 import os, re
-from distutils import version
+from distutils.version import LooseVersion
 from yt.mods import *
 from yt.data_objects.data_containers import YTDataContainer
 namespace = locals().copy()
@@ -23,10 +23,12 @@
     code.interact(doc, None, namespace)
     sys.exit()
 
-if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
     api_version = '0.10'
+elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+    api_version = '0.11'
 else:
-    api_version = '0.11'
+    api_version = '1.0'
 
 if api_version == "0.10" and "DISPLAY" in os.environ:
     from matplotlib import rcParams
@@ -42,13 +44,18 @@
         ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
 elif api_version == "0.10":
     ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
-elif api_version == "0.11":
-    from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
+else:
+    if api_version == "0.11":
+        from IPython.frontend.terminal.interactiveshell import \
+            TerminalInteractiveShell
+    elif api_version == "1.0":
+        from IPython.terminal.interactiveshell import TerminalInteractiveShell
+    else:
+        raise RuntimeError
     ip_shell = TerminalInteractiveShell(user_ns=namespace, banner1 = doc,
                     display_banner = True)
     if "DISPLAY" in os.environ: ip_shell.enable_pylab(import_all=False)
-else:
-    raise RuntimeError
+
 
 # The rest is a modified version of the IPython default profile code
 
@@ -77,7 +84,7 @@
     ip = ip_shell.IP.getapi()
     try_next = IPython.ipapi.TryNext
     kwargs = dict(sys_exit=1, banner=doc)
-elif api_version == "0.11":
+elif api_version in ("0.11", "1.0"):
     ip = ip_shell
     try_next = IPython.core.error.TryNext
     kwargs = dict()

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -96,7 +96,7 @@
     if answer_big_data:
         nose_argv.append('--answer-big-data')
     log_suppress = ytcfg.getboolean("yt","suppressStreamLogging")
-    ytcfg["yt","suppressStreamLogging"] = 'True'
+    ytcfg.set("yt","suppressStreamLogging", 'True')
     initial_dir = os.getcwd()
     yt_file = os.path.abspath(__file__)
     yt_dir = os.path.dirname(yt_file)
@@ -105,4 +105,4 @@
         nose.run(argv=nose_argv)
     finally:
         os.chdir(initial_dir)
-        ytcfg["yt","suppressStreamLogging"] = log_suppress
+        ytcfg.set("yt","suppressStreamLogging", str(log_suppress))

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
--- /dev/null
+++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
@@ -0,0 +1,809 @@
+from scipy import optimize
+import numpy as na
+import h5py
+from yt.analysis_modules.absorption_spectrum.absorption_line \
+        import voigt
+
+
+def generate_total_fit(x, fluxData, orderFits, speciesDicts, 
+        minError=1E-5, complexLim=.999,
+        fitLim=.99, minLength=3, 
+        maxLength=1000, splitLim=.99,
+        output_file=None):
+
+    """
+    This function is designed to fit an absorption spectrum by breaking 
+    the spectrum up into absorption complexes, and iteratively adding
+    and optimizing voigt profiles to each complex.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        1d array of wavelengths
+    fluxData : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    orderFits : list
+        list of the names of the species in the order that they 
+        should be fit. Names should correspond to the names of the species
+        given in speciesDicts. (ex: ['lya','OVI'])
+    speciesDicts : dictionary
+        Dictionary of dictionaries (I'm addicted to dictionaries, I
+        confess). Top level keys should be the names of all the species given
+        in orderFits. The entries should be dictionaries containing all 
+        relevant parameters needed to create an absorption line of a given 
+        species (f,Gamma,lambda0) as well as max and min values for parameters
+        to be fit
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+    output_file : string, optional
+        location to save the results of the fit. 
+
+    Returns
+    -------
+    allSpeciesLines : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. (ie: N[0],b[0],z[0] will create a line that
+        fits some part of the absorption spectrum). 'group#' is a similar list
+        but identifies which absorbing complex each line belongs to. Lines
+        with the same group# were fit at the same time. group#'s do not
+        correlate between species (ie: an lya line with group number 1 and
+        an OVI line with group number 1 were not fit together and do
+        not necessarily correspond to the same region)
+    yFit : (N) ndarray
+        array of flux corresponding to the combination of all fitted
+        absorption profiles. Same size as x.
+    """
+
+    #Empty dictionary for fitted lines
+    allSpeciesLines = {}
+
+    #Wavelength of beginning of array, wavelength resolution
+    x0,xRes=x[0],x[1]-x[0]
+
+    #Empty fit without any lines
+    yFit = na.ones(len(fluxData))
+
+    #Find all regions where lines/groups of lines are present
+    cBounds = _find_complexes(x, fluxData, fitLim=fitLim,
+            complexLim=complexLim, minLength=minLength,
+            maxLength=maxLength, splitLim=splitLim)
+
+    #Fit all species one at a time in given order from low to high wavelength
+    for species in orderFits:
+        speciesDict = speciesDicts[species]
+        speciesLines = {'N':na.array([]),
+                        'b':na.array([]),
+                        'z':na.array([]),
+                        'group#':na.array([])}
+
+        #Set up wavelengths for species
+        initWl = speciesDict['wavelength'][0]
+
+        for b_i,b in enumerate(cBounds):
+            xBounded=x[b[1]:b[2]]
+            yDatBounded=fluxData[b[1]:b[2]]
+            yFitBounded=yFit[b[1]:b[2]]
+
+            #Find init redshift
+            z=(xBounded[yDatBounded.argmin()]-initWl)/initWl
+
+            #Check if any flux at partner sites
+            if not _line_exists(speciesDict['wavelength'],
+                    fluxData,z,x0,xRes,fitLim): 
+                continue 
+
+            #Fit Using complex tools
+            newLinesP,flag=_complex_fit(xBounded,yDatBounded,yFitBounded,
+                    z,fitLim,minError*(b[2]-b[1]),speciesDict)
+
+            #Check existence of partner lines if applicable
+            newLinesP = _remove_unaccepted_partners(newLinesP, x, fluxData, 
+                    b, minError*(b[2]-b[1]),
+                    x0, xRes, speciesDict)
+
+            #If flagged as a bad fit, species is lyman alpha,
+            #   and it may be a saturated line, use special tools
+            if flag and species=='lya' and min(yDatBounded)<.1:
+                newLinesP=_large_flag_fit(xBounded,yDatBounded,
+                        yFitBounded,z,speciesDict,
+                        minSize,minError*(b[2]-b[1]))
+
+            #Adjust total current fit
+            yFit=yFit*_gen_flux_lines(x,newLinesP,speciesDict)
+
+            #Add new group to all fitted lines
+            if na.size(newLinesP)>0:
+                speciesLines['N']=na.append(speciesLines['N'],newLinesP[:,0])
+                speciesLines['b']=na.append(speciesLines['b'],newLinesP[:,1])
+                speciesLines['z']=na.append(speciesLines['z'],newLinesP[:,2])
+                groupNums = b_i*na.ones(na.size(newLinesP[:,0]))
+                speciesLines['group#']=na.append(speciesLines['group#'],groupNums)
+
+        allSpeciesLines[species]=speciesLines
+
+    if output_file:
+        _output_fit(allSpeciesLines, output_file)
+
+    return (allSpeciesLines,yFit)
+
+def _complex_fit(x, yDat, yFit, initz, minSize, errBound, speciesDict, 
+        initP=None):
+    """ Fit an absorption complex by iteratively adding and optimizing
+    voigt profiles.
+    
+    A complex is defined as a region where some number of lines may be present,
+    or a region of non zero of absorption. Lines are iteratively added
+    and optimized until the difference between the flux generated using
+    the optimized parameters has a least squares difference between the 
+    desired flux profile less than the error bound.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    initP : (,3,) ndarray
+        initial guess to try for line parameters to fit the region. Used
+        by large_flag_fit. Default = None, and initial guess generated
+        automatically.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        Array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]
+    flag : bool
+        boolean value indicating the success of the fit (True if unsuccessful)
+    """
+
+    #Setup initial line guesses
+    if initP==None: #Regular fit
+        initP = [0,0,0] 
+        if min(yDat)<.5: #Large lines get larger initial guess 
+            initP[0] = 10**16
+        elif min(yDat)>.9: #Small lines get smaller initial guess
+            initP[0] = 10**12.5
+        else:
+            initP[0] = speciesDict['init_N']
+        initP[1] = speciesDict['init_b']
+        initP[2]=initz
+        initP=na.array([initP])
+
+    linesP = initP
+
+    #For generating new z guesses
+    wl0 = speciesDict['wavelength'][0]
+
+    #Check if first line exists still
+    if min(yDat-yFit+1)>minSize: 
+        return [],False
+    
+    #Values to proceed through first run
+    errSq,prevErrSq=1,1000
+
+    while True:
+        #Initial parameter guess from joining parameters from all lines
+        #   in lines into a single array
+        initP = linesP.flatten()
+
+        #Optimize line
+        fitP,success=optimize.leastsq(_voigt_error,initP,
+                args=(x,yDat,yFit,speciesDict),
+                epsfcn=1E-10,maxfev=1000)
+
+        #Set results of optimization
+        linesP = na.reshape(fitP,(-1,3))
+
+        #Generate difference between current best fit and data
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+
+        #Sum to get idea of goodness of fit
+        errSq=sum(dif**2)
+
+        #If good enough, break
+        if errSq < errBound: 
+            break
+
+        #If last fit was worse, reject the last line and revert to last fit
+        if errSq > prevErrSq*10:
+            #If its still pretty damn bad, cut losses and try flag fit tools
+            if prevErrSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                yNewFit=_gen_flux_lines(x,prevLinesP,speciesDict)
+                break
+
+        #If too many lines 
+        if na.shape(linesP)[0]>8 or na.size(linesP)+3>=len(x):
+            #If its fitable by flag tools and still bad, use flag tools
+            if errSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                break 
+
+        #Store previous data in case reject next fit
+        prevErrSq = errSq
+        prevLinesP = linesP
+
+
+        #Set up initial condition for new line
+        newP = [0,0,0] 
+        if min(dif)<.1:
+            newP[0]=10**12
+        elif min(dif)>.9:
+            newP[0]=10**16
+        else:
+            newP[0]=10**14
+        newP[1] = speciesDict['init_b']
+        newP[2]=(x[dif.argmax()]-wl0)/wl0
+        linesP=na.append(linesP,[newP],axis=0)
+
+
+    #Check the parameters of all lines to see if they fall in an
+    #   acceptable range, as given in dict ref
+    remove=[]
+    for i,p in enumerate(linesP):
+        check=_check_params(na.array([p]),speciesDict)
+        if check: 
+            remove.append(i)
+    linesP = na.delete(linesP,remove,axis=0)
+
+    return linesP,False
+
+def _large_flag_fit(x, yDat, yFit, initz, speciesDict, minSize, errBound):
+    """
+    Attempts to more robustly fit saturated lyman alpha regions that have
+    not converged to satisfactory fits using the standard tools.
+
+    Uses a preselected sample of a wide range of initial parameter guesses
+    designed to fit saturated lines (see get_test_lines).
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+
+    Returns
+    -------
+    bestP : (3,) ndarray
+        array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]  
+    """
+
+    #Set up some initial line guesses
+    lineTests = _get_test_lines(initz)
+
+    #Keep track of the lowest achieved error
+    bestError = 1000 
+
+    #Iterate through test line guesses
+    for initLines in lineTests:
+        if initLines[1,0]==0:
+            initLines = na.delete(initLines,1,axis=0)
+
+        #Do fitting with initLines as first guess
+        linesP,flag=_complex_fit(x,yDat,yFit,initz,
+                minSize,errBound,speciesDict,initP=initLines)
+
+        #Find error of last fit
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+        errSq=sum(dif**2)
+
+        #If error lower, keep track of the lines used to make that fit
+        if errSq < bestError:
+            bestError = errSq
+            bestP = linesP
+
+    if bestError>10*errBound*len(x): 
+        return []
+    else:
+        return bestP
+
+def _get_test_lines(initz):
+    """
+    Returns a 3d numpy array of lines to test as initial guesses for difficult
+    to fit lyman alpha absorbers that are saturated. 
+    
+    The array is 3d because
+    the first dimension gives separate initial guesses, the second dimension
+    has multiple lines for the same guess (trying a broad line plus a 
+    saturated line) and the 3d dimension contains the 3 fit parameters (N,b,z)
+
+    Parameters
+    ----------
+    initz : float
+        redshift to give all the test lines
+
+    Returns
+    -------
+    testP : (,3,) ndarray
+        numpy array of the form 
+        [[[N1a,b1a,z1a], [N1b,b1b,z1b]], [[N2a,b2,z2a],...] ...]
+    """
+
+    #Set up a bunch of empty lines
+    testP = na.zeros((10,2,3))
+
+    testP[0,0,:]=[1E18,20,initz]
+    testP[1,0,:]=[1E18,40,initz]
+    testP[2,0,:]=[1E16,5, initz]
+    testP[3,0,:]=[1E16,20,initz]
+    testP[4,0,:]=[1E16,80,initz]
+
+    testP[5,0,:]=[1E18,20,initz]
+    testP[6,0,:]=[1E18,40,initz]
+    testP[7,0,:]=[1E16,5, initz]
+    testP[8,0,:]=[1E16,20,initz]
+    testP[9,0,:]=[1E16,80,initz]
+
+    testP[5,1,:]=[1E13,100,initz]
+    testP[6,1,:]=[1E13,100,initz]
+    testP[7,1,:]=[1E13,100,initz]
+    testP[8,1,:]=[1E13,100,initz]
+    testP[9,1,:]=[1E13,100,initz]
+
+    return testP
+
+def _get_bounds(z, b, wl, x0, xRes):
+    """ 
+    Gets the indices of range of wavelength that the wavelength wl is in 
+    with the size of some initial wavelength range.
+
+    Used for checking if species with multiple lines (as in the OVI doublet)
+    fit all lines appropriately.
+
+    Parameters
+    ----------
+    z : float
+        redshift
+    b : (3) ndarray/list
+        initial bounds in form [i0,i1,i2] where i0 is the index of the 
+        minimum flux for the complex, i1 is index of the lower wavelength 
+        edge of the complex, and i2 is the index of the higher wavelength
+        edge of the complex.
+    wl : float
+        unredshifted wavelength of the peak of the new region 
+    x0 : float
+        wavelength of the index 0
+    xRes : float
+        difference in wavelength for two consecutive indices
+    
+    Returns
+    -------
+    indices : (2) tuple
+        Tuple (i1,i2) where i1 is the index of the lower wavelength bound of 
+        the new region and i2 is the index of the higher wavelength bound of
+        the new region
+    """
+
+    r=[-b[1]+100+b[0],b[2]+100-b[0]]
+    redWl = (z+1)*wl
+    iRedWl=int((redWl-x0)/xRes)
+    indices = (iRedWl-r[0],iRedWl+r[1])
+
+    return indices
+
+def _remove_unaccepted_partners(linesP, x, y, b, errBound, 
+        x0, xRes, speciesDict):
+    """
+    Given a set of parameters [N,b,z] that form multiple lines for a given
+    species (as in the OVI doublet), remove any set of parameters where
+    not all transition wavelengths have a line that matches the fit.
+
+    (ex: if a fit is determined based on the first line of the OVI doublet,
+    but the given parameters give a bad fit of the wavelength space of
+    the second line then that set of parameters is removed from the array
+    of line parameters.)
+
+    Parameters
+    ----------
+    linesP : (3,) ndarray
+        array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    x : (N) ndarray
+        wavelength array [nm]
+    y : (N) ndarray
+        normalized flux array of original data
+    b : (3) tuple/list/ndarray
+        indices that give the bounds of the original region so that another 
+        region of similar size can be used to determine the goodness
+        of fit of the other wavelengths
+    errBound : float
+        size of the error that is appropriate for a given region, 
+        adjusted to account for the size of the region.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        array similar to linesP that only contains lines with
+        appropriate fits of all transition wavelengths.
+    """
+
+    #List of lines to remove
+    removeLines=[]
+
+    #Iterate through all sets of line parameters
+    for i,p in enumerate(linesP):
+
+        #iterate over all transition wavelengths
+        for wl in speciesDict['wavelength']:
+
+            #Get the bounds of a similar sized region around the
+            #   appropriate wavelength, and then get the appropriate
+            #   region of wavelength and flux
+            lb = _get_bounds(p[2],b,wl,x0,xRes)
+            xb,yb=x[lb[0]:lb[1]],y[lb[0]:lb[1]]
+
+            #Generate a fit and find the difference to data
+            yFitb=_gen_flux_lines(xb,na.array([p]),speciesDict)
+            dif =yb-yFitb
+
+            #Only counts as an error if line is too big ---------------<
+            dif = [k for k in dif if k>0]
+            err = sum(dif)
+
+            #If the fit is too bad then add the line to list of removed lines
+            if err > errBound*1E2:
+                removeLines.append(i)
+                break
+
+    #Remove all bad line fits
+    linesP = na.delete(linesP,removeLines,axis=0)
+
+    return linesP 
+
+
+
+def _line_exists(wavelengths, y, z, x0, xRes,fluxMin):
+    """For a group of lines finds if the there is some change in flux greater
+    than some minimum at the same redshift with different initial wavelengths
+
+    Parameters
+    ----------
+    wavelengths : (N) ndarray
+        array of initial wavelengths to check
+    y : (N) ndarray
+        flux array to check
+    x0 : float
+        wavelength of the first value in y
+    xRes : float
+        difference in wavelength between consecutive cells in flux array
+    fluxMin : float
+        maximum flux to count as a line existing. 
+
+    Returns
+    -------
+
+    flag : boolean 
+        value indicating whether all lines exist. True if all lines exist
+    """
+
+    #Iterate through initial wavelengths
+    for wl in wavelengths:
+        #Redshifted wavelength
+        redWl = (z+1)*wl
+
+        #Index of the redshifted wavelength
+        indexRedWl = (redWl-x0)/xRes
+
+        #Check if surpasses minimum absorption bound
+        if y[int(indexRedWl)]>fluxMin:
+            return False
+
+    return True
+
+def _find_complexes(x, yDat, complexLim=.999, fitLim=.99,
+        minLength =3, maxLength=1000, splitLim=.99):
+    """Breaks up the wavelength space into groups
+    where there is some absorption. 
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelengths
+    yDat : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+
+    Returns
+    -------
+    cBounds : (3,) 
+        list of bounds in the form [[i0,i1,i2],...] where i0 is the 
+        index of the maximum flux for a complex, i1 is the index of the
+        beginning of the complex, and i2 is the index of the end of the 
+        complex. Indexes refer to the indices of x and yDat.
+    """
+
+    #Initialize empty list of bounds
+    cBounds=[]
+
+    #Iterate through cells of flux
+    i=0
+    while (i<len(x)):
+
+        #Start tracking at a region that surpasses flux of edge
+        if yDat[i]<complexLim:
+
+            #Iterate through until reach next edge
+            j=0
+            while yDat[i+j]<complexLim: j=j+1
+
+            #Check if the complex is big enough
+            if j >minLength:
+
+                #Check if there is enough absorption for the complex to
+                #   be included
+                cPeak = yDat[i:i+j].argmin()
+                if yDat[cPeak+i]<fitLim:
+                    cBounds.append([cPeak+i,i,i+j])
+
+            i=i+j
+        i=i+1
+
+    i=0
+    #Iterate through the bounds
+    while i < len(cBounds):
+        b=cBounds[i]
+
+        #Check if the region needs to be divided
+        if b[2]-b[1]>maxLength:
+
+            #Find the minimum absorption in the middle two quartiles of
+            #   the large complex
+            q=(b[2]-b[1])/4
+            cut = yDat[b[1]+q:b[2]-q].argmax()+b[1]+q
+
+            #Only break it up if the minimum absorption is actually low enough
+            if yDat[cut]>splitLim:
+
+                #Get the new two peaks
+                b1Peak = yDat[b[1]:cut].argmin()+b[1]
+                b2Peak = yDat[cut:b[2]].argmin()+cut
+
+                #add the two regions separately
+                cBounds.insert(i+1,[b1Peak,b[1],cut])
+                cBounds.insert(i+2,[b2Peak,cut,b[2]])
+
+                #Remove the original region
+                cBounds.pop(i)
+                i=i+1
+        i=i+1
+
+    return cBounds
+
+def _gen_flux_lines(x, linesP, speciesDict):
+    """
+    Calculates the normalized flux for a region of wavelength space
+    generated by a set of absorption lines.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        Array of wavelength
+    linesP: (3,) ndarray
+        Array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    speciesDict : dictionary
+        Dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+
+    Returns
+    -------
+    flux : (N) ndarray
+        Array of normalized flux generated by the line parameters
+        given in linesP over the wavelength space given in x. Same size as x.
+    """
+    y=0
+    for p in linesP:
+        for i in range(speciesDict['numLines']):
+            f=speciesDict['f'][i]
+            g=speciesDict['Gamma'][i]
+            wl=speciesDict['wavelength'][i]
+            y = y+ _gen_tau(x,p,f,g,wl)
+    flux = na.exp(-y)
+    return flux
+
+def _gen_tau(t, p, f, Gamma, lambda_unshifted):
+    """This calculates a flux distribution for given parameters using the yt
+    voigt profile generator"""
+    N,b,z= p
+    
+    #Calculating quantities
+    tau_o = 1.4973614E-15*N*f*lambda_unshifted/b
+    a=7.95774715459E-15*Gamma*lambda_unshifted/b
+    x=299792.458/b*(lambda_unshifted*(1+z)/t-1)
+    
+    H = na.zeros(len(x))
+    H = voigt(a,x)
+    
+    tau = tau_o*H
+
+    return tau
+
+def _voigt_error(pTotal, x, yDat, yFit, speciesDict):
+    """
+    Gives the error of each point  used to optimize the fit of a group
+        of absorption lines to a given flux profile.
+
+        If the parameters are not in the acceptable range as defined
+        in speciesDict, the first value of the error array will
+        contain a large value (999), to prevent the optimizer from running
+        into negative number problems.
+
+    Parameters
+    ----------
+    pTotal : (3,) ndarray 
+        Array with form [[N1, b1, z1], ...] 
+    x : (N) ndarray
+        array of wavelengths [nm]
+    yDat : (N) ndarray
+        desired normalized flux from fits of lines in wavelength
+        space given by x
+    yFit : (N) ndarray
+        previous fit over the wavelength space given by x.
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+
+    Returns
+    -------
+    error : (N) ndarray
+        the difference between the fit generated by the parameters
+        given in pTotal multiplied by the previous fit and the desired
+        flux profile, w/ first index modified appropriately for bad 
+        parameter choices
+    """
+
+    pTotal.shape = (-1,3)
+    yNewFit = _gen_flux_lines(x,pTotal,speciesDict)
+
+    error = yDat-yFit*yNewFit
+    error[0] = _check_params(pTotal,speciesDict)
+
+    return error
+
+def _check_params(p, speciesDict):
+    """
+    Check to see if any of the parameters in p fall outside the range 
+        given in speciesDict.
+
+    Parameters
+    ----------
+    p : (3,) ndarray
+        array with form [[N1, b1, z1], ...] 
+    speciesDict : dictionary
+        dictionary with properties giving the max and min
+        values appropriate for each parameter N,b, and z.
+
+    Returns
+    -------
+    check : int
+        0 if all values are fine
+        999 if any values fall outside acceptable range
+    """
+    check = 0
+    if any(p[:,0] > speciesDict['maxN']) or\
+          any(p[:,0] < speciesDict['minN']) or\
+          any(p[:,1] > speciesDict['maxb']) or\
+          any(p[:,1] < speciesDict['minb']) or\
+          any(p[:,2] > speciesDict['maxz']) or\
+          any(p[:,2] < speciesDict['minz']):
+              check = 999
+    return check
+
+
+def _output_fit(lineDic, file_name = 'spectrum_fit.h5'):
+    """
+    This function is designed to output the parameters of the series
+    of lines used to fit an absorption spectrum. 
+
+    The dataset contains entries in the form species/N, species/b
+    species/z, and species/complex. The ith entry in each of the datasets
+    is the fitted parameter for the ith line fitted to the spectrum for
+    the given species. The species names come from the fitted line
+    dictionary.
+
+    Parameters
+    ----------
+    lineDic : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. 
+    fileName : string, optional
+        Name of the file to output fit to. Default = 'spectrum_fit.h5'
+
+    """
+    f = h5py.File(file_name, 'w')
+    for ion, params in lineDic.iteritems():
+        f.create_dataset("{0}/N".format(ion),data=params['N'])
+        f.create_dataset("{0}/b".format(ion),data=params['b'])
+        f.create_dataset("{0}/z".format(ion),data=params['z'])
+        f.create_dataset("{0}/complex".format(ion),data=params['group#'])
+    print 'Writing spectrum fit to {0}'.format(file_name)
+

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/analysis_modules/absorption_spectrum/api.py
--- a/yt/analysis_modules/absorption_spectrum/api.py
+++ b/yt/analysis_modules/absorption_spectrum/api.py
@@ -30,3 +30,6 @@
 
 from .absorption_spectrum import \
     AbsorptionSpectrum
+
+from .absorption_spectrum_fit import \
+    generate_total_fit

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -28,7 +28,7 @@
 import ConfigParser, os, os.path, types
 
 ytcfgDefaults = dict(
-    serialize = 'True',
+    serialize = 'False',
     onlydeserialize = 'False',
     timefunctions = 'False',
     logfile = 'False',
@@ -62,7 +62,7 @@
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
-    gold_standard_filename = 'gold008',
+    gold_standard_filename = 'gold009',
     local_standard_filename = 'local001',
     sketchfab_api_key = 'None',
     thread_field_detection = 'False'

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -8,7 +8,7 @@
 def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
-    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -86,8 +86,11 @@
         if not os.path.exists(apath): raise IOError(filename)
         if apath not in _cached_pfs:
             obj = object.__new__(cls)
-            _cached_pfs[apath] = obj
-        return _cached_pfs[apath]
+            if obj._skip_cache is False:
+                _cached_pfs[apath] = obj
+        else:
+            obj = _cached_pfs[apath]
+        return obj
 
     def __init__(self, filename, data_style=None, file_style=None):
         """
@@ -157,6 +160,10 @@
     def _mrep(self):
         return MinimalStaticOutput(self)
 
+    @property
+    def _skip_cache(self):
+        return False
+
     def hub_upload(self):
         self._mrep.upload()
 

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -753,6 +753,8 @@
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
+        if data.pf.dimensionality < i+1:
+            break
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
             np.subtract(r, DW[i], rdw)

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    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 "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:
@@ -309,6 +308,10 @@
         self.grid_left_edge = np.round(self.parameter_file.domain_left_edge + dx*glis, decimals=6)
         self.grid_dimensions = gdims.astype("int32")
         self.grid_right_edge = np.round(self.grid_left_edge + dx*self.grid_dimensions, decimals=6)
+        if self.parameter_file.dimensionality <= 2:
+            self.grid_right_edge[:,2] = self.parameter_file.domain_right_edge[2]
+        if self.parameter_file.dimensionality == 1:
+            self.grid_right_edge[:,1:] = self.parameter_file.domain_right_edge[1:]
         self.grid_particle_count = np.zeros([self.num_grids, 1], dtype='int64')
 
     def _populate_grid_objects(self):
@@ -335,7 +338,9 @@
     _data_style = "athena"
 
     def __init__(self, filename, data_style='athena',
-                 storage_filename=None, parameters={}):
+                 storage_filename=None, parameters=None):
+        if parameters is None:
+            parameters = {}
         self.specified_parameters = parameters
         StaticOutput.__init__(self, filename, data_style)
         self.filename = filename
@@ -467,6 +472,10 @@
             pass
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
     def __repr__(self):
         return self.basename.rsplit(".", 1)[0]
 

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/frontends/athena/fields.py
--- a/yt/frontends/athena/fields.py
+++ b/yt/frontends/athena/fields.py
@@ -128,15 +128,16 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]/(data.pf["Gamma"]-1.0)/data["density"]
     else:
-        return (data["total_energy"] - 
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) - 
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])/data["density"]
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint/data["density"]
 add_field("Gas_Energy", function=_gasenergy, take_log=False,
-          units=r"\rm{erg}/\rm{g}")
+          convert_function=_convertEnergy, units=r"\rm{erg}/\rm{g}")
 
 def _convertPressure(data) :
     return data.convert("Density")*data.convert("x-velocity")**2
@@ -144,15 +145,17 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]
     else:
-        return (data["total_energy"] -
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) -
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])*(data.pf["Gamma"]-1.0)
-add_field("Pressure", function=_pressure, take_log=False, convert_function=_convertPressure,
-          units=r"\rm{erg}/\rm{cm}^3", projected_units=r"\rm{erg}/\rm{cm}^2")
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint*(data.pf["Gamma"]-1.0)
+add_field("Pressure", function=_pressure, take_log=False,
+          convert_function=_convertPressure, units=r"\rm{erg}/\rm{cm}^3",
+          projected_units=r"\rm{erg}/\rm{cm}^2")
 
 def _temperature(field, data):
     if data.has_field_parameter("mu"):

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -367,5 +367,21 @@
 
 
 def _abar(field, data):
-    return 1.0 / data['sumy']
+    try:
+        return 1.0 / data['sumy']
+    except:
+        pass
+    return data['dens']*Na*kboltz*data['temp']/data['pres']
 add_field('abar', function=_abar, take_log=False)
+	
+
+def _NumberDensity(fields,data) :
+    try:
+        return data["nele"]+data["nion"]
+    except:
+        pass
+    return data['pres']/(data['temp']*kboltz)
+add_field("NumberDensity", function=_NumberDensity,
+        units=r'\rm{cm}^{-3}')
+
+

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -308,6 +308,10 @@
     def _is_valid(cls, *args, **kwargs):
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
 class StreamDictFieldHandler(dict):
 
     @property

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -28,7 +28,7 @@
 import contextlib
 import warnings, struct, subprocess
 import numpy as np
-from distutils import version
+from distutils.version import LooseVersion
 from math import floor, ceil
 
 from yt.utilities.exceptions import *
@@ -250,6 +250,17 @@
      %(filename)s:%(lineno)s
 """
 
+def get_ipython_api_version():
+    import IPython
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
+        api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
+    else:
+        api_version = '1.0'
+
+    return api_version
+
 def insert_ipython(num_up=1):
     """
     Placed inside a function, this will insert an IPython interpreter at that
@@ -259,11 +270,7 @@
     defaults to 1 so that this function itself is stripped off.
     """
 
-    import IPython
-    if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
-        api_version = '0.10'
-    else:
-        api_version = '0.11'
+    api_version = get_ipython_api_version()
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]
@@ -281,7 +288,10 @@
         cfg.InteractiveShellEmbed.local_ns = loc
         cfg.InteractiveShellEmbed.global_ns = glo
         IPython.embed(config=cfg, banner2 = __header % dd)
-        from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        if api_version == '0.11':
+            from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        else:
+            from IPython.terminal.embed import InteractiveShellEmbed
         ipshell = InteractiveShellEmbed(config=cfg)
 
     del ipshell

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/startup_tasks.py
--- a/yt/startup_tasks.py
+++ b/yt/startup_tasks.py
@@ -36,9 +36,11 @@
 def turn_on_parallelism():
     try:
         from mpi4py import MPI
-        parallel_capable = (MPI.COMM_WORLD.size > 1)
-    except ImportError:
-        parallel_capable = False
+    except ImportError as e:
+        mylog.error("Warning: Attempting to turn on parallelism, " +
+                    "but mpi4py import failed. Try pip install mpi4py.")
+        raise e
+    parallel_capable = (MPI.COMM_WORLD.size > 1)
     if parallel_capable:
         mylog.info("Global parallel computation enabled: %s / %s",
                    MPI.COMM_WORLD.rank, MPI.COMM_WORLD.size)

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -89,7 +89,8 @@
         for lvl in lvl_range:
             #grids = self.data_source.select_grids(lvl)
             grids = np.array([b for b, mask in self.data_source.blocks if b.Level == lvl])
-            if len(grids) == 0: continue
+            gids = np.array([g.id for g in grids if g.Level == lvl],
+                            dtype="int64")
             self.add_grids(grids)
 
     def check_tree(self):

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -270,7 +270,7 @@
     with temp_cwd(path):
         try:
             load(pf_fn)
-        except:
+        except YTOutputNotIdentified:
             return False
     return AnswerTestingTest.result_storage is not None
 

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1456,7 +1456,12 @@
         """
     def __call__(self, args):
         kwargs = {}
-        from IPython.frontend.html.notebook.notebookapp import NotebookApp
+        try:
+            # IPython 1.0+
+            from IPython.html.notebookapp import NotebookApp
+        except ImportError:
+            # pre-IPython v1.0
+            from IPython.frontend.html.notebook.notebookapp import NotebookApp
         pw = ytcfg.get("yt", "notebook_password")
         if len(pw) == 0 and not args.no_password:
             import IPython.lib

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -58,6 +58,15 @@
     double sin(double x) nogil
     double sqrt(double x) nogil
 
+ctypedef void sampler_function(
+                VolumeContainer *vc,
+                np.float64_t v_pos[3],
+                np.float64_t v_dir[3],
+                np.float64_t enter_t,
+                np.float64_t exit_t,
+                int index[3],
+                void *data) nogil
+
 cdef class PartitionedGrid:
     cdef public object my_data
     cdef public object source_mask 
@@ -223,7 +232,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function *sampler
+    cdef sampler_function *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -921,7 +930,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function *sampler,
+                     sampler_function *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -1,15 +1,16 @@
 #
 # Physical Constants and Units Conversion Factors
 #
-# Values for these constants are drawn from IAU and IUPAC data 
-# unless otherwise noted:
+# Values for these constants, unless otherwise noted, are drawn from IAU,
+# IUPAC, and NIST data, whichever is newer.
 # http://maia.usno.navy.mil/NSFA/IAU2009_consts.html
 # http://goldbook.iupac.org/list_goldbook_phys_constants_defs.html
+# http://physics.nist.gov/cuu/Constants/index.html
 
 # Masses
-mass_hydrogen_cgs = 1.674534e-24  # g
-mass_electron_cgs = 9.1093898e-28  # g
-amu_cgs           = 1.6605402e-24  # g
+mass_electron_cgs = 9.109382-28  # g
+amu_cgs           = 1.660538921e-24  # g
+mass_hydrogen_cgs = 1.007947*amu_cgs  # g
 mass_sun_cgs = 1.98841586e33  # g
 # Velocities
 speed_of_light_cgs = 2.99792458e10  # cm/s, exact
@@ -22,10 +23,10 @@
 charge_proton_cgs = 4.8032056e-10  # esu = 1.602176487e-19  Coulombs
 
 # Physical Constants
-boltzmann_constant_cgs = 1.3806504e-16  # erg K^-1
-gravitational_constant_cgs  = 6.67428e-8  # cm^3 g^-1 s^-2
-planck_constant_cgs   = 6.62606896e-27  # erg s
-stefan_boltzmann_constant_cgs = 5.67051e-5 # erg cm^-2 s^-1 K^-4
+boltzmann_constant_cgs = 1.3806488e-16  # erg K^-1
+gravitational_constant_cgs  = 6.67384e-8  # cm^3 g^-1 s^-2
+planck_constant_cgs   = 6.62606957e-27  # erg s
+stefan_boltzmann_constant_cgs = 5.670373e-5 # erg cm^-2 s^-1 K^-4
 # The following value was calcualted assuming H = 100 km/s/Mpc.
 # To get the correct value for your cosmological parameters, 
 # you'll need to multiply through by h^2
@@ -69,16 +70,17 @@
 cm_per_pc     = 1.0 / pc_per_cm
 
 # time
+# "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 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_year = 31.5576e6
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25
 
 # temperature / energy
-erg_per_eV = 1.602176487e-12 # http://goldbook.iupac.org/E02014.html
+erg_per_eV = 1.602176562e-12
 erg_per_keV = erg_per_eV * 1.0e3
 K_per_keV = erg_per_keV / boltzmann_constant_cgs
 keV_per_K = 1.0 / K_per_keV

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -23,6 +23,7 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 import matplotlib
+import cStringIO
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
@@ -33,12 +34,20 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            axes.cla()
+            self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -57,7 +66,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name
@@ -67,13 +76,18 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -52,7 +52,7 @@
 from yt.utilities.delaunay.triangulate import Triangulation as triang
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
-    fix_axis, get_image_suffix
+    fix_axis, get_image_suffix, get_ipython_api_version
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
     x_dict, y_dict, \
@@ -90,6 +90,17 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -399,7 +410,7 @@
         nWx, nWy = Wx/factor, Wy/factor
         self.xlim = (centerx - nWx*0.5, centerx + nWx*0.5)
         self.ylim = (centery - nWy*0.5, centery + nWy*0.5)
-
+        return self
 
     @invalidate_data
     def pan(self, deltas):
@@ -413,6 +424,7 @@
         """
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
+        return self
 
     @invalidate_data
     def pan_rel(self, deltas):
@@ -427,6 +439,7 @@
         Wx, Wy = self.width
         self.xlim = (self.xlim[0] + Wx*deltas[0], self.xlim[1] + Wx*deltas[0])
         self.ylim = (self.ylim[0] + Wy*deltas[1], self.ylim[1] + Wy*deltas[1])
+        return self
 
     @invalidate_data
     def set_window(self, bounds):
@@ -563,6 +576,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -904,9 +918,19 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            cax = None
+            if self.plots.has_key(f):
+                if self.plots[f].figure is not None:
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -973,6 +997,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 
@@ -1130,7 +1155,12 @@
 
         """
         if "__IPYTHON__" in dir(__builtin__):
-            self._send_zmq()
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                from IPython.display import display
+                display(self)
         else:
             raise YTNotInsideNotebook
 
@@ -1142,6 +1172,15 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        ret = ''
+        for field in self.plots:
+            img = base64.b64encode(self.plots[field]._repr_png_())
+            ret += '<img src="data:image/png;base64,%s"><br>' % img
+        return ret
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 
@@ -1164,11 +1203,9 @@
          The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center',
              or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1280,12 +1317,9 @@
         The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center',
              or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:
 
@@ -1401,11 +1435,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1494,11 +1528,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1808,6 +1842,7 @@
 class WindowPlotMPL(ImagePlotMPL):
     def __init__(self, data, cbname, cmap, extent, aspect, zlim, size,
                  fontsize):
+            figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             msg = 'The axis ratio of the requested plot is very narrow. ' \
@@ -1817,7 +1852,8 @@
             mylog.warn(msg)
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':

diff -r 7372a6bb4bb0bd9891b670b19191fe95391aea5f -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -542,7 +542,7 @@
                 (-self.width[0]/2.0, self.width[0]/2.0,
                  -self.width[1]/2.0, self.width[1]/2.0),
                 image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.transfer_function, self.sub_samples)
+                np.array(self.width, dtype='float64'), self.transfer_function, self.sub_samples)
         return args
 
     star_trees = None
@@ -2159,10 +2159,10 @@
     def get_sampler_args(self, image):
         rotp = np.concatenate([self.orienter.inv_mat.ravel('F'), self.back_center.ravel()])
         args = (rotp, self.box_vectors[2], self.back_center,
-            (-self.width[0]/2, self.width[0]/2,
-             -self.width[1]/2, self.width[1]/2),
+            (-self.width[0]/2., self.width[0]/2.,
+             -self.width[1]/2., self.width[1]/2.),
             image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.sub_samples)
+                np.array(self.width, dtype='float64'), self.sub_samples)
         return args
 
     def finalize_image(self,image):


https://bitbucket.org/yt_analysis/yt-3.0/commits/4c748a593636/
Changeset:   4c748a593636
Branch:      yt-3.0
User:        ngoldbaum
Date:        2013-08-16 22:22:01
Summary:     Fixing an error I made fixing a merge conflict.
Affected #:  1 file

diff -r 5c4c13506b7b11d76f69bba2de4fa5fbb7ba44a8 -r 4c748a593636b1ecb5775d549aa9720cef420611 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1840,9 +1840,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size,
-                 fontsize):
-            figure, axes, cax):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+                figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             msg = 'The axis ratio of the requested plot is very narrow. ' \


https://bitbucket.org/yt_analysis/yt-3.0/commits/0f157d8055c4/
Changeset:   0f157d8055c4
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 03:18:18
Summary:     Merging with Nathan's development repo
Affected #:  31 files

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c .hgchurn
--- a/.hgchurn
+++ b/.hgchurn
@@ -4,8 +4,16 @@
 juxtaposicion at gmail.com = cemoody at ucsc.edu
 chummels at gmail.com = chummels at astro.columbia.edu
 jwise at astro.princeton.edu = jwise at physics.gatech.edu
-atmyers = atmyers at berkeley.edu
 sam.skillman at gmail.com = samskillman at gmail.com
 casey at thestarkeffect.com = caseywstark at gmail.com
 chiffre = chiffre at posteo.de
 Christian Karch = chiffre at posteo.de
+atmyers at berkeley.edu = atmyers2 at gmail.com
+atmyers = atmyers2 at gmail.com
+drudd = drudd at uchicago.edu
+awetzel = andrew.wetzel at yale.edu
+David Collins (dcollins4096 at gmail.com) = dcollins4096 at gmail.com
+dcollins at physics.ucsd.edu = dcollins4096 at gmail.com
+tabel = tabel at slac.stanford.edu
+sername=kayleanelson = kaylea.nelson at yale.edu
+kayleanelson = kaylea.nelson at yale.edu

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include distribute_setup.py README* CREDITS FUNDING LICENSE.txt
 recursive-include yt/gui/reason/html *.html *.png *.ico *.js
 recursive-include yt *.pyx *.pxd *.hh *.h README*
+recursive-include yt/utilities/kdtree *.f90 *.v Makefile LICENSE
\ No newline at end of file

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c scripts/iyt
--- a/scripts/iyt
+++ b/scripts/iyt
@@ -1,6 +1,6 @@
 #!python
 import os, re
-from distutils import version
+from distutils.version import LooseVersion
 from yt.mods import *
 from yt.data_objects.data_containers import YTDataContainer
 namespace = locals().copy()
@@ -23,10 +23,12 @@
     code.interact(doc, None, namespace)
     sys.exit()
 
-if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
+if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
     api_version = '0.10'
+elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+    api_version = '0.11'
 else:
-    api_version = '0.11'
+    api_version = '1.0'
 
 if api_version == "0.10" and "DISPLAY" in os.environ:
     from matplotlib import rcParams
@@ -42,13 +44,18 @@
         ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
 elif api_version == "0.10":
     ip_shell = IPython.Shell.IPShellMatplotlib(user_ns=namespace)
-elif api_version == "0.11":
-    from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
+else:
+    if api_version == "0.11":
+        from IPython.frontend.terminal.interactiveshell import \
+            TerminalInteractiveShell
+    elif api_version == "1.0":
+        from IPython.terminal.interactiveshell import TerminalInteractiveShell
+    else:
+        raise RuntimeError
     ip_shell = TerminalInteractiveShell(user_ns=namespace, banner1 = doc,
                     display_banner = True)
     if "DISPLAY" in os.environ: ip_shell.enable_pylab(import_all=False)
-else:
-    raise RuntimeError
+
 
 # The rest is a modified version of the IPython default profile code
 
@@ -77,7 +84,7 @@
     ip = ip_shell.IP.getapi()
     try_next = IPython.ipapi.TryNext
     kwargs = dict(sys_exit=1, banner=doc)
-elif api_version == "0.11":
+elif api_version in ("0.11", "1.0"):
     ip = ip_shell
     try_next = IPython.core.error.TryNext
     kwargs = dict()

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -96,7 +96,7 @@
     if answer_big_data:
         nose_argv.append('--answer-big-data')
     log_suppress = ytcfg.getboolean("yt","suppressStreamLogging")
-    ytcfg["yt","suppressStreamLogging"] = 'True'
+    ytcfg.set("yt","suppressStreamLogging", 'True')
     initial_dir = os.getcwd()
     yt_file = os.path.abspath(__file__)
     yt_dir = os.path.dirname(yt_file)
@@ -105,4 +105,4 @@
         nose.run(argv=nose_argv)
     finally:
         os.chdir(initial_dir)
-        ytcfg["yt","suppressStreamLogging"] = log_suppress
+        ytcfg.set("yt","suppressStreamLogging", str(log_suppress))

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
--- /dev/null
+++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
@@ -0,0 +1,809 @@
+from scipy import optimize
+import numpy as na
+import h5py
+from yt.analysis_modules.absorption_spectrum.absorption_line \
+        import voigt
+
+
+def generate_total_fit(x, fluxData, orderFits, speciesDicts, 
+        minError=1E-5, complexLim=.999,
+        fitLim=.99, minLength=3, 
+        maxLength=1000, splitLim=.99,
+        output_file=None):
+
+    """
+    This function is designed to fit an absorption spectrum by breaking 
+    the spectrum up into absorption complexes, and iteratively adding
+    and optimizing voigt profiles to each complex.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        1d array of wavelengths
+    fluxData : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    orderFits : list
+        list of the names of the species in the order that they 
+        should be fit. Names should correspond to the names of the species
+        given in speciesDicts. (ex: ['lya','OVI'])
+    speciesDicts : dictionary
+        Dictionary of dictionaries (I'm addicted to dictionaries, I
+        confess). Top level keys should be the names of all the species given
+        in orderFits. The entries should be dictionaries containing all 
+        relevant parameters needed to create an absorption line of a given 
+        species (f,Gamma,lambda0) as well as max and min values for parameters
+        to be fit
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+    output_file : string, optional
+        location to save the results of the fit. 
+
+    Returns
+    -------
+    allSpeciesLines : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. (ie: N[0],b[0],z[0] will create a line that
+        fits some part of the absorption spectrum). 'group#' is a similar list
+        but identifies which absorbing complex each line belongs to. Lines
+        with the same group# were fit at the same time. group#'s do not
+        correlate between species (ie: an lya line with group number 1 and
+        an OVI line with group number 1 were not fit together and do
+        not necessarily correspond to the same region)
+    yFit : (N) ndarray
+        array of flux corresponding to the combination of all fitted
+        absorption profiles. Same size as x.
+    """
+
+    #Empty dictionary for fitted lines
+    allSpeciesLines = {}
+
+    #Wavelength of beginning of array, wavelength resolution
+    x0,xRes=x[0],x[1]-x[0]
+
+    #Empty fit without any lines
+    yFit = na.ones(len(fluxData))
+
+    #Find all regions where lines/groups of lines are present
+    cBounds = _find_complexes(x, fluxData, fitLim=fitLim,
+            complexLim=complexLim, minLength=minLength,
+            maxLength=maxLength, splitLim=splitLim)
+
+    #Fit all species one at a time in given order from low to high wavelength
+    for species in orderFits:
+        speciesDict = speciesDicts[species]
+        speciesLines = {'N':na.array([]),
+                        'b':na.array([]),
+                        'z':na.array([]),
+                        'group#':na.array([])}
+
+        #Set up wavelengths for species
+        initWl = speciesDict['wavelength'][0]
+
+        for b_i,b in enumerate(cBounds):
+            xBounded=x[b[1]:b[2]]
+            yDatBounded=fluxData[b[1]:b[2]]
+            yFitBounded=yFit[b[1]:b[2]]
+
+            #Find init redshift
+            z=(xBounded[yDatBounded.argmin()]-initWl)/initWl
+
+            #Check if any flux at partner sites
+            if not _line_exists(speciesDict['wavelength'],
+                    fluxData,z,x0,xRes,fitLim): 
+                continue 
+
+            #Fit Using complex tools
+            newLinesP,flag=_complex_fit(xBounded,yDatBounded,yFitBounded,
+                    z,fitLim,minError*(b[2]-b[1]),speciesDict)
+
+            #Check existence of partner lines if applicable
+            newLinesP = _remove_unaccepted_partners(newLinesP, x, fluxData, 
+                    b, minError*(b[2]-b[1]),
+                    x0, xRes, speciesDict)
+
+            #If flagged as a bad fit, species is lyman alpha,
+            #   and it may be a saturated line, use special tools
+            if flag and species=='lya' and min(yDatBounded)<.1:
+                newLinesP=_large_flag_fit(xBounded,yDatBounded,
+                        yFitBounded,z,speciesDict,
+                        minSize,minError*(b[2]-b[1]))
+
+            #Adjust total current fit
+            yFit=yFit*_gen_flux_lines(x,newLinesP,speciesDict)
+
+            #Add new group to all fitted lines
+            if na.size(newLinesP)>0:
+                speciesLines['N']=na.append(speciesLines['N'],newLinesP[:,0])
+                speciesLines['b']=na.append(speciesLines['b'],newLinesP[:,1])
+                speciesLines['z']=na.append(speciesLines['z'],newLinesP[:,2])
+                groupNums = b_i*na.ones(na.size(newLinesP[:,0]))
+                speciesLines['group#']=na.append(speciesLines['group#'],groupNums)
+
+        allSpeciesLines[species]=speciesLines
+
+    if output_file:
+        _output_fit(allSpeciesLines, output_file)
+
+    return (allSpeciesLines,yFit)
+
+def _complex_fit(x, yDat, yFit, initz, minSize, errBound, speciesDict, 
+        initP=None):
+    """ Fit an absorption complex by iteratively adding and optimizing
+    voigt profiles.
+    
+    A complex is defined as a region where some number of lines may be present,
+    or a region of non zero of absorption. Lines are iteratively added
+    and optimized until the difference between the flux generated using
+    the optimized parameters has a least squares difference between the 
+    desired flux profile less than the error bound.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    initP : (,3,) ndarray
+        initial guess to try for line parameters to fit the region. Used
+        by large_flag_fit. Default = None, and initial guess generated
+        automatically.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        Array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]
+    flag : bool
+        boolean value indicating the success of the fit (True if unsuccessful)
+    """
+
+    #Setup initial line guesses
+    if initP==None: #Regular fit
+        initP = [0,0,0] 
+        if min(yDat)<.5: #Large lines get larger initial guess 
+            initP[0] = 10**16
+        elif min(yDat)>.9: #Small lines get smaller initial guess
+            initP[0] = 10**12.5
+        else:
+            initP[0] = speciesDict['init_N']
+        initP[1] = speciesDict['init_b']
+        initP[2]=initz
+        initP=na.array([initP])
+
+    linesP = initP
+
+    #For generating new z guesses
+    wl0 = speciesDict['wavelength'][0]
+
+    #Check if first line exists still
+    if min(yDat-yFit+1)>minSize: 
+        return [],False
+    
+    #Values to proceed through first run
+    errSq,prevErrSq=1,1000
+
+    while True:
+        #Initial parameter guess from joining parameters from all lines
+        #   in lines into a single array
+        initP = linesP.flatten()
+
+        #Optimize line
+        fitP,success=optimize.leastsq(_voigt_error,initP,
+                args=(x,yDat,yFit,speciesDict),
+                epsfcn=1E-10,maxfev=1000)
+
+        #Set results of optimization
+        linesP = na.reshape(fitP,(-1,3))
+
+        #Generate difference between current best fit and data
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+
+        #Sum to get idea of goodness of fit
+        errSq=sum(dif**2)
+
+        #If good enough, break
+        if errSq < errBound: 
+            break
+
+        #If last fit was worse, reject the last line and revert to last fit
+        if errSq > prevErrSq*10:
+            #If its still pretty damn bad, cut losses and try flag fit tools
+            if prevErrSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                yNewFit=_gen_flux_lines(x,prevLinesP,speciesDict)
+                break
+
+        #If too many lines 
+        if na.shape(linesP)[0]>8 or na.size(linesP)+3>=len(x):
+            #If its fitable by flag tools and still bad, use flag tools
+            if errSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                break 
+
+        #Store previous data in case reject next fit
+        prevErrSq = errSq
+        prevLinesP = linesP
+
+
+        #Set up initial condition for new line
+        newP = [0,0,0] 
+        if min(dif)<.1:
+            newP[0]=10**12
+        elif min(dif)>.9:
+            newP[0]=10**16
+        else:
+            newP[0]=10**14
+        newP[1] = speciesDict['init_b']
+        newP[2]=(x[dif.argmax()]-wl0)/wl0
+        linesP=na.append(linesP,[newP],axis=0)
+
+
+    #Check the parameters of all lines to see if they fall in an
+    #   acceptable range, as given in dict ref
+    remove=[]
+    for i,p in enumerate(linesP):
+        check=_check_params(na.array([p]),speciesDict)
+        if check: 
+            remove.append(i)
+    linesP = na.delete(linesP,remove,axis=0)
+
+    return linesP,False
+
+def _large_flag_fit(x, yDat, yFit, initz, speciesDict, minSize, errBound):
+    """
+    Attempts to more robustly fit saturated lyman alpha regions that have
+    not converged to satisfactory fits using the standard tools.
+
+    Uses a preselected sample of a wide range of initial parameter guesses
+    designed to fit saturated lines (see get_test_lines).
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+
+    Returns
+    -------
+    bestP : (3,) ndarray
+        array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]  
+    """
+
+    #Set up some initial line guesses
+    lineTests = _get_test_lines(initz)
+
+    #Keep track of the lowest achieved error
+    bestError = 1000 
+
+    #Iterate through test line guesses
+    for initLines in lineTests:
+        if initLines[1,0]==0:
+            initLines = na.delete(initLines,1,axis=0)
+
+        #Do fitting with initLines as first guess
+        linesP,flag=_complex_fit(x,yDat,yFit,initz,
+                minSize,errBound,speciesDict,initP=initLines)
+
+        #Find error of last fit
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+        errSq=sum(dif**2)
+
+        #If error lower, keep track of the lines used to make that fit
+        if errSq < bestError:
+            bestError = errSq
+            bestP = linesP
+
+    if bestError>10*errBound*len(x): 
+        return []
+    else:
+        return bestP
+
+def _get_test_lines(initz):
+    """
+    Returns a 3d numpy array of lines to test as initial guesses for difficult
+    to fit lyman alpha absorbers that are saturated. 
+    
+    The array is 3d because
+    the first dimension gives separate initial guesses, the second dimension
+    has multiple lines for the same guess (trying a broad line plus a 
+    saturated line) and the 3d dimension contains the 3 fit parameters (N,b,z)
+
+    Parameters
+    ----------
+    initz : float
+        redshift to give all the test lines
+
+    Returns
+    -------
+    testP : (,3,) ndarray
+        numpy array of the form 
+        [[[N1a,b1a,z1a], [N1b,b1b,z1b]], [[N2a,b2,z2a],...] ...]
+    """
+
+    #Set up a bunch of empty lines
+    testP = na.zeros((10,2,3))
+
+    testP[0,0,:]=[1E18,20,initz]
+    testP[1,0,:]=[1E18,40,initz]
+    testP[2,0,:]=[1E16,5, initz]
+    testP[3,0,:]=[1E16,20,initz]
+    testP[4,0,:]=[1E16,80,initz]
+
+    testP[5,0,:]=[1E18,20,initz]
+    testP[6,0,:]=[1E18,40,initz]
+    testP[7,0,:]=[1E16,5, initz]
+    testP[8,0,:]=[1E16,20,initz]
+    testP[9,0,:]=[1E16,80,initz]
+
+    testP[5,1,:]=[1E13,100,initz]
+    testP[6,1,:]=[1E13,100,initz]
+    testP[7,1,:]=[1E13,100,initz]
+    testP[8,1,:]=[1E13,100,initz]
+    testP[9,1,:]=[1E13,100,initz]
+
+    return testP
+
+def _get_bounds(z, b, wl, x0, xRes):
+    """ 
+    Gets the indices of range of wavelength that the wavelength wl is in 
+    with the size of some initial wavelength range.
+
+    Used for checking if species with multiple lines (as in the OVI doublet)
+    fit all lines appropriately.
+
+    Parameters
+    ----------
+    z : float
+        redshift
+    b : (3) ndarray/list
+        initial bounds in form [i0,i1,i2] where i0 is the index of the 
+        minimum flux for the complex, i1 is index of the lower wavelength 
+        edge of the complex, and i2 is the index of the higher wavelength
+        edge of the complex.
+    wl : float
+        unredshifted wavelength of the peak of the new region 
+    x0 : float
+        wavelength of the index 0
+    xRes : float
+        difference in wavelength for two consecutive indices
+    
+    Returns
+    -------
+    indices : (2) tuple
+        Tuple (i1,i2) where i1 is the index of the lower wavelength bound of 
+        the new region and i2 is the index of the higher wavelength bound of
+        the new region
+    """
+
+    r=[-b[1]+100+b[0],b[2]+100-b[0]]
+    redWl = (z+1)*wl
+    iRedWl=int((redWl-x0)/xRes)
+    indices = (iRedWl-r[0],iRedWl+r[1])
+
+    return indices
+
+def _remove_unaccepted_partners(linesP, x, y, b, errBound, 
+        x0, xRes, speciesDict):
+    """
+    Given a set of parameters [N,b,z] that form multiple lines for a given
+    species (as in the OVI doublet), remove any set of parameters where
+    not all transition wavelengths have a line that matches the fit.
+
+    (ex: if a fit is determined based on the first line of the OVI doublet,
+    but the given parameters give a bad fit of the wavelength space of
+    the second line then that set of parameters is removed from the array
+    of line parameters.)
+
+    Parameters
+    ----------
+    linesP : (3,) ndarray
+        array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    x : (N) ndarray
+        wavelength array [nm]
+    y : (N) ndarray
+        normalized flux array of original data
+    b : (3) tuple/list/ndarray
+        indices that give the bounds of the original region so that another 
+        region of similar size can be used to determine the goodness
+        of fit of the other wavelengths
+    errBound : float
+        size of the error that is appropriate for a given region, 
+        adjusted to account for the size of the region.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        array similar to linesP that only contains lines with
+        appropriate fits of all transition wavelengths.
+    """
+
+    #List of lines to remove
+    removeLines=[]
+
+    #Iterate through all sets of line parameters
+    for i,p in enumerate(linesP):
+
+        #iterate over all transition wavelengths
+        for wl in speciesDict['wavelength']:
+
+            #Get the bounds of a similar sized region around the
+            #   appropriate wavelength, and then get the appropriate
+            #   region of wavelength and flux
+            lb = _get_bounds(p[2],b,wl,x0,xRes)
+            xb,yb=x[lb[0]:lb[1]],y[lb[0]:lb[1]]
+
+            #Generate a fit and find the difference to data
+            yFitb=_gen_flux_lines(xb,na.array([p]),speciesDict)
+            dif =yb-yFitb
+
+            #Only counts as an error if line is too big ---------------<
+            dif = [k for k in dif if k>0]
+            err = sum(dif)
+
+            #If the fit is too bad then add the line to list of removed lines
+            if err > errBound*1E2:
+                removeLines.append(i)
+                break
+
+    #Remove all bad line fits
+    linesP = na.delete(linesP,removeLines,axis=0)
+
+    return linesP 
+
+
+
+def _line_exists(wavelengths, y, z, x0, xRes,fluxMin):
+    """For a group of lines finds if the there is some change in flux greater
+    than some minimum at the same redshift with different initial wavelengths
+
+    Parameters
+    ----------
+    wavelengths : (N) ndarray
+        array of initial wavelengths to check
+    y : (N) ndarray
+        flux array to check
+    x0 : float
+        wavelength of the first value in y
+    xRes : float
+        difference in wavelength between consecutive cells in flux array
+    fluxMin : float
+        maximum flux to count as a line existing. 
+
+    Returns
+    -------
+
+    flag : boolean 
+        value indicating whether all lines exist. True if all lines exist
+    """
+
+    #Iterate through initial wavelengths
+    for wl in wavelengths:
+        #Redshifted wavelength
+        redWl = (z+1)*wl
+
+        #Index of the redshifted wavelength
+        indexRedWl = (redWl-x0)/xRes
+
+        #Check if surpasses minimum absorption bound
+        if y[int(indexRedWl)]>fluxMin:
+            return False
+
+    return True
+
+def _find_complexes(x, yDat, complexLim=.999, fitLim=.99,
+        minLength =3, maxLength=1000, splitLim=.99):
+    """Breaks up the wavelength space into groups
+    where there is some absorption. 
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelengths
+    yDat : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+
+    Returns
+    -------
+    cBounds : (3,) 
+        list of bounds in the form [[i0,i1,i2],...] where i0 is the 
+        index of the maximum flux for a complex, i1 is the index of the
+        beginning of the complex, and i2 is the index of the end of the 
+        complex. Indexes refer to the indices of x and yDat.
+    """
+
+    #Initialize empty list of bounds
+    cBounds=[]
+
+    #Iterate through cells of flux
+    i=0
+    while (i<len(x)):
+
+        #Start tracking at a region that surpasses flux of edge
+        if yDat[i]<complexLim:
+
+            #Iterate through until reach next edge
+            j=0
+            while yDat[i+j]<complexLim: j=j+1
+
+            #Check if the complex is big enough
+            if j >minLength:
+
+                #Check if there is enough absorption for the complex to
+                #   be included
+                cPeak = yDat[i:i+j].argmin()
+                if yDat[cPeak+i]<fitLim:
+                    cBounds.append([cPeak+i,i,i+j])
+
+            i=i+j
+        i=i+1
+
+    i=0
+    #Iterate through the bounds
+    while i < len(cBounds):
+        b=cBounds[i]
+
+        #Check if the region needs to be divided
+        if b[2]-b[1]>maxLength:
+
+            #Find the minimum absorption in the middle two quartiles of
+            #   the large complex
+            q=(b[2]-b[1])/4
+            cut = yDat[b[1]+q:b[2]-q].argmax()+b[1]+q
+
+            #Only break it up if the minimum absorption is actually low enough
+            if yDat[cut]>splitLim:
+
+                #Get the new two peaks
+                b1Peak = yDat[b[1]:cut].argmin()+b[1]
+                b2Peak = yDat[cut:b[2]].argmin()+cut
+
+                #add the two regions separately
+                cBounds.insert(i+1,[b1Peak,b[1],cut])
+                cBounds.insert(i+2,[b2Peak,cut,b[2]])
+
+                #Remove the original region
+                cBounds.pop(i)
+                i=i+1
+        i=i+1
+
+    return cBounds
+
+def _gen_flux_lines(x, linesP, speciesDict):
+    """
+    Calculates the normalized flux for a region of wavelength space
+    generated by a set of absorption lines.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        Array of wavelength
+    linesP: (3,) ndarray
+        Array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    speciesDict : dictionary
+        Dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+
+    Returns
+    -------
+    flux : (N) ndarray
+        Array of normalized flux generated by the line parameters
+        given in linesP over the wavelength space given in x. Same size as x.
+    """
+    y=0
+    for p in linesP:
+        for i in range(speciesDict['numLines']):
+            f=speciesDict['f'][i]
+            g=speciesDict['Gamma'][i]
+            wl=speciesDict['wavelength'][i]
+            y = y+ _gen_tau(x,p,f,g,wl)
+    flux = na.exp(-y)
+    return flux
+
+def _gen_tau(t, p, f, Gamma, lambda_unshifted):
+    """This calculates a flux distribution for given parameters using the yt
+    voigt profile generator"""
+    N,b,z= p
+    
+    #Calculating quantities
+    tau_o = 1.4973614E-15*N*f*lambda_unshifted/b
+    a=7.95774715459E-15*Gamma*lambda_unshifted/b
+    x=299792.458/b*(lambda_unshifted*(1+z)/t-1)
+    
+    H = na.zeros(len(x))
+    H = voigt(a,x)
+    
+    tau = tau_o*H
+
+    return tau
+
+def _voigt_error(pTotal, x, yDat, yFit, speciesDict):
+    """
+    Gives the error of each point  used to optimize the fit of a group
+        of absorption lines to a given flux profile.
+
+        If the parameters are not in the acceptable range as defined
+        in speciesDict, the first value of the error array will
+        contain a large value (999), to prevent the optimizer from running
+        into negative number problems.
+
+    Parameters
+    ----------
+    pTotal : (3,) ndarray 
+        Array with form [[N1, b1, z1], ...] 
+    x : (N) ndarray
+        array of wavelengths [nm]
+    yDat : (N) ndarray
+        desired normalized flux from fits of lines in wavelength
+        space given by x
+    yFit : (N) ndarray
+        previous fit over the wavelength space given by x.
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+
+    Returns
+    -------
+    error : (N) ndarray
+        the difference between the fit generated by the parameters
+        given in pTotal multiplied by the previous fit and the desired
+        flux profile, w/ first index modified appropriately for bad 
+        parameter choices
+    """
+
+    pTotal.shape = (-1,3)
+    yNewFit = _gen_flux_lines(x,pTotal,speciesDict)
+
+    error = yDat-yFit*yNewFit
+    error[0] = _check_params(pTotal,speciesDict)
+
+    return error
+
+def _check_params(p, speciesDict):
+    """
+    Check to see if any of the parameters in p fall outside the range 
+        given in speciesDict.
+
+    Parameters
+    ----------
+    p : (3,) ndarray
+        array with form [[N1, b1, z1], ...] 
+    speciesDict : dictionary
+        dictionary with properties giving the max and min
+        values appropriate for each parameter N,b, and z.
+
+    Returns
+    -------
+    check : int
+        0 if all values are fine
+        999 if any values fall outside acceptable range
+    """
+    check = 0
+    if any(p[:,0] > speciesDict['maxN']) or\
+          any(p[:,0] < speciesDict['minN']) or\
+          any(p[:,1] > speciesDict['maxb']) or\
+          any(p[:,1] < speciesDict['minb']) or\
+          any(p[:,2] > speciesDict['maxz']) or\
+          any(p[:,2] < speciesDict['minz']):
+              check = 999
+    return check
+
+
+def _output_fit(lineDic, file_name = 'spectrum_fit.h5'):
+    """
+    This function is designed to output the parameters of the series
+    of lines used to fit an absorption spectrum. 
+
+    The dataset contains entries in the form species/N, species/b
+    species/z, and species/complex. The ith entry in each of the datasets
+    is the fitted parameter for the ith line fitted to the spectrum for
+    the given species. The species names come from the fitted line
+    dictionary.
+
+    Parameters
+    ----------
+    lineDic : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. 
+    fileName : string, optional
+        Name of the file to output fit to. Default = 'spectrum_fit.h5'
+
+    """
+    f = h5py.File(file_name, 'w')
+    for ion, params in lineDic.iteritems():
+        f.create_dataset("{0}/N".format(ion),data=params['N'])
+        f.create_dataset("{0}/b".format(ion),data=params['b'])
+        f.create_dataset("{0}/z".format(ion),data=params['z'])
+        f.create_dataset("{0}/complex".format(ion),data=params['group#'])
+    print 'Writing spectrum fit to {0}'.format(file_name)
+

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/analysis_modules/absorption_spectrum/api.py
--- a/yt/analysis_modules/absorption_spectrum/api.py
+++ b/yt/analysis_modules/absorption_spectrum/api.py
@@ -30,3 +30,6 @@
 
 from .absorption_spectrum import \
     AbsorptionSpectrum
+
+from .absorption_spectrum_fit import \
+    generate_total_fit

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -28,7 +28,7 @@
 import ConfigParser, os, os.path, types
 
 ytcfgDefaults = dict(
-    serialize = 'True',
+    serialize = 'False',
     onlydeserialize = 'False',
     timefunctions = 'False',
     logfile = 'False',
@@ -62,7 +62,7 @@
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
-    gold_standard_filename = 'gold008',
+    gold_standard_filename = 'gold009',
     local_standard_filename = 'local001',
     sketchfab_api_key = 'None',
     thread_field_detection = 'False'

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -8,7 +8,7 @@
 def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
-    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -86,8 +86,11 @@
         if not os.path.exists(apath): raise IOError(filename)
         if apath not in _cached_pfs:
             obj = object.__new__(cls)
-            _cached_pfs[apath] = obj
-        return _cached_pfs[apath]
+            if obj._skip_cache is False:
+                _cached_pfs[apath] = obj
+        else:
+            obj = _cached_pfs[apath]
+        return obj
 
     def __init__(self, filename, data_style=None, file_style=None):
         """
@@ -157,6 +160,10 @@
     def _mrep(self):
         return MinimalStaticOutput(self)
 
+    @property
+    def _skip_cache(self):
+        return False
+
     def hub_upload(self):
         self._mrep.upload()
 

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -753,6 +753,8 @@
         rdw = radius.copy()
     for i, ax in enumerate('xyz'):
         np.subtract(data["%s%s" % (field_prefix, ax)], center[i], r)
+        if data.pf.dimensionality < i+1:
+            break
         if data.pf.periodicity[i] == True:
             np.abs(r, r)
             np.subtract(r, DW[i], rdw)

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    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 "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:
@@ -309,6 +308,10 @@
         self.grid_left_edge = np.round(self.parameter_file.domain_left_edge + dx*glis, decimals=6)
         self.grid_dimensions = gdims.astype("int32")
         self.grid_right_edge = np.round(self.grid_left_edge + dx*self.grid_dimensions, decimals=6)
+        if self.parameter_file.dimensionality <= 2:
+            self.grid_right_edge[:,2] = self.parameter_file.domain_right_edge[2]
+        if self.parameter_file.dimensionality == 1:
+            self.grid_right_edge[:,1:] = self.parameter_file.domain_right_edge[1:]
         self.grid_particle_count = np.zeros([self.num_grids, 1], dtype='int64')
 
     def _populate_grid_objects(self):
@@ -335,7 +338,9 @@
     _data_style = "athena"
 
     def __init__(self, filename, data_style='athena',
-                 storage_filename=None, parameters={}):
+                 storage_filename=None, parameters=None):
+        if parameters is None:
+            parameters = {}
         self.specified_parameters = parameters
         StaticOutput.__init__(self, filename, data_style)
         self.filename = filename
@@ -467,6 +472,10 @@
             pass
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
     def __repr__(self):
         return self.basename.rsplit(".", 1)[0]
 

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/frontends/athena/fields.py
--- a/yt/frontends/athena/fields.py
+++ b/yt/frontends/athena/fields.py
@@ -128,15 +128,16 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]/(data.pf["Gamma"]-1.0)/data["density"]
     else:
-        return (data["total_energy"] - 
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) - 
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])/data["density"]
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint/data["density"]
 add_field("Gas_Energy", function=_gasenergy, take_log=False,
-          units=r"\rm{erg}/\rm{g}")
+          convert_function=_convertEnergy, units=r"\rm{erg}/\rm{g}")
 
 def _convertPressure(data) :
     return data.convert("Density")*data.convert("x-velocity")**2
@@ -144,15 +145,17 @@
     if "pressure" in data.pf.field_info:
         return data["pressure"]
     else:
-        return (data["total_energy"] -
-                0.5*(data["cell_centered_B_x"]**2 +
-                     data["cell_centered_B_y"]**2 +
-                     data["cell_centered_B_z"]**2) -
-                0.5*(data["momentum_x"]**2 +
-                     data["momentum_y"]**2 +
-                     data["momentum_z"]**2)/data["density"])*(data.pf["Gamma"]-1.0)
-add_field("Pressure", function=_pressure, take_log=False, convert_function=_convertPressure,
-          units=r"\rm{erg}/\rm{cm}^3", projected_units=r"\rm{erg}/\rm{cm}^2")
+        eint = data["total_energy"] - 0.5*(data["momentum_x"]**2 +
+                                           data["momentum_y"]**2 +
+                                           data["momentum_z"]**2)/data["density"]
+        if "cell_centered_B_x" in data.pf.field_info:
+            eint -= 0.5*(data["cell_centered_B_x"]**2 +
+                         data["cell_centered_B_y"]**2 +
+                         data["cell_centered_B_z"]**2)
+        return eint*(data.pf["Gamma"]-1.0)
+add_field("Pressure", function=_pressure, take_log=False,
+          convert_function=_convertPressure, units=r"\rm{erg}/\rm{cm}^3",
+          projected_units=r"\rm{erg}/\rm{cm}^2")
 
 def _temperature(field, data):
     if data.has_field_parameter("mu"):

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/frontends/enzo/io.py
--- a/yt/frontends/enzo/io.py
+++ b/yt/frontends/enzo/io.py
@@ -115,6 +115,7 @@
                 if g.NumberOfParticles == 0: continue
                 x, y, z = (data[g.id].pop("particle_position_%s" % ax)
                            for ax in 'xyz')
+                x, y, z = (np.array(arr, dtype='float64') for arr in (x, y, z))
                 size += g.count_particles(selector, x, y, z)
         read_fields = fields[:]
         for field in fields:
@@ -132,6 +133,7 @@
                 if g.NumberOfParticles == 0: continue
                 x, y, z = (data[g.id]["particle_position_%s" % ax]
                            for ax in 'xyz')
+                x, y, z = (np.array(arr, dtype='float64') for arr in (x, y, z))
                 mask = g.select_particles(selector, x, y, z)
                 if mask is None: continue
                 for field in set(fields):

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/frontends/flash/fields.py
--- a/yt/frontends/flash/fields.py
+++ b/yt/frontends/flash/fields.py
@@ -367,5 +367,21 @@
 
 
 def _abar(field, data):
-    return 1.0 / data['sumy']
+    try:
+        return 1.0 / data['sumy']
+    except:
+        pass
+    return data['dens']*Na*kboltz*data['temp']/data['pres']
 add_field('abar', function=_abar, take_log=False)
+	
+
+def _NumberDensity(fields,data) :
+    try:
+        return data["nele"]+data["nion"]
+    except:
+        pass
+    return data['pres']/(data['temp']*kboltz)
+add_field("NumberDensity", function=_NumberDensity,
+        units=r'\rm{cm}^{-3}')
+
+

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -308,6 +308,10 @@
     def _is_valid(cls, *args, **kwargs):
         return False
 
+    @property
+    def _skip_cache(self):
+        return True
+
 class StreamDictFieldHandler(dict):
 
     @property

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -28,7 +28,7 @@
 import contextlib
 import warnings, struct, subprocess
 import numpy as np
-from distutils import version
+from distutils.version import LooseVersion
 from math import floor, ceil
 
 from yt.utilities.exceptions import *
@@ -250,6 +250,17 @@
      %(filename)s:%(lineno)s
 """
 
+def get_ipython_api_version():
+    import IPython
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
+        api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
+    else:
+        api_version = '1.0'
+
+    return api_version
+
 def insert_ipython(num_up=1):
     """
     Placed inside a function, this will insert an IPython interpreter at that
@@ -259,11 +270,7 @@
     defaults to 1 so that this function itself is stripped off.
     """
 
-    import IPython
-    if version.LooseVersion(IPython.__version__) <= version.LooseVersion('0.10'):
-        api_version = '0.10'
-    else:
-        api_version = '0.11'
+    api_version = get_ipython_api_version()
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]
@@ -281,7 +288,10 @@
         cfg.InteractiveShellEmbed.local_ns = loc
         cfg.InteractiveShellEmbed.global_ns = glo
         IPython.embed(config=cfg, banner2 = __header % dd)
-        from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        if api_version == '0.11':
+            from IPython.frontend.terminal.embed import InteractiveShellEmbed
+        else:
+            from IPython.terminal.embed import InteractiveShellEmbed
         ipshell = InteractiveShellEmbed(config=cfg)
 
     del ipshell

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/startup_tasks.py
--- a/yt/startup_tasks.py
+++ b/yt/startup_tasks.py
@@ -36,9 +36,11 @@
 def turn_on_parallelism():
     try:
         from mpi4py import MPI
-        parallel_capable = (MPI.COMM_WORLD.size > 1)
-    except ImportError:
-        parallel_capable = False
+    except ImportError as e:
+        mylog.error("Warning: Attempting to turn on parallelism, " +
+                    "but mpi4py import failed. Try pip install mpi4py.")
+        raise e
+    parallel_capable = (MPI.COMM_WORLD.size > 1)
     if parallel_capable:
         mylog.info("Global parallel computation enabled: %s / %s",
                    MPI.COMM_WORLD.rank, MPI.COMM_WORLD.size)

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/utilities/amr_kdtree/amr_kdtree.py
--- a/yt/utilities/amr_kdtree/amr_kdtree.py
+++ b/yt/utilities/amr_kdtree/amr_kdtree.py
@@ -89,7 +89,8 @@
         for lvl in lvl_range:
             #grids = self.data_source.select_grids(lvl)
             grids = np.array([b for b, mask in self.data_source.blocks if b.Level == lvl])
-            if len(grids) == 0: continue
+            gids = np.array([g.id for g in grids if g.Level == lvl],
+                            dtype="int64")
             self.add_grids(grids)
 
     def check_tree(self):

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -270,7 +270,7 @@
     with temp_cwd(path):
         try:
             load(pf_fn)
-        except:
+        except YTOutputNotIdentified:
             return False
     return AnswerTestingTest.result_storage is not None
 

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/utilities/command_line.py
--- a/yt/utilities/command_line.py
+++ b/yt/utilities/command_line.py
@@ -1456,7 +1456,12 @@
         """
     def __call__(self, args):
         kwargs = {}
-        from IPython.frontend.html.notebook.notebookapp import NotebookApp
+        try:
+            # IPython 1.0+
+            from IPython.html.notebookapp import NotebookApp
+        except ImportError:
+            # pre-IPython v1.0
+            from IPython.frontend.html.notebook.notebookapp import NotebookApp
         pw = ytcfg.get("yt", "notebook_password")
         if len(pw) == 0 and not args.no_password:
             import IPython.lib

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -58,6 +58,15 @@
     double sin(double x) nogil
     double sqrt(double x) nogil
 
+ctypedef void sampler_function(
+                VolumeContainer *vc,
+                np.float64_t v_pos[3],
+                np.float64_t v_dir[3],
+                np.float64_t enter_t,
+                np.float64_t exit_t,
+                int index[3],
+                void *data) nogil
+
 cdef class PartitionedGrid:
     cdef public object my_data
     cdef public object source_mask 
@@ -223,7 +232,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function *sampler
+    cdef sampler_function *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -921,7 +930,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function *sampler,
+                     sampler_function *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -1,15 +1,16 @@
 #
 # Physical Constants and Units Conversion Factors
 #
-# Values for these constants are drawn from IAU and IUPAC data 
-# unless otherwise noted:
+# Values for these constants, unless otherwise noted, are drawn from IAU,
+# IUPAC, and NIST data, whichever is newer.
 # http://maia.usno.navy.mil/NSFA/IAU2009_consts.html
 # http://goldbook.iupac.org/list_goldbook_phys_constants_defs.html
+# http://physics.nist.gov/cuu/Constants/index.html
 
 # Masses
-mass_hydrogen_cgs = 1.674534e-24  # g
-mass_electron_cgs = 9.1093898e-28  # g
-amu_cgs           = 1.6605402e-24  # g
+mass_electron_cgs = 9.109382-28  # g
+amu_cgs           = 1.660538921e-24  # g
+mass_hydrogen_cgs = 1.007947*amu_cgs  # g
 mass_sun_cgs = 1.98841586e33  # g
 # Velocities
 speed_of_light_cgs = 2.99792458e10  # cm/s, exact
@@ -22,10 +23,10 @@
 charge_proton_cgs = 4.8032056e-10  # esu = 1.602176487e-19  Coulombs
 
 # Physical Constants
-boltzmann_constant_cgs = 1.3806504e-16  # erg K^-1
-gravitational_constant_cgs  = 6.67428e-8  # cm^3 g^-1 s^-2
-planck_constant_cgs   = 6.62606896e-27  # erg s
-stefan_boltzmann_constant_cgs = 5.67051e-5 # erg cm^-2 s^-1 K^-4
+boltzmann_constant_cgs = 1.3806488e-16  # erg K^-1
+gravitational_constant_cgs  = 6.67384e-8  # cm^3 g^-1 s^-2
+planck_constant_cgs   = 6.62606957e-27  # erg s
+stefan_boltzmann_constant_cgs = 5.670373e-5 # erg cm^-2 s^-1 K^-4
 # The following value was calcualted assuming H = 100 km/s/Mpc.
 # To get the correct value for your cosmological parameters, 
 # you'll need to multiply through by h^2
@@ -69,16 +70,17 @@
 cm_per_pc     = 1.0 / pc_per_cm
 
 # time
+# "IAU Style Manual" by G.A. Wilkins, Comm. 5, in IAU Transactions XXB (1989)
 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_year = 31.5576e6
 sec_per_day  = 86400.0
 sec_per_hr   = 3600.0
 day_per_year = 365.25
 
 # temperature / energy
-erg_per_eV = 1.602176487e-12 # http://goldbook.iupac.org/E02014.html
+erg_per_eV = 1.602176562e-12
 erg_per_keV = erg_per_eV * 1.0e3
 K_per_keV = erg_per_keV / boltzmann_constant_cgs
 keV_per_K = 1.0 / K_per_keV

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -23,6 +23,7 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 import matplotlib
+import cStringIO
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
@@ -33,12 +34,20 @@
     """A base class for all yt plots made using matplotlib.
 
     """
-    def __init__(self, fsize, axrect):
+    def __init__(self, fsize, axrect, figure, axes):
         """Initialize PlotMPL class"""
         self._plot_valid = True
-        self.figure = matplotlib.figure.Figure(figsize=fsize,
-                                               frameon=True)
-        self.axes = self.figure.add_axes(axrect)
+        if figure is None:
+            self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True)
+        else:
+            figure.set_size_inches(fsize)
+            self.figure = figure
+        if axes is None:
+            self.axes = self.figure.add_axes(axrect)
+        else:
+            axes.cla()
+            self.axes = axes
+        self.canvas = FigureCanvasAgg(self.figure)
 
     def save(self, name, mpl_kwargs, canvas=None):
         """Choose backend and save image to disk"""
@@ -57,7 +66,7 @@
             canvas = FigureCanvasPS(self.figure)
         else:
             mylog.warning("Unknown suffix %s, defaulting to Agg", suffix)
-            canvas = FigureCanvasAgg(self.figure)
+            canvas = self.canvas
 
         canvas.print_figure(name, **mpl_kwargs)
         return name
@@ -67,13 +76,18 @@
     """A base class for yt plots made using imshow
 
     """
-    def __init__(self, fsize, axrect, caxrect, zlim):
+    def __init__(self, fsize, axrect, caxrect, zlim, figure, axes, cax):
         """Initialize ImagePlotMPL class object"""
-        PlotMPL.__init__(self, fsize, axrect)
+        PlotMPL.__init__(self, fsize, axrect, figure, axes)
         self.zmin, self.zmax = zlim
-        self.cax = self.figure.add_axes(caxrect)
+        if cax is None:
+            self.cax = self.figure.add_axes(caxrect)
+        else:
+            cax.cla()
+            cax.set_position(caxrect)
+            self.cax = cax
 
-    def _init_image(self, data, cbnorm, cmap, extent, aspect=None):
+    def _init_image(self, data, cbnorm, cmap, extent, aspect):
         """Store output of imshow in image variable"""
         if (cbnorm == 'log10'):
             norm = matplotlib.colors.LogNorm()

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -52,7 +52,7 @@
 from yt.utilities.delaunay.triangulate import Triangulation as triang
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
-    fix_axis, get_image_suffix
+    fix_axis, get_image_suffix, get_ipython_api_version
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
     x_dict, y_dict, \
@@ -90,6 +90,17 @@
         return rv
     return newfunc
 
+def invalidate_figure(f):
+    @wraps(f)
+    def newfunc(*args, **kwargs):
+        rv = f(*args, **kwargs)
+        for field in args[0].fields:
+            args[0].plots[field].figure = None
+            args[0].plots[field].axes = None
+            args[0].plots[field].cax = None
+        return rv
+    return newfunc
+
 def invalidate_plot(f):
     @wraps(f)
     def newfunc(*args, **kwargs):
@@ -399,7 +410,7 @@
         nWx, nWy = Wx/factor, Wy/factor
         self.xlim = (centerx - nWx*0.5, centerx + nWx*0.5)
         self.ylim = (centery - nWy*0.5, centery + nWy*0.5)
-
+        return self
 
     @invalidate_data
     def pan(self, deltas):
@@ -413,6 +424,7 @@
         """
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
+        return self
 
     @invalidate_data
     def pan_rel(self, deltas):
@@ -427,6 +439,7 @@
         Wx, Wy = self.width
         self.xlim = (self.xlim[0] + Wx*deltas[0], self.xlim[1] + Wx*deltas[0])
         self.ylim = (self.ylim[0] + Wy*deltas[1], self.ylim[1] + Wy*deltas[1])
+        return self
 
     @invalidate_data
     def set_window(self, bounds):
@@ -563,6 +576,7 @@
             self.buff_size = (size, size)
 
     @invalidate_plot
+    @invalidate_figure
     def set_window_size(self, size):
         """Sets a new window size for the plot
 
@@ -904,9 +918,19 @@
 
             fp = self._font_properties
 
+            fig = None
+            axes = None
+            cax = None
+            if self.plots.has_key(f):
+                if self.plots[f].figure is not None:
+                    fig = self.plots[f].figure
+                    axes = self.plots[f].axes
+                    cax = self.plots[f].cax
+
             self.plots[f] = WindowPlotMPL(image, self._field_transform[f].name,
                                           self._colormaps[f], extent, aspect,
-                                          zlim, size, fp.get_size())
+                                          zlim, size, fp.get_size(), fig, axes,
+                                          cax)
 
             axes_unit_labels = ['', '']
             for i, un in enumerate((unit_x, unit_y)):
@@ -973,6 +997,7 @@
                 del self._frb[key]
 
     @invalidate_plot
+    @invalidate_figure
     def set_font(self, font_dict=None):
         """set the font and font properties
 
@@ -1130,7 +1155,12 @@
 
         """
         if "__IPYTHON__" in dir(__builtin__):
-            self._send_zmq()
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                from IPython.display import display
+                display(self)
         else:
             raise YTNotInsideNotebook
 
@@ -1142,6 +1172,15 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        ret = ''
+        for field in self.plots:
+            img = base64.b64encode(self.plots[field]._repr_png_())
+            ret += '<img src="data:image/png;base64,%s"><br>' % img
+        return ret
+
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file
 
@@ -1164,11 +1203,9 @@
          The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center',
              or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1280,12 +1317,9 @@
         The name of the field(s) to be plotted.
     center : two or three-element vector of sequence floats, 'c', or 'center',
              or 'max'
-         The coordinate of the center of the image.  If left blank,
-         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.
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
          Width can have four different formats to support windows with variable
          x and y widths.  They are:
 
@@ -1401,11 +1435,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center will be at 
+         the point of highest density.
     width : A tuple or a float
         A tuple containing the width of image and the string key of
         the unit: (width, 'unit').  If set to a float, code units
@@ -1494,11 +1528,11 @@
         The vector normal to the slicing plane.
     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 blank,
-        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, or one of 'c', 
+         'center', 'max' or 'm'. The coordinate of the center of the image. 
+         If set to 'c', 'center' or left blank, the plot is centered on the
+         middle of the domain. If set to 'max' or 'm', the center 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:
@@ -1806,8 +1840,9 @@
             self._field_transform[field] = linear_transform
 
 class WindowPlotMPL(ImagePlotMPL):
-    def __init__(self, data, cbname, cmap, extent, aspect, zlim, size,
-                 fontsize):
+    def __init__(
+            self, data, cbname, cmap, extent, aspect, zlim, size, fontsize,
+                figure, axes, cax):
         fsize, axrect, caxrect = self._get_best_layout(size, fontsize)
         if np.any(np.array(axrect) < 0):
             msg = 'The axis ratio of the requested plot is very narrow. ' \
@@ -1817,7 +1852,8 @@
             mylog.warn(msg)
             axrect  = (0.07, 0.10, 0.80, 0.80)
             caxrect = (0.87, 0.10, 0.04, 0.80)
-        ImagePlotMPL.__init__(self, fsize, axrect, caxrect, zlim)
+        ImagePlotMPL.__init__(
+            self, fsize, axrect, caxrect, zlim, figure, axes, cax)
         self._init_image(data, cbname, cmap, extent, aspect)
         self.image.axes.ticklabel_format(scilimits=(-2,3))
         if cbname == 'linear':

diff -r 94a623c5561291e621cb984d6716493aa9535478 -r 0f157d8055c439fe1251710756d600308c6a141c yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -542,7 +542,7 @@
                 (-self.width[0]/2.0, self.width[0]/2.0,
                  -self.width[1]/2.0, self.width[1]/2.0),
                 image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.transfer_function, self.sub_samples)
+                np.array(self.width, dtype='float64'), self.transfer_function, self.sub_samples)
         return args
 
     star_trees = None
@@ -2159,10 +2159,10 @@
     def get_sampler_args(self, image):
         rotp = np.concatenate([self.orienter.inv_mat.ravel('F'), self.back_center.ravel()])
         args = (rotp, self.box_vectors[2], self.back_center,
-            (-self.width[0]/2, self.width[0]/2,
-             -self.width[1]/2, self.width[1]/2),
+            (-self.width[0]/2., self.width[0]/2.,
+             -self.width[1]/2., self.width[1]/2.),
             image, self.orienter.unit_vectors[0], self.orienter.unit_vectors[1],
-                np.array(self.width), self.sub_samples)
+                np.array(self.width, dtype='float64'), self.sub_samples)
         return args
 
     def finalize_image(self,image):


https://bitbucket.org/yt_analysis/yt-3.0/commits/b52c0bef2ef5/
Changeset:   b52c0bef2ef5
Branch:      yt-3.0
User:        drudd
Date:        2013-07-31 00:18:21
Summary:     Removed eterm option from select_cell
Affected #:  2 files

diff -r d5dcab54f8f06a104ef931b259dfd79940a1a085 -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -43,8 +43,7 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = ?) nogil
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil

diff -r d5dcab54f8f06a104ef931b259dfd79940a1a085 -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -195,9 +195,7 @@
         res = self.select_grid(LE, RE, level, root)
         if res == 1 and data.domain > 0 and root.domain != data.domain:
             res = -1
-        cdef int eterm[3] 
         cdef int increment = 1
-        eterm[0] = eterm[1] = eterm[2] = 0
         cdef int next_level, this_level
         # next_level: an int that says whether or not we can progress to children
         # this_level: an int that says whether or not we can select from this
@@ -241,7 +239,7 @@
                             data.pos[2] = (data.pos[2] >> 1)
                             data.level -= 1
                         elif this_level == 1:
-                            selected = self.select_cell(spos, sdds, eterm)
+                            selected = self.select_cell(spos, sdds)
                             if ch != NULL:
                                 selected *= self.overlap_cells
                             data.global_index += increment
@@ -261,8 +259,7 @@
                                np.int32_t level, Oct *o = NULL) nogil:
         return 0
     
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 0
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil:
@@ -312,7 +309,6 @@
         cdef int this_level = 0
         if level == self.max_level:
             this_level = 1
-        cdef int eterm[3]
         self.set_bounds(<np.float64_t *> left_edge.data,
                         <np.float64_t *> right_edge.data,
                         dds, ind, &check)
@@ -320,20 +316,14 @@
             if check == 1:
                 pos[0] = left_edge[0] + dds[0] * 0.5
                 for i in range(ind[0][0], ind[0][1]):
-                    eterm[0] = 0
                     pos[1] = left_edge[1] + dds[1] * 0.5
                     for j in range(ind[1][0], ind[1][1]):
-                        eterm[1] = 0
                         pos[2] = left_edge[2] + dds[2] * 0.5
                         for k in range(ind[2][0], ind[2][1]):
-                            eterm[2] = 0
                             if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += self.select_cell(pos, dds, eterm)
-                            if eterm[2] == 1: break
+                                count += self.select_cell(pos, dds)
                             pos[2] += dds[1]
-                        if eterm[1] == 1: break
                         pos[1] += dds[1]
-                    if eterm[0] == 1: break
                     pos[0] += dds[0]
             else:
                 for i in range(ind[0][0], ind[0][1]):
@@ -363,7 +353,6 @@
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
         cdef int check = 1
         cdef int total = 0
-        cdef int eterm[3]
         self.set_bounds(<np.float64_t *> left_edge.data,
                         <np.float64_t *> right_edge.data,
                         dds, ind, &check)
@@ -380,21 +369,15 @@
             if check == 1:
                 pos[0] = left_edge[0] + dds[0] * 0.5
                 for i in range(ind[0][0], ind[0][1]):
-                    eterm[0] = 0
                     pos[1] = left_edge[1] + dds[1] * 0.5
                     for j in range(ind[1][0], ind[1][1]):
-                        eterm[1] = 0
                         pos[2] = left_edge[2] + dds[2] * 0.5
                         for k in range(ind[2][0], ind[2][1]):
-                            eterm[2] = 0
                             if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = self.select_cell(pos, dds, eterm)
+                                mask[i,j,k] = self.select_cell(pos, dds)
                                 total += mask[i,j,k]
-                            if eterm[2] == 1: break
                             pos[2] += dds[1]
-                        if eterm[1] == 1: break
                         pos[1] += dds[1]
-                    if eterm[0] == 1: break
                     pos[0] += dds[0]
             else:
                 for i in range(ind[0][0], ind[0][1]):
@@ -494,8 +477,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         # sphere center either inside cell or center of cell lies inside sphere
         if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
             pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
@@ -587,14 +569,12 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         cdef int i
         cdef np.float64_t dxp
         for i in range(3):
             dxp = self.dx_pad * dds[i]
             if pos[i] - dxp >= self.right_edge[i]:
-                eterm[i] = 1
                 return 0
             if pos[i] + dxp <= self.left_edge[i]: return 0
         return 1
@@ -666,8 +646,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return self.select_point( pos ) 
 
     @cython.boundscheck(False)
@@ -771,8 +750,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         cdef np.float64_t left_edge[3]
         cdef np.float64_t right_edge[3]
         cdef int i
@@ -865,8 +843,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if pos[self.axis] + 0.5*dds[self.axis] > self.coord \
            and pos[self.axis] - 0.5*dds[self.axis] <= self.coord:
             return 1
@@ -922,8 +899,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
            self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
            self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax] and \
@@ -1215,8 +1191,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return self.select_point(pos)
 
     @cython.boundscheck(False)
@@ -1317,8 +1292,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_point(self, np.float64_t pos[3] ) nogil:
@@ -1359,8 +1333,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],
@@ -1410,8 +1383,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],
@@ -1451,8 +1423,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],


https://bitbucket.org/yt_analysis/yt-3.0/commits/e3b131318ef0/
Changeset:   e3b131318ef0
Branch:      yt-3.0
User:        drudd
Date:        2013-08-06 00:42:40
Summary:     Merged with MattTurk's selector_generalize
Affected #:  23 files

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -497,10 +497,13 @@
     def _fill_fields(self, fields):
         output_fields = [np.zeros(self.ActiveDimensions, dtype="float64")
                          for field in fields]
+        domain_dims = self.pf.domain_dimensions.astype("int64") \
+                    * self.pf.refine_by**self.level
         for chunk in self._data_source.chunks(fields, "io"):
             input_fields = [chunk[field] for field in fields]
             fill_region(input_fields, output_fields, self.level,
-                        self.global_startindex, chunk.icoords, chunk.ires)
+                        self.global_startindex, chunk.icoords, chunk.ires,
+                        domain_dims, self.pf.refine_by)
         for name, v in zip(fields, output_fields):
             self[name] = v
 
@@ -653,13 +656,14 @@
     def _fill_fields(self, fields):
         ls = self._initialize_level_state(fields)
         for level in range(self.level + 1):
-            tot = 0
+            domain_dims = self.pf.domain_dimensions.astype("int64") \
+                        * self.pf.refine_by**level
             for chunk in ls.data_source.chunks(fields, "io"):
                 chunk[fields[0]]
                 input_fields = [chunk[field] for field in fields]
-                tot += fill_region(input_fields, ls.fields, ls.current_level,
+                fill_region(input_fields, ls.fields, ls.current_level,
                             ls.global_startindex, chunk.icoords,
-                            chunk.ires)
+                            chunk.ires, domain_dims, self.pf.refine_by)
             self._update_level_state(ls)
         for name, v in zip(fields, ls.fields):
             if self.level > 0: v = v[1:-1,1:-1,1:-1]
@@ -703,7 +707,7 @@
         new_fields = []
         for input_field in level_state.fields:
             output_field = np.zeros(output_dims, dtype="float64")
-            output_left = self.global_startindex + 0.5
+            output_left = level_state.global_startindex + 0.5
             ghost_zone_interpolate(rf, input_field, input_left,
                                    output_field, output_left)
             new_fields.append(output_field)

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -489,14 +489,15 @@
         op.initialize()
         op.process_grid(self, positions, fields)
         vals = op.finalize()
+        if vals is None: return
         return vals.reshape(self.ActiveDimensions, order="C")
 
     def _get_selector_mask(self, selector):
-        if id(selector) == self._last_selector_id:
+        if hash(selector) == self._last_selector_id:
             mask = self._last_mask
         else:
             self._last_mask = mask = selector.fill_mask(self)
-            self._last_selector_id = id(selector)
+            self._last_selector_id = hash(selector)
             if mask is None:
                 self._last_count = 0
             else:

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -121,6 +121,7 @@
         op.process_octree(self.oct_handler, self.domain_ind, positions, fields,
             self.domain_id, self._domain_offset)
         vals = op.finalize()
+        if vals is None: return
         return np.asfortranarray(vals)
 
     def select_icoords(self, dobj):
@@ -161,7 +162,7 @@
         return n
 
     def count(self, selector):
-        if id(selector) == self._last_selector_id:
+        if hash(selector) == self._last_selector_id:
             if self._last_mask is None: return 0
             return self._last_mask.sum()
         self.select(selector)

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/particle_fields.py
--- a/yt/data_objects/particle_fields.py
+++ b/yt/data_objects/particle_fields.py
@@ -113,6 +113,19 @@
             particle_type = True,
             units = r"\mathrm{M}_\odot")
 
+    def particle_mesh_ids(field, data):
+        pos = data[ptype, coord_name]
+        ids = np.zeros(pos.shape[0], dtype="float64") - 1
+        # This is float64 in name only.  It will be properly cast inside the
+        # deposit operation.
+        #_ids = ids.view("float64")
+        data.deposit(pos, [ids], method = "mesh_id")
+        return ids
+    registry.add_field((ptype, "mesh_id"),
+            function = particle_mesh_ids,
+            validators = [ValidateSpatial()],
+            particle_type = True)
+
     return list(set(registry.keys()).difference(orig))
 
 

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/tests/test_ellipsoid.py
--- a/yt/data_objects/tests/test_ellipsoid.py
+++ b/yt/data_objects/tests/test_ellipsoid.py
@@ -5,13 +5,23 @@
     ytcfg["yt","loglevel"] = "50"
     ytcfg["yt","__withintesting"] = "True"
 
+def _difference(x1, x2, dw):
+    rel = x1 - x2
+    rel[rel >  dw/2.0] -= dw
+    rel[rel < -dw/2.0] += dw
+    return rel
+
 def test_ellipsoid():
     # We decompose in different ways
-    cs = [np.array([0.5, 0.5, 0.5]),
+    cs = [
+          np.array([0.5, 0.5, 0.5]),
           np.array([0.1, 0.2, 0.3]),
-          np.array([0.8, 0.8, 0.8])]
+          np.array([0.8, 0.8, 0.8])
+          ]
+    np.random.seed(int(0x4d3d3d3))
     for nprocs in [1, 2, 4, 8]:
         pf = fake_random_pf(64, nprocs = nprocs)
+        DW = pf.domain_right_edge - pf.domain_left_edge
         min_dx = 2.0/pf.domain_dimensions
         ABC = np.random.random((3, 12)) * 0.1
         e0s = np.random.random((3, 12))
@@ -26,10 +36,17 @@
                 e0 = e0s[:,i]
                 tilt = tilts[i]
                 ell = pf.h.ellipsoid(c, A, B, C, e0, tilt)
-                yield assert_equal, np.all(ell["Radius"] <= A), True
+                yield assert_array_less, ell["Radius"], A
                 p = np.array([ell[ax] for ax in 'xyz'])
-                v  = np.zeros_like(ell["Radius"])
-                v += (((p - c[:,None]) * ell._e0[:,None]).sum(axis=0) / ell._A)**2
-                v += (((p - c[:,None]) * ell._e1[:,None]).sum(axis=0) / ell._B)**2
-                v += (((p - c[:,None]) * ell._e2[:,None]).sum(axis=0) / ell._C)**2
-                yield assert_equal, np.all(np.sqrt(v) <= 1.0), True
+                dot_evec = [np.zeros_like(ell["Radius"]) for i in range(3)]
+                vecs = [ell._e0, ell._e1, ell._e2]
+                mags = [ell._A, ell._B, ell._C]
+                my_c = np.array([c]*p.shape[1]).transpose()
+                for ax_i in range(3):
+                    dist = _difference(p[ax_i,:], my_c[ax_i,:], DW[ax_i])
+                    for ax_j in range(3):
+                        dot_evec[ax_j] += dist * vecs[ax_j][ax_i]
+                dist = 0
+                for ax_i in range(3):
+                    dist += dot_evec[ax_i]**2.0 / mags[ax_i]**2.0
+                yield assert_array_less, dist, 1.0

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/tests/test_fields.py
--- a/yt/data_objects/tests/test_fields.py
+++ b/yt/data_objects/tests/test_fields.py
@@ -24,6 +24,7 @@
 _base_fields = ["Density", "x-velocity", "y-velocity", "z-velocity"]
 
 def realistic_pf(fields, nprocs):
+    np.random.seed(int(0x4d3d3d3))
     pf = fake_random_pf(16, fields = fields, nprocs = nprocs)
     pf.parameters["HydroMethod"] = "streaming"
     pf.parameters["Gamma"] = 5.0/3.0
@@ -52,7 +53,7 @@
     def __call__(self):
         field = FieldInfo[self.field_name]
         deps = field.get_dependencies()
-        fields = deps.requested + _base_fields
+        fields = list(set(deps.requested + _base_fields))
         skip_grids = False
         needs_spatial = False
         for v in field.validators:
@@ -99,3 +100,8 @@
         if FieldInfo[field].particle_type: continue
         for nproc in [1, 4, 8]:
             yield TestFieldAccess(field, nproc)
+
+if __name__ == "__main__":
+    setup()
+    for t in test_all_fields():
+        t()

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/data_objects/universal_fields.py
--- a/yt/data_objects/universal_fields.py
+++ b/yt/data_objects/universal_fields.py
@@ -376,12 +376,6 @@
 add_field("DynamicalTime", function=_DynamicalTime,
            units=r"\rm{s}")
 
-def JeansMassMsun(field,data):
-    return (MJ_constant * 
-            ((data["Temperature"]/data["MeanMolecularWeight"])**(1.5)) *
-            (data["Density"]**(-0.5)))
-add_field("JeansMassMsun",function=JeansMassMsun,units=r"\rm{Msun}")
-
 def _CellMass(field, data):
     return data["Density"] * data["CellVolume"]
 def _convertCellMassMsun(data):
@@ -619,7 +613,7 @@
 def _convertSpecificAngularMomentum(data):
     return data.convert("cm")
 def _convertSpecificAngularMomentumKMSMPC(data):
-    return data.convert("mpc")/1e5
+    return km_per_cm*data.convert("mpc")
 
 def _SpecificAngularMomentumX(field, data):
     xv, yv, zv = obtain_velocities(data)
@@ -678,8 +672,6 @@
 #          function=_ParticleSpecificAngularMomentum, particle_type=True,
 #          convert_function=_convertSpecificAngularMomentum, vector_field=True,
 #          units=r"\rm{cm}^2/\rm{s}", validators=[ValidateParameter('center')])
-def _convertSpecificAngularMomentumKMSMPC(data):
-    return km_per_cm*data.convert("mpc")
 #add_field("ParticleSpecificAngularMomentumKMSMPC",
 #          function=_ParticleSpecificAngularMomentum, particle_type=True,
 #          convert_function=_convertSpecificAngularMomentumKMSMPC, vector_field=True,
@@ -909,7 +901,7 @@
     pos = pos - np.reshape(center, (3, 1))
     vel = vel - np.reshape(bv, (3, 1))
     spht = get_sph_theta_component(vel, theta, phi, normal)
-    return sphrt
+    return spht
 
 add_field("ParticleThetaVelocity", function=_ParticleThetaVelocity,
           particle_type=True, units=r"\rm{cm}/\rm{s}",
@@ -928,8 +920,8 @@
     phi = get_sph_phi(pos.copy(), center)
     pos = pos - np.reshape(center, (3, 1))
     vel = vel - np.reshape(bv, (3, 1))
-    sphp = get_sph_phi_component(vel, theta, phi, normal)
-    return sphrp
+    sphp = get_sph_phi_component(vel, phi, normal)
+    return sphp
 
 add_field("ParticlePhiVelocity", function=_ParticleThetaVelocity,
           particle_type=True, units=r"\rm{cm}/\rm{s}",

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/frontends/sph/data_structures.py
--- a/yt/frontends/sph/data_structures.py
+++ b/yt/frontends/sph/data_structures.py
@@ -151,7 +151,8 @@
 
     def __init__(self, filename, data_style="gadget_binary",
                  additional_fields = (),
-                 unit_base = None):
+                 unit_base = None, n_ref = 64):
+        self.n_ref = n_ref
         self.storage_filename = None
         if unit_base is not None and "UnitLength_in_cm" in unit_base:
             # We assume this is comoving, because in the absence of comoving
@@ -264,10 +265,11 @@
     _particle_coordinates_name = "Coordinates"
     _header_spec = None # Override so that there's no confusion
 
-    def __init__(self, filename, data_style="OWLS"):
+    def __init__(self, filename, data_style="OWLS", n_ref = 64):
         self.storage_filename = None
         super(OWLSStaticOutput, self).__init__(filename, data_style,
-                                               unit_base = None)
+                                               unit_base = None,
+                                               n_ref = n_ref)
 
     def __repr__(self):
         return os.path.basename(self.parameter_filename).split(".")[0]
@@ -357,7 +359,9 @@
                  domain_left_edge = None,
                  domain_right_edge = None,
                  unit_base = None,
-                 cosmology_parameters = None):
+                 cosmology_parameters = None,
+                 n_ref = 64):
+        self.n_ref = n_ref
         self.endian = endian
         self.storage_filename = None
         if domain_left_edge is None:

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/frontends/sph/io.py
--- a/yt/frontends/sph/io.py
+++ b/yt/frontends/sph/io.py
@@ -380,6 +380,12 @@
                 rv[field] = np.empty(size, dtype="float64")
                 if size == 0: continue
                 rv[field][:] = vals[field][mask]
+            if field == "Coordinates":
+                eps = np.finfo(rv[field].dtype).eps
+                for i in range(3):
+                  rv[field][:,i] = np.clip(rv[field][:,i],
+                      self.domain_left_edge[i] + eps,
+                      self.domain_right_edge[i] - eps)
         return rv
 
     def _read_particle_selection(self, chunks, selector, fields):
@@ -421,6 +427,8 @@
         ind = 0
         DLE, DRE = pf.domain_left_edge, pf.domain_right_edge
         dx = (DRE - DLE) / (2**_ORDER_MAX)
+        self.domain_left_edge = DLE
+        self.domain_right_edge = DRE
         with open(data_file.filename, "rb") as f:
             f.seek(pf._header_offset)
             for iptype, ptype in enumerate(self._ptypes):
@@ -446,9 +454,11 @@
                                                pf.domain_left_edge,
                                                pf.domain_right_edge)
                     pos = np.empty((pp.size, 3), dtype="float64")
-                    pos[:,0] = pp["Coordinates"]["x"]
-                    pos[:,1] = pp["Coordinates"]["y"]
-                    pos[:,2] = pp["Coordinates"]["z"]
+                    for i, ax in enumerate("xyz"):
+                        eps = np.finfo(pp["Coordinates"][ax].dtype).eps
+                        pos[:,i] = np.clip(pp["Coordinates"][ax],
+                                    pf.domain_left_edge[i] + eps,
+                                    pf.domain_right_edge[i] - eps)
                     regions.add_data_file(pos, data_file.file_id)
                     morton[ind:ind+c] = compute_morton(
                         pos[:,0], pos[:,1], pos[:,2],

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/frontends/stream/api.py
--- a/yt/frontends/stream/api.py
+++ b/yt/frontends/stream/api.py
@@ -31,6 +31,7 @@
       StreamHandler, \
       load_uniform_grid, \
       load_amr_grids, \
+      load_particles, \
       refine_amr
 
 from .fields import \

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -733,9 +733,11 @@
     _data_style = "stream_particles"
     file_count = 1
     filename_template = "stream_file"
+    n_ref = 64
 
 def load_particles(data, sim_unit_to_cm, bbox=None,
-                      sim_time=0.0, periodicity=(True, True, True)):
+                      sim_time=0.0, periodicity=(True, True, True),
+                      n_ref = 64):
     r"""Load a set of particles into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamParticleHandler`.
 
@@ -764,6 +766,9 @@
     periodicity : tuple of booleans
         Determines whether the data will be treated as periodic along
         each axis
+    n_ref : int
+        The number of particles that result in refining an oct used for
+        indexing the particles.
 
     Examples
     --------
@@ -818,6 +823,7 @@
     handler.cosmology_simulation = 0
 
     spf = StreamParticlesStaticOutput(handler)
+    spf.n_ref = n_ref
     spf.units["cm"] = sim_unit_to_cm
     spf.units['1'] = 1.0
     spf.units["unitary"] = 1.0

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/particle_deposit.pxd
--- a/yt/geometry/particle_deposit.pxd
+++ b/yt/geometry/particle_deposit.pxd
@@ -63,6 +63,8 @@
     # We assume each will allocate and define their own temporary storage
     cdef public object nvals
     cdef public int bad_indices
+    cdef int update_values
     cdef void process(self, int dim[3], np.float64_t left_edge[3],
                       np.float64_t dds[3], np.int64_t offset,
-                      np.float64_t ppos[3], np.float64_t *fields)
+                      np.float64_t ppos[3], np.float64_t *fields,
+                      np.int64_t domain_ind)

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/particle_deposit.pyx
--- a/yt/geometry/particle_deposit.pyx
+++ b/yt/geometry/particle_deposit.pyx
@@ -38,6 +38,7 @@
 cdef class ParticleDepositOperation:
     def __init__(self, nvals):
         self.nvals = nvals
+        self.update_values = 0 # This is the default
 
     def initialize(self, *args):
         raise NotImplementedError
@@ -101,7 +102,10 @@
             if offset < 0: continue
             # Check that we found the oct ...
             self.process(dims, oi.left_edge, oi.dds,
-                         offset, pos, field_vals)
+                         offset, pos, field_vals, oct.domain_ind)
+            if self.update_values == 1:
+                for j in range(nf):
+                    field_pointers[j][i] = field_vals[j] 
         
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -116,6 +120,7 @@
         cdef np.ndarray[np.float64_t, ndim=1] tarr
         field_pointers = <np.float64_t**> alloca(sizeof(np.float64_t *) * nf)
         field_vals = <np.float64_t*>alloca(sizeof(np.float64_t) * nf)
+        cdef np.int64_t gid = getattr(gobj, "id", -1)
         for i in range(nf):
             tarr = fields[i]
             field_pointers[i] = <np.float64_t *> tarr.data
@@ -131,11 +136,15 @@
                 field_vals[j] = field_pointers[j][i]
             for j in range(3):
                 pos[j] = positions[i, j]
-            self.process(dims, left_edge, dds, 0, pos, field_vals)
+            self.process(dims, left_edge, dds, 0, pos, field_vals, gid)
+            if self.update_values == 1:
+                for j in range(nf):
+                    field_pointers[j][i] = field_vals[j] 
 
     cdef void process(self, int dim[3], np.float64_t left_edge[3],
                       np.float64_t dds[3], np.int64_t offset,
-                      np.float64_t ppos[3], np.float64_t *fields):
+                      np.float64_t ppos[3], np.float64_t *fields,
+                      np.int64_t domain_ind):
         raise NotImplementedError
 
 cdef class CountParticles(ParticleDepositOperation):
@@ -154,7 +163,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset, # offset into IO field
                       np.float64_t ppos[3], # this particle's position
-                      np.float64_t *fields # any other fields we need
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         # here we do our thing; this is the kernel
         cdef int ii[3], i
@@ -190,7 +200,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset,
                       np.float64_t ppos[3],
-                      np.float64_t *fields
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], half_len, ib0[3], ib1[3]
         cdef int i, j, k
@@ -243,7 +254,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset, 
                       np.float64_t ppos[3],
-                      np.float64_t *fields 
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], i
         for i in range(3):
@@ -289,7 +301,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset,
                       np.float64_t ppos[3],
-                      np.float64_t *fields
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], i, cell_index
         cdef float k, mk, qk
@@ -331,7 +344,8 @@
                       np.float64_t dds[3],
                       np.int64_t offset, # offset into IO field
                       np.float64_t ppos[3], # this particle's position
-                      np.float64_t *fields # any other fields we need
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         
         cdef int i, j, k, ind[3], ii
@@ -375,14 +389,15 @@
         self.ow = np.zeros(self.nvals, dtype='float64', order='F')
         cdef np.ndarray warr = self.ow
         self.w = <np.float64_t*> warr.data
-    
+
     @cython.cdivision(True)
     cdef void process(self, int dim[3],
                       np.float64_t left_edge[3], 
                       np.float64_t dds[3],
                       np.int64_t offset, 
                       np.float64_t ppos[3],
-                      np.float64_t *fields 
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
                       ):
         cdef int ii[3], i
         for i in range(3):
@@ -393,5 +408,27 @@
     def finalize(self):
         return self.owf / self.ow
 
-deposit_weighted_mean= WeightedMeanParticleField
+deposit_weighted_mean = WeightedMeanParticleField
 
+cdef class MeshIdentifier(ParticleDepositOperation):
+    # This is a tricky one!  What it does is put into the particle array the
+    # value of the oct or block (grids will always be zero) identifier that a
+    # given particle resides in
+    def initialize(self):
+        self.update_values = 1
+
+    @cython.cdivision(True)
+    cdef void process(self, int dim[3],
+                      np.float64_t left_edge[3], 
+                      np.float64_t dds[3],
+                      np.int64_t offset, 
+                      np.float64_t ppos[3],
+                      np.float64_t *fields,
+                      np.int64_t domain_ind
+                      ):
+        fields[0] = domain_ind
+
+    def finalize(self):
+        return
+
+deposit_mesh_id = MeshIdentifier

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/particle_geometry_handler.py
--- a/yt/geometry/particle_geometry_handler.py
+++ b/yt/geometry/particle_geometry_handler.py
@@ -87,7 +87,7 @@
         pf = self.parameter_file
         self.oct_handler = ParticleOctreeContainer(
             [1, 1, 1], pf.domain_left_edge, pf.domain_right_edge)
-        self.oct_handler.n_ref = 64
+        self.oct_handler.n_ref = pf.n_ref
         mylog.info("Allocating for %0.3e particles", self.total_particles)
         # No more than 256^3 in the region finder.
         N = min(len(self.data_files), 256) 

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/particle_oct_container.pyx
--- a/yt/geometry/particle_oct_container.pyx
+++ b/yt/geometry/particle_oct_container.pyx
@@ -190,7 +190,7 @@
                 if cur.children == NULL or \
                    cur.children[cind(ind[0],ind[1],ind[2])] == NULL:
                     cur = self.refine_oct(cur, index, level)
-                    self.filter_particles(cur, data, p, level + 1)
+                    self.filter_particles(cur, data, p, level)
                 else:
                     cur = cur.children[cind(ind[0],ind[1],ind[2])]
             cur.file_ind += 1
@@ -215,7 +215,7 @@
                     o.children[cind(i,j,k)] = noct
         o.file_ind = self.n_ref + 1
         for i in range(3):
-            ind[i] = (index >> ((ORDER_MAX - (level + 1))*3 + (2 - i))) & 1
+            ind[i] = (index >> ((ORDER_MAX - level)*3 + (2 - i))) & 1
         noct = o.children[cind(ind[0],ind[1],ind[2])]
         return noct
 

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -52,7 +52,3 @@
 
 	# compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
     cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
-
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check)

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -254,11 +254,15 @@
             this_level = 0 # We turn this off for the second pass.
             iter += 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
-        return 0
-    
+        if level < self.min_level or level > self.max_level: return 0
+        return self.select_bbox(left_edge,right_edge)
+ 
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 0
 
@@ -293,14 +297,12 @@
         cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         cdef np.float64_t dds[3], pos[3]
-        cdef int i, j, k, ind[3][2]
+        cdef int i, j, k, dim[3]
         child_mask = gobj.child_mask
         for i in range(3):
-            ind[i][0] = 0
-            ind[i][1] = gobj.ActiveDimensions[i]
+            dim[i] = gobj.ActiveDimensions[i]
             dds[i] = odds[i]
         cdef int count = 0
-        cdef int check = 1
         # Check for the level bounds
         cdef np.int32_t level = gobj.Level
         if level < self.min_level or level > self.max_level:
@@ -309,28 +311,18 @@
         cdef int this_level = 0
         if level == self.max_level:
             this_level = 1
-        self.set_bounds(<np.float64_t *> left_edge.data,
-                        <np.float64_t *> right_edge.data,
-                        dds, ind, &check)
         with nogil:
-            if check == 1:
-                pos[0] = left_edge[0] + dds[0] * 0.5
-                for i in range(ind[0][0], ind[0][1]):
-                    pos[1] = left_edge[1] + dds[1] * 0.5
-                    for j in range(ind[1][0], ind[1][1]):
-                        pos[2] = left_edge[2] + dds[2] * 0.5
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += self.select_cell(pos, dds)
-                            pos[2] += dds[1]
-                        pos[1] += dds[1]
-                    pos[0] += dds[0]
-            else:
-                for i in range(ind[0][0], ind[0][1]):
-                    for j in range(ind[1][0], ind[1][1]):
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += 1
+            pos[0] = left_edge[0] + dds[0] * 0.5
+            for i in range(dim[0]):
+                pos[1] = left_edge[1] + dds[1] * 0.5
+                for j in range(dim[1]):
+                    pos[2] = left_edge[2] + dds[2] * 0.5
+                    for k in range(dim[2]):
+                        if child_mask[i,j,k] == 1 or this_level == 1:
+                            count += self.select_cell(pos, dds)
+                        pos[2] += dds[1]
+                    pos[1] += dds[1]
+                pos[0] += dds[0]
         return count
 
     @cython.boundscheck(False)
@@ -339,8 +331,9 @@
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         child_mask = gobj.child_mask
-        cdef np.ndarray[np.uint8_t, ndim=3] mask 
+        cdef np.ndarray[np.uint8_t, ndim=3] mask
         cdef int ind[3][2]
+        cdef int dim[3]
         cdef np.ndarray[np.float64_t, ndim=1] odds = gobj.dds
         cdef np.ndarray[np.float64_t, ndim=1] left_edge = gobj.LeftEdge
         cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
@@ -348,52 +341,34 @@
         cdef np.float64_t dds[3], pos[3]
         for i in range(3):
             dds[i] = odds[i]
-            ind[i][0] = 0
-            ind[i][1] = gobj.ActiveDimensions[i]
+            dim[i] = gobj.ActiveDimensions[i]
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
-        cdef int check = 1
         cdef int total = 0
-        self.set_bounds(<np.float64_t *> left_edge.data,
-                        <np.float64_t *> right_edge.data,
-                        dds, ind, &check)
         cdef int temp
         # Check for the level bounds
         cdef np.int32_t level = gobj.Level
         if level < self.min_level or level > self.max_level:
-            return mask
+            return mask.astype("bool")
         # We set this to 1 if we ignore child_mask
         cdef int this_level = 0
         if level == self.max_level:
             this_level = 1
         with nogil:
-            if check == 1:
-                pos[0] = left_edge[0] + dds[0] * 0.5
-                for i in range(ind[0][0], ind[0][1]):
-                    pos[1] = left_edge[1] + dds[1] * 0.5
-                    for j in range(ind[1][0], ind[1][1]):
-                        pos[2] = left_edge[2] + dds[2] * 0.5
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = self.select_cell(pos, dds)
-                                total += mask[i,j,k]
-                            pos[2] += dds[1]
-                        pos[1] += dds[1]
-                    pos[0] += dds[0]
-            else:
-                for i in range(ind[0][0], ind[0][1]):
-                    for j in range(ind[1][0], ind[1][1]):
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = 1
+            pos[0] = left_edge[0] + dds[0] * 0.5
+            for i in range(dim[0]):
+                pos[1] = left_edge[1] + dds[1] * 0.5
+                for j in range(dim[1]):
+                    pos[2] = left_edge[2] + dds[2] * 0.5
+                    for k in range(dim[2]):
+                        if child_mask[i,j,k] == 1 or this_level == 1:
+                            mask[i,j,k] = self.select_cell(pos, dds)
                             total += mask[i,j,k]
+                        pos[2] += dds[1]
+                    pos[1] += dds[1]
+                pos[0] += dds[0]
         if total == 0: return None
         return mask.astype("bool")
 
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        return
-
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -455,6 +430,21 @@
         if count == 0: return None
         return mask.astype("bool")
 
+    def __hash__(self):
+        return hash(self._hash_vals() + self._base_hash())
+
+    def _hash_vals(self):
+        raise NotImplementedError
+
+    def _base_hash(self):
+        return (self.min_level, self.max_level, self.overlap_cells,
+                self.periodicity[0],
+                self.periodicity[1],
+                self.periodicity[2],
+                self.domain_width[0],
+                self.domain_width[1],
+                self.domain_width[2])
+
 cdef class SphereSelector(SelectorObject):
     cdef np.float64_t radius
     cdef np.float64_t radius2
@@ -469,14 +459,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox(left_edge,right_edge)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         # sphere center either inside cell or center of cell lies inside sphere
         if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
@@ -532,6 +514,10 @@
         if dist <= self.radius2: return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.radius, self.radius2,
+                self.center[0], self.center[1], self.center[2])
+
 sphere_selector = SphereSelector
 
 cdef class RegionSelector(SelectorObject):
@@ -549,21 +535,23 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        if level < self.min_level or level > self.max_level: return 0
-        return self.select_bbox( left_edge, right_edge )
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil:
-        cdef int i
+        cdef int i, shift, included
+        cdef np.float64_t LE, RE
         for i in range(3):
-            if left_edge[i] >= self.right_edge[i]: return 0
-            if right_edge[i] <= self.left_edge[i]: return 0
+            if not self.periodicity[i]:
+                if left_edge[i] > self.right_edge[i]: return 0
+                if right_edge[i] < self.left_edge[i]: return 0
+            else:
+                included = 1
+                for shift in range(3):
+                    LE = left_edge[i] + self.domain_width[i] * (shift - 1)
+                    RE = right_edge[i] + self.domain_width[i] * (shift - 1)
+                    if LE > self.right_edge[i]: continue
+                    if RE < self.left_edge[i]: continue
+                    included = 1
+                if included == 0: return 0
         return 1
 
     @cython.boundscheck(False)
@@ -571,52 +559,39 @@
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         cdef int i
-        cdef np.float64_t dxp
+        cdef np.float64_t LE[3], RE[3]
+        if self.dx_pad == 0.0:
+            return self.select_point(pos)
         for i in range(3):
-            dxp = self.dx_pad * dds[i]
-            if pos[i] - dxp >= self.right_edge[i]:
-                return 0
-            if pos[i] + dxp <= self.left_edge[i]: return 0
-        return 1
+            LE[i] = pos[i] - self.dx_pad * dds[i]
+            RE[i] = pos[i] + self.dx_pad * dds[i]
+        return self.select_bbox(LE, RE)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_point(self, np.float64_t pos[3]) nogil:
         # assume pos[3] is inside domain
-        cdef int i
-        for i in range(3) :
-            if pos[i] < self.left_edge[i] or \
-                    pos[i] >= self.right_edge[i] :
-                return 0
+        cdef int i, shift, included
+        cdef np.float64_t dxp, ppos
+        for i in range(3):
+            if not self.periodicity[i]:
+                if pos[i] < self.left_edge[i]: return 0
+                if pos[i] > self.right_edge[i]: return 0
+            else:
+                included = 0
+                for shift in range(3):
+                    ppos = pos[i] + self.domain_width[i] * (shift - 1)
+                    if ppos < self.left_edge[i]: continue
+                    if ppos > self.right_edge[i]: continue
+                    included = 1
+                if included == 0: return 0
         return 1
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int temp, i, all_inside
-        # Left pos is left_edge + 0.5 * dds
-        # This means the grid is fully within the region
-        # Note vice versa!
-        all_inside = 1 
-        for i in range(3):
-            # If the region starts after the grid does...
-            if self.left_edge[i] > left_edge[i]:
-                temp = <int> ((self.left_edge[i] - left_edge[i])/dds[i]) - 1
-                #ind[i][0] = iclip(temp, ind[i][0], ind[i][1])
-                all_inside = 0
-            # If the region ends before the grid does...
-            if self.right_edge[i] < right_edge[i]:
-                temp = <int> ((self.right_edge[i] - left_edge[i])/dds[i]) + 1
-                #ind[i][1] = iclip(temp, ind[i][0], ind[i][1])
-                all_inside = 0
-        if all_inside == 0:
-            check[0] = 1
-        else:
-            check[0] = 0
+    def _hash_vals(self):
+        return (self.left_edge[0], self.left_edge[1], self.left_edge[2],
+                self.right_edge[0], self.right_edge[1], self.right_edge[2],
+                self.dx_pad)
 
 region_selector = RegionSelector
 
@@ -638,14 +613,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox( left_edge, right_edge )
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return self.select_point( pos ) 
 
@@ -727,6 +694,11 @@
         if all_over == 0 and all_under == 0 and any_radius == 1: return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.norm_vec[0], self.norm_vec[1], self.norm_vec[2],
+                self.center[0], self.center[1], self.center[2],
+                self.radius, self.radius2, self.height)
+
 disk_selector = DiskSelector
 
 cdef class CuttingPlaneSelector(SelectorObject):
@@ -742,14 +714,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox(left_edge,right_edge)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         cdef np.float64_t left_edge[3]
         cdef np.float64_t right_edge[3]
@@ -809,6 +773,10 @@
             return 0
         return 1
 
+    def _hash_vals(self):
+        return (self.norm_vec[0], self.norm_vec[1], self.norm_vec[2],
+                self.d)
+
 cutting_selector = CuttingPlaneSelector
 
 cdef class SliceSelector(SelectorObject):
@@ -822,27 +790,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int i
-        for i in range(3):
-            if self.axis == i:
-                ind[i][0] = <int> ((self.coord - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-        check[0] = 0
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox( left_edge, right_edge )
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if pos[self.axis] + 0.5*dds[self.axis] > self.coord \
            and pos[self.axis] - 0.5*dds[self.axis] <= self.coord:
@@ -871,6 +818,9 @@
             return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.axis, self.coord)
+
 slice_selector = SliceSelector
 
 cdef class OrthoRaySelector(SelectorObject):
@@ -891,14 +841,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox(left_edge,right_edge)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
            self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
@@ -931,21 +873,8 @@
             return 1
         return 0
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int i
-        for i in range(3):
-            if self.px_ax == i:
-                ind[i][0] = <int> ((self.px - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-            elif self.py_ax == i:
-                ind[i][0] = <int> ((self.py - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-        check[0] = 0
+    def _hash_vals(self):
+        return (self.px_ax, self.py_ax, self.px, self.py, self.axis)
 
 ortho_ray_selector = OrthoRaySelector
 
@@ -987,14 +916,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox(left_edge,right_edge)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.float64_t, ndim=3] t, dt
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
@@ -1113,6 +1034,11 @@
                     return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.p1[0], self.p1[1], self.p1[2],
+                self.p2[0], self.p2[1], self.p2[2],
+                self.vec[0], self.vec[1], self.vec[2])
+
 ray_selector = RaySelector
 
 cdef class DataCollectionSelector(SelectorObject):
@@ -1126,15 +1052,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1162,6 +1079,9 @@
         mask = np.ones(gobj.ActiveDimensions, dtype='uint8')
         return mask.astype("bool")
 
+    def _hash_vals(self):
+        return (hash(self.obj_ids.tostring()), self.nids)
+
 data_collection_selector = DataCollectionSelector
 
 cdef class EllipsoidSelector(SelectorObject):
@@ -1183,14 +1103,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        return self.select_bbox(left_edge, right_edge)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return self.select_point(pos)
 
@@ -1248,6 +1160,13 @@
         if dist <= self.mag[0]**2: return 1
         return 0
 
+    def _hash_vals(self):
+        return (self.vec[0][0], self.vec[0][1], self.vec[0][2],
+                self.vec[1][0], self.vec[1][1], self.vec[1][2],
+                self.vec[2][0], self.vec[2][1], self.vec[2][2],
+                self.mag[0], self.mag[1], self.mag[2],
+                self.center[0], self.center[1], self.center[2])
+
 ellipsoid_selector = EllipsoidSelector
 
 cdef class GridSelector(SelectorObject):
@@ -1259,15 +1178,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1299,6 +1209,9 @@
         # we apparently don't check if the point actually lies in the grid..
         return 1
 
+    def _hash_vals(self):
+        return (self.ind,)
+
 grid_selector = GridSelector
 
 cdef class OctreeSubsetSelector(SelectorObject):
@@ -1315,15 +1228,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1333,9 +1237,31 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return self.base_selector.select_bbox(left_edge, right_edge)
+    
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                          np.float64_t right_edge[3], np.int32_t level,
                          Oct *o = NULL) nogil:
@@ -1346,6 +1272,9 @@
         if res == 1 and o != NULL and o.domain != self.domain_id:
             return -1
         return res
+    
+    def _hash_vals(self):
+        return (hash(self.base_selector), self.domain_id)
 
 octree_subset_selector = OctreeSubsetSelector
 
@@ -1365,15 +1294,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1383,15 +1303,37 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return self.base_selector.select_bbox(left_edge, right_edge)
+    
     cdef int select_grid(self, np.float64_t left_edge[3],
                          np.float64_t right_edge[3], np.int32_t level,
                          Oct *o = NULL) nogil:
         # Because visitors now use select_grid, we should be explicitly
         # checking this.
         return self.base_selector.select_grid(left_edge, right_edge, level, o)
+    
+    def _hash_vals(self):
+        return (hash(self.base_selector), self.min_ind, self.max_ind)
 
 particle_octree_subset_selector = ParticleOctreeSubsetSelector
 
@@ -1403,15 +1345,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1441,4 +1374,7 @@
                                np.float64_t right_edge[3]) nogil:
         return 1
 
+    def _hash_vals(self):
+        return ("always", 1,)
+
 always_selector = AlwaysSelector

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/setup.py
--- a/yt/geometry/setup.py
+++ b/yt/geometry/setup.py
@@ -41,6 +41,7 @@
                 libraries=["m"],
                 depends=["yt/utilities/lib/fp_utils.pxd",
                          "yt/geometry/oct_container.pxd",
+                         "yt/geometry/selection_routines.pxd",
                          "yt/geometry/particle_deposit.pxd"])
     config.add_extension("fake_octree", 
                 ["yt/geometry/fake_octree.pyx"],

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/geometry/tests/test_particle_octree.py
--- a/yt/geometry/tests/test_particle_octree.py
+++ b/yt/geometry/tests/test_particle_octree.py
@@ -3,6 +3,8 @@
 from yt.geometry.particle_oct_container import ParticleOctreeContainer
 from yt.geometry.oct_container import _ORDER_MAX
 from yt.utilities.lib.geometry_utils import get_morton_indices
+from yt.frontends.stream.api import load_particles
+import yt.data_objects.api
 import time, os
 
 NPART = 32**3
@@ -35,7 +37,27 @@
         # This visits every cell -- including those covered by octs.
         #for dom in range(ndom):
         #    level_count += octree.count_levels(total_count.size-1, dom, mask)
-        yield assert_equal, total_count, [1, 8, 64, 104, 184, 480, 1680, 1480]
+        yield assert_equal, total_count, [1, 8, 64, 64, 256, 536, 1856, 1672]
+
+def test_particle_octree_counts():
+    np.random.seed(int(0x4d3d3d3))
+    # Eight times as many!
+    pos = []
+    data = {}
+    bbox = []
+    for i, ax in enumerate('xyz'):
+        DW = DRE[i] - DLE[i]
+        LE = DLE[i]
+        data["particle_position_%s" % ax] = \
+            np.random.normal(0.5, scale=0.05, size=(NPART*8)) * DW + LE
+        bbox.append( [DLE[i], DRE[i]] )
+    bbox = np.array(bbox)
+    for n_ref in [16, 32, 64, 512, 1024]:
+        pf = load_particles(data, 1.0, bbox = bbox, n_ref = n_ref)
+        dd = pf.h.all_data()
+        bi = dd["all","mesh_id"]
+        v = np.bincount(bi.astype("int64"))
+        yield assert_equal, v.max() <= n_ref, True
 
 if __name__=="__main__":
     for i in test_add_particles_random():

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/utilities/lib/misc_utilities.pyx
--- a/yt/utilities/lib/misc_utilities.pyx
+++ b/yt/utilities/lib/misc_utilities.pyx
@@ -544,6 +544,7 @@
                 np.ndarray[np.int64_t, ndim=1] left_index,
                 np.ndarray[np.int64_t, ndim=2] ipos,
                 np.ndarray[np.int64_t, ndim=1] ires,
+                np.ndarray[np.int64_t, ndim=1] level_dims,
                 np.int64_t refine_by = 2
                 ):
     cdef int i, n
@@ -552,29 +553,51 @@
     cdef np.ndarray[np.float64_t, ndim=3] ofield
     cdef np.ndarray[np.float64_t, ndim=1] ifield
     nf = len(input_fields)
+    # The variable offsets governs for each dimension and each possible
+    # wrapping if we do it.  Then the wi, wj, wk indices check into each
+    # [dim][wrap] inside the loops.
+    cdef int offsets[3][3], wi, wj, wk
+    cdef np.int64_t off
     for i in range(3):
         dim[i] = output_fields[0].shape[i]
+        offsets[i][0] = offsets[i][2] = 0
+        offsets[i][1] = 1
+        if left_index[i] < 0:
+            offsets[i][2] = 1
+        if left_index[i] + dim[i] >= level_dims[i]:
+            offsets[i][0] = 1
     for n in range(nf):
         tot = 0
         ofield = output_fields[n]
         ifield = input_fields[n]
         for i in range(ipos.shape[0]):
             rf = refine_by**(output_level - ires[i]) 
-            for n in range(3):
-                iind[n] = ipos[i, n] * rf - left_index[n]
-            for oi in range(rf):
-                oind[0] = oi + iind[0]
-                if oind[0] < 0 or oind[0] >= dim[0]:
-                    continue
-                for oj in range(rf):
-                    oind[1] = oj + iind[1]
-                    if oind[1] < 0 or oind[1] >= dim[1]:
+            for wi in range(3):
+                if offsets[0][wi] == 0: continue
+                off = (left_index[0] + level_dims[0]*(wi-1))
+                iind[0] = ipos[i, 0] * rf - off
+                for oi in range(rf):
+                    # Now we need to apply our offset
+                    oind[0] = oi + iind[0]
+                    if oind[0] < 0 or oind[0] >= dim[0]:
                         continue
-                    for ok in range(rf):
-                        oind[2] = ok + iind[2]
-                        if oind[2] < 0 or oind[2] >= dim[2]:
-                            continue
-                        ofield[oind[0], oind[1], oind[2]] = \
-                            ifield[i]
-                        tot += 1
+                    for wj in range(3):
+                        if offsets[1][wj] == 0: continue
+                        off = (left_index[1] + level_dims[1]*(wj-1))
+                        iind[1] = ipos[i, 1] * rf - off
+                        for oj in range(rf):
+                            oind[1] = oj + iind[1]
+                            if oind[1] < 0 or oind[1] >= dim[1]:
+                                continue
+                            for wk in range(3):
+                                if offsets[2][wk] == 0: continue
+                                off = (left_index[2] + level_dims[2]*(wk-1))
+                                iind[2] = ipos[i, 2] * rf - off
+                                for ok in range(rf):
+                                    oind[2] = ok + iind[2]
+                                    if oind[2] < 0 or oind[2] >= dim[2]:
+                                        continue
+                                    ofield[oind[0], oind[1], oind[2]] = \
+                                        ifield[i]
+                                    tot += 1
     return tot

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/utilities/lib/tests/test_fill_region.py
--- a/yt/utilities/lib/tests/test_fill_region.py
+++ b/yt/utilities/lib/tests/test_fill_region.py
@@ -21,8 +21,9 @@
         ipos[:,1] = ind[1].ravel()
         ipos[:,2] = ind[2].ravel()
         ires = np.zeros(NDIM*NDIM*NDIM, "int64")
+        ddims = np.array([NDIM, NDIM, NDIM], dtype="int64") * rf
         fill_region(input_fields, output_fields, level,
-                    left_index, ipos, ires)
+                    left_index, ipos, ires, ddims, 2)
         for r in range(level + 1):
             for o, i in zip(output_fields, v):
                 assert_equal( o[r::rf,r::rf,r::rf], i)

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/utilities/tests/test_selectors.py
--- a/yt/utilities/tests/test_selectors.py
+++ b/yt/utilities/tests/test_selectors.py
@@ -93,10 +93,11 @@
     assert(all(pf.periodicity))
 
     for i,d in enumerate('xyz'):
-        for coord in np.arange(0,1.0,0.1):
+        for coord in np.arange(0.0,1.0,0.1):
             data = pf.h.slice(i, coord)
             data.get_data()
-            assert(data.shape[0] == 64**2)
+            yield assert_equal, data.shape[0], 64**2
+            yield assert_equal, data["Ones"].shape[0], 64**2
             yield assert_array_less, np.abs(data[d] - coord), 1./128.+1e-6
 
 def test_cutting_plane_selector():

diff -r b52c0bef2ef5fc85e260c6b31a5126afaaf3f3b4 -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1100,12 +1100,15 @@
 
     def _send_zmq(self):
         try:
-            # pre-IPython v0.14
+            # pre-IPython v1.0
             from IPython.zmq.pylab.backend_inline import send_figure as display
         except ImportError:
-            # IPython v0.14+
+            # IPython v1.0+
             from IPython.core.display import display
         for k, v in sorted(self.plots.iteritems()):
+            # Due to a quirk in the matplotlib API, we need to create
+            # a dummy canvas variable here that is never used.
+            canvas = FigureCanvasAgg(v.figure)  # NOQA
             display(v.figure)
 
     def show(self):


https://bitbucket.org/yt_analysis/yt-3.0/commits/8be775767368/
Changeset:   8be775767368
Branch:      yt-3.0
User:        drudd
Date:        2013-08-06 00:45:46
Summary:     Synced with upstream
Affected #:  4 files

diff -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 -r 8be77576736895c1588e52e1ca5630e5dd4b8878 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,13 +12,16 @@
 yt/frontends/sph/smoothing_kernel.c
 yt/geometry/fake_octree.c
 yt/geometry/oct_container.c
+yt/geometry/oct_visitors.c
 yt/geometry/particle_deposit.c
+yt/geometry/particle_oct_container.c
 yt/geometry/selection_routines.c
 yt/utilities/amr_utils.c
 yt/utilities/kdtree/forthonf2c.h
 yt/utilities/libconfig_wrapper.c
 yt/utilities/spatial/ckdtree.c
 yt/utilities/lib/alt_ray_tracers.c
+yt/utilities/lib/amr_kdtools.c
 yt/utilities/lib/CICDeposit.c
 yt/utilities/lib/ContourFinding.c
 yt/utilities/lib/DepthFirstOctree.c

diff -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 -r 8be77576736895c1588e52e1ca5630e5dd4b8878 yt/frontends/enzo/data_structures.py
--- a/yt/frontends/enzo/data_structures.py
+++ b/yt/frontends/enzo/data_structures.py
@@ -675,7 +675,7 @@
 
 class EnzoHierarchy1D(EnzoHierarchy):
 
-    def _fill_arrays(self, ei, si, LE, RE, npart):
+    def _fill_arrays(self, ei, si, LE, RE, npart, nap):
         self.grid_dimensions[:,:1] = ei
         self.grid_dimensions[:,:1] -= np.array(si, self.float_type)
         self.grid_dimensions += 1
@@ -685,10 +685,12 @@
         self.grid_left_edge[:,1:] = 0.0
         self.grid_right_edge[:,1:] = 1.0
         self.grid_dimensions[:,1:] = 1
+        if nap is not None:
+            raise NotImplementedError
 
 class EnzoHierarchy2D(EnzoHierarchy):
 
-    def _fill_arrays(self, ei, si, LE, RE, npart):
+    def _fill_arrays(self, ei, si, LE, RE, npart, nap):
         self.grid_dimensions[:,:2] = ei
         self.grid_dimensions[:,:2] -= np.array(si, self.float_type)
         self.grid_dimensions += 1
@@ -698,6 +700,8 @@
         self.grid_left_edge[:,2] = 0.0
         self.grid_right_edge[:,2] = 1.0
         self.grid_dimensions[:,2] = 1
+        if nap is not None:
+            raise NotImplementedError
 
 class EnzoStaticOutput(StaticOutput):
     """

diff -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 -r 8be77576736895c1588e52e1ca5630e5dd4b8878 yt/frontends/enzo/io.py
--- a/yt/frontends/enzo/io.py
+++ b/yt/frontends/enzo/io.py
@@ -277,6 +277,33 @@
                         (grid.id, field)).transpose()
         return t
 
+    def _read_fluid_selection(self, chunks, selector, fields, size):
+        rv = {}
+        # Now we have to do something unpleasant
+        chunks = list(chunks)
+        if selector.__class__.__name__ == "GridSelector":
+            return self._read_grid_chunk(chunks, fields)
+        if any((ftype != "gas" for ftype, fname in fields)):
+            raise NotImplementedError
+        for field in fields:
+            ftype, fname = field
+            fsize = size
+            rv[field] = np.empty(fsize, dtype="float64")
+        ng = sum(len(c.objs) for c in chunks)
+        mylog.debug("Reading %s cells of %s fields in %s grids",
+                   size, [f2 for f1, f2 in fields], ng)
+        ind = 0
+        for chunk in chunks:
+            data = self._read_chunk_data(chunk, fields)
+            for g in chunk.objs:
+                for field in fields:
+                    ftype, fname = field
+                    ds = np.atleast_3d(data[g.id].pop(fname))
+                    nd = g.select(selector, ds, rv[field], ind)  # caches
+                ind += nd
+                data.pop(g.id)
+        return rv
+
 
 class IOHandlerPacked1D(IOHandlerPackedHDF5):
 

diff -r e3b131318ef0c0dd07e0923eff35b8eb34b48083 -r 8be77576736895c1588e52e1ca5630e5dd4b8878 yt/frontends/sph/data_structures.py
--- a/yt/frontends/sph/data_structures.py
+++ b/yt/frontends/sph/data_structures.py
@@ -28,6 +28,7 @@
 import stat
 import weakref
 import struct
+import glob
 from itertools import izip
 
 from yt.utilities.fortran_utils import read_record
@@ -46,6 +47,7 @@
     G, \
     gravitational_constant_cgs, \
     km_per_pc, \
+    cm_per_kpc, \
     mass_sun_cgs
 from yt.utilities.cosmology import Cosmology
 from .fields import \
@@ -107,11 +109,12 @@
         mpch = {}
         mpch.update(mpc_conversion)
         unit_base = self._unit_base or {}
-        for unit in mpc_conversion:
-            mpch['%sh' % unit] = mpch[unit] * self.hubble_constant
-            mpch['%shcm' % unit] = (mpch["%sh" % unit] / 
-                    (1 + self.current_redshift))
-            mpch['%scm' % unit] = mpch[unit] / (1 + self.current_redshift)
+        if self.cosmological_simulation:
+            for unit in mpc_conversion:
+                mpch['%sh' % unit] = mpch[unit] * self.hubble_constant
+                mpch['%shcm' % unit] = (mpch["%sh" % unit] /
+                                (1 + self.current_redshift))
+                mpch['%scm' % unit] = mpch[unit] / (1 + self.current_redshift)
         # ud == unit destination
         # ur == unit registry
         for ud, ur in [(self.units, mpch), (self.time_units, sec_conversion)]:
@@ -360,6 +363,7 @@
                  domain_right_edge = None,
                  unit_base = None,
                  cosmology_parameters = None,
+                 parameter_file = None,
                  n_ref = 64):
         self.n_ref = n_ref
         self.endian = endian
@@ -379,6 +383,7 @@
 
         self._unit_base = unit_base or {}
         self._cosmology_parameters = cosmology_parameters
+        self._param_file = parameter_file
         super(TipsyStaticOutput, self).__init__(filename, data_style)
 
     def __repr__(self):
@@ -386,44 +391,74 @@
 
     def _parse_parameter_file(self):
 
-        # The entries in this header are capitalized and named to match Table 4
-        # in the GADGET-2 user guide.
+        # Parsing the header of the tipsy file, from this we obtain
+        # the snapshot time and particle counts.
 
         f = open(self.parameter_filename, "rb")
         hh = self.endian + "".join(["%s" % (b) for a,b in self._header_spec])
         hvals = dict([(a, c) for (a, b), c in zip(self._header_spec,
                      struct.unpack(hh, f.read(struct.calcsize(hh))))])
+        self.parameters.update(hvals)
         self._header_offset = f.tell()
 
+        # These are always true, for now.
         self.dimensionality = 3
         self.refine_by = 2
         self.parameters["HydroMethod"] = "sph"
+
         self.unique_identifier = \
             int(os.stat(self.parameter_filename)[stat.ST_CTIME])
-        # Set standard values
 
-        # This may not be correct.
+        # Read in parameter file, if available.
+        if self._param_file is None:
+            pfn = glob.glob(os.path.join(self.directory, "*.param"))
+            assert len(pfn) < 2, \
+                "More than one param file is in the data directory"
+            if pfn == []:
+                pfn = None
+            else:
+                pfn = pfn[0]
+        else:
+            pfn = self._param_file
+
+        if pfn is not None:
+            for line in (l.strip() for l in open(pfn)):
+                # skip comment lines and blank lines
+                l = line.strip()
+                if l.startswith('#') or l == '':
+                    continue
+                # parse parameters according to tipsy parameter type
+                param, val = (i.strip() for i in line.split('=',1))
+                if param.startswith('n') or param.startswith('i'):
+                    val = long(val)
+                elif param.startswith('d'):
+                    val = float(val)
+                elif param.startswith('b'):
+                    val = bool(float(val))
+                self.parameters[param] = val
+
         self.current_time = hvals["time"]
+        self.domain_dimensions = np.ones(3, "int32") * 2
+        if self.parameters.get('bPeriodic', True):
+            self.periodicity = (True, True, True)
+        else:
+            self.periodicity = (False, False, False)
 
-        # NOTE: These are now set in the main initializer.
-        #self.domain_left_edge = np.zeros(3, "float64") - 0.5
-        #self.domain_right_edge = np.ones(3, "float64") + 0.5
-        self.domain_dimensions = np.ones(3, "int32") * 2
-        self.periodicity = (True, True, True)
-
-        self.cosmological_simulation = 1
-
-        cosm = self._cosmology_parameters or {}
-        dcosm = dict(current_redshift = 0.0,
-                     omega_lambda = 0.0,
-                     omega_matter = 0.0,
-                     hubble_constant = 1.0)
-        for param in ['current_redshift', 'omega_lambda',
-                      'omega_matter', 'hubble_constant']:
-            pval = cosm.get(param, dcosm[param])
-            setattr(self, param, pval)
-
-        self.parameters = hvals
+        if self.parameters.get('bComove', True):
+            self.cosmological_simulation = 1
+            cosm = self._cosmology_parameters or {}
+            dcosm = dict(current_redshift = 0.0,
+                         omega_lambda = 0.0,
+                         omega_matter = 0.0,
+                         hubble_constant = 1.0)
+            for param in ['current_redshift', 'omega_lambda',
+                          'omega_matter', 'hubble_constant']:
+                pval = cosm.get(param, dcosm[param])
+                setattr(self, param, pval)
+        else:
+            self.cosmological_simulation = 0.0
+            kpc_unit = self.parameters.get('dKpcUnit', 1.0)
+            self._unit_base['cm'] = 1.0 / (kpc_unit * cm_per_kpc)
 
         self.filename_template = self.parameter_filename
         self.file_count = 1
@@ -432,12 +467,17 @@
 
     def _set_units(self):
         super(TipsyStaticOutput, self)._set_units()
-        DW = (self.domain_right_edge - self.domain_left_edge).max()
-        cosmo = Cosmology(self.hubble_constant * 100.0,
-                          self.omega_matter, self.omega_lambda)
-        length_unit = DW * self.units['cm'] # Get it in proper cm
-        density_unit = cosmo.CriticalDensity(self.current_redshift)
-        mass_unit = density_unit * length_unit**3
+        if self.cosmological_simulation:
+            DW = (self.domain_right_edge - self.domain_left_edge).max()
+            cosmo = Cosmology(self.hubble_constant * 100.0,
+                              self.omega_matter, self.omega_lambda)
+            length_unit = DW * self.units['cm'] # Get it in proper cm
+            density_unit = cosmo.CriticalDensity(self.current_redshift)
+            mass_unit = density_unit * length_unit**3
+        else:
+            mass_unit = self.parameters.get('dMsolUnit', 1.0) * mass_sun_cgs
+            length_unit = self.parameters.get('dKpcUnit', 1.0) * cm_per_kpc
+            density_unit = mass_unit / length_unit**3
         time_unit = 1.0 / np.sqrt(G*density_unit)
         velocity_unit = length_unit / time_unit
         self.conversion_factors["velocity"] = velocity_unit


https://bitbucket.org/yt_analysis/yt-3.0/commits/e018996fcb31/
Changeset:   e018996fcb31
Branch:      yt-3.0
User:        drudd
Date:        2013-08-09 20:06:38
Summary:     Fixes for artio
Affected #:  2 files

diff -r 8be77576736895c1588e52e1ca5630e5dd4b8878 -r e018996fcb3137effa6a5ba013f4105c398684f6 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -188,8 +188,7 @@
         status = artio_fileset_open_particles( self.handle )
         check_artio_status(status)
    
-    # this should possibly be __dealloc__ 
-    def __del__(self) :
+    def __dealloc__(self) :
         if self.num_octs_per_level : free(self.num_octs_per_level)
         if self.grid_variables : free(self.grid_variables)
 

diff -r 8be77576736895c1588e52e1ca5630e5dd4b8878 -r e018996fcb3137effa6a5ba013f4105c398684f6 yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -45,7 +45,7 @@
 
     def _read_particle_selection(self, chunks, selector, fields):
         # TODO: determine proper datatype for fields
-        tr = dict((ftuple, np.empty(0, dtype='float32')) for ftuple in fields)
+        tr = dict((ftuple, np.empty(0, dtype='float64')) for ftuple in fields)
         for onechunk in chunks:
             for artchunk in onechunk.objs:
                 artchunk.fill_particles(tr, fields)


https://bitbucket.org/yt_analysis/yt-3.0/commits/68d162e0028d/
Changeset:   68d162e0028d
Branch:      yt-3.0
User:        drudd
Date:        2013-08-13 22:47:24
Summary:     Removed false assertion that periodicity support was broken when domain_left_edge != 0
Affected #:  1 file

diff -r e018996fcb3137effa6a5ba013f4105c398684f6 -r 68d162e0028d803bc5bb75b741f5ececaf447d39 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -123,10 +123,6 @@
         self.overlap_cells = 0
 
         for i in range(3) :
-            if dobj.pf.periodicity[i] and dobj.pf.domain_left_edge[i] != 0.0 :
-                print "SelectorObject periodicity assumes left_edge == 0"
-                raise RuntimeError
-
             self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
                                    dobj.pf.domain_left_edge[i]
             self.periodicity[i] = dobj.pf.periodicity[i]


https://bitbucket.org/yt_analysis/yt-3.0/commits/02acc0921a62/
Changeset:   02acc0921a62
Branch:      yt-3.0
User:        drudd
Date:        2013-08-14 23:40:39
Summary:     Changed RegionSelector to operate on regions with left_edge inside domain, right edge inside or one periodic image away
Affected #:  1 file

diff -r 68d162e0028d803bc5bb75b741f5ececaf447d39 -r 02acc0921a629c73055e5bff67416d60adfed2af yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -470,7 +470,7 @@
         cdef int i
         cdef np.float64_t dist, dist2 = 0
         for i in range(3):
-            dist = self.difference( pos[i], self.center[i], i )
+            dist = self.difference(pos[i], self.center[i], i)
             dist2 += dist*dist
         if dist2 <= self.radius2: return 1
         return 0
@@ -482,7 +482,7 @@
         cdef int i
         cdef np.float64_t dist, dist2 = 0
         for i in range(3):
-            dist = self.difference( pos[i], self.center[i], i ) 
+            dist = self.difference(pos[i], self.center[i], i) 
             dist2 += dist*dist
         dist = self.radius+radius
         if dist2 <= dist*dist: return 1
@@ -503,7 +503,7 @@
         dist = 0
         for i in range(3):
             box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.difference( box_center, self.center[i], i )
+            relcenter = self.difference(box_center, self.center[i], i)
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
             dist += closest*closest
@@ -519,14 +519,36 @@
 cdef class RegionSelector(SelectorObject):
     cdef np.float64_t left_edge[3]
     cdef np.float64_t right_edge[3]
+    cdef np.float64_t right_edge_shift[3]
     cdef np.float64_t dx_pad
 
     def __init__(self, dobj):
         cdef int i
+        cdef np.float64_t region_width, domain_width
         self.dx_pad =dobj._dx_pad
         for i in range(3):
+            region_width = dobj.right_edge[i] - dobj.left_edge[i]
+            domain_width = dobj.pf.domain_right_edge[i] - dobj.pf.domain_left_edge[i]
+
+            if region_width <= 0 or region_width > domain_width:
+                raise RuntimeError
+
+            if dobj.pf.periodicity[i]:
+                # shift so left_edge guaranteed in domain
+                if dobj.left_edge[i] < dobj.pf.domain_left_edge[i]:
+                    dobj.left_edge[i] += domain_width
+                    dobj.right_edge[i] += domain_width
+                elif dobj.left_edge[i] > dobj.pf.domain_right_edge[i]:
+                    dobj.left_edge[i] += domain_width
+                    dobj.right_edge[i] += domain_width
+            else:
+                if dobj.left_edge[i] < dobj.pf.domain_left_edge or \
+                   dobj.right_edge[i] > dobj.pf.domain_right_edge:
+                    raise RuntimeError
+                
             self.left_edge[i] = dobj.left_edge[i]
             self.right_edge[i] = dobj.right_edge[i]
+            self.right_edge_shift[i] = dobj.right_edge[i] - domain_width
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -536,18 +558,10 @@
         cdef int i, shift, included
         cdef np.float64_t LE, RE
         for i in range(3):
-            if not self.periodicity[i]:
-                if left_edge[i] > self.right_edge[i]: return 0
-                if right_edge[i] < self.left_edge[i]: return 0
-            else:
-                included = 1
-                for shift in range(3):
-                    LE = left_edge[i] + self.domain_width[i] * (shift - 1)
-                    RE = right_edge[i] + self.domain_width[i] * (shift - 1)
-                    if LE > self.right_edge[i]: continue
-                    if RE < self.left_edge[i]: continue
-                    included = 1
-                if included == 0: return 0
+            if (right_edge[i] < self.left_edge[i] and \
+                left_edge[i] >= self.right_edge_shift[i]) or \
+                left_edge[i] >= self.right_edge[i]:
+                return 0
         return 1
 
     @cython.boundscheck(False)
@@ -567,21 +581,11 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_point(self, np.float64_t pos[3]) nogil:
-        # assume pos[3] is inside domain
-        cdef int i, shift, included
-        cdef np.float64_t dxp, ppos
+        cdef int i
         for i in range(3):
-            if not self.periodicity[i]:
-                if pos[i] < self.left_edge[i]: return 0
-                if pos[i] > self.right_edge[i]: return 0
-            else:
-                included = 0
-                for shift in range(3):
-                    ppos = pos[i] + self.domain_width[i] * (shift - 1)
-                    if ppos < self.left_edge[i]: continue
-                    if ppos > self.right_edge[i]: continue
-                    included = 1
-                if included == 0: return 0
+            if (self.right_edge_shift[i] <= pos[i] < self.left_edge[i]) or \
+               pos[i] >= self.right_edge[i]:
+                return 0
         return 1
 
     def _hash_vals(self):
@@ -620,7 +624,7 @@
         cdef int i
         h = d = 0
         for i in range(3):
-            temp = self.difference( pos[i], self.center[i], i )
+            temp = self.difference(pos[i], self.center[i], i)
             h += temp * self.norm_vec[i]
             d += temp*temp
         r2 = (d - h*h)
@@ -635,7 +639,7 @@
         cdef int i
         h = d = 0
         for i in range(3):
-            temp = self.difference( pos[i], self.center[i], i )
+            temp = self.difference(pos[i], self.center[i], i)
             h += pos[i] * self.norm_vec[i]
             d += temp*temp
         r2 = (d - h*h)
@@ -678,7 +682,7 @@
                     pos[2] = arr[k][2]
                     H = D = 0
                     for n in range(3):
-                        temp = self.difference( pos[n], self.center[n], n )
+                        temp = self.difference(pos[n], self.center[n], n)
                         H += (temp * self.norm_vec[n])
                         D += temp*temp
                     R2 = (D - H*H)
@@ -800,7 +804,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
-        cdef np.float64_t dist = self.difference( pos[self.axis], self.coord, self.axis )
+        cdef np.float64_t dist = self.difference(pos[self.axis], self.coord, self.axis)
         if dist*dist < radius*radius:
             return 1
         return 0
@@ -853,8 +857,8 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
-        cdef np.float64_t dx = self.difference( pos[self.px_ax], self.px, self.px_ax )
-        cdef np.float64_t dy = self.difference( pos[self.py_ax], self.py, self.py_ax )
+        cdef np.float64_t dx = self.difference(pos[self.px_ax], self.px, self.px_ax)
+        cdef np.float64_t dy = self.difference(pos[self.py_ax], self.py, self.py_ax)
         if dx*dx + dy*dy < radius*radius:
             return 1
         return 0
@@ -1129,7 +1133,7 @@
         cdef int i
         cdef np.float64_t dist2 = 0
         for i in range(3):
-            dist2 += self.difference( pos[i], self.center[i], i )**2
+            dist2 += self.difference(pos[i], self.center[i], i)**2
         if dist2 <= (self.mag[0]+radius)**2: return 1
         return 0
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/b93fb828bc3e/
Changeset:   b93fb828bc3e
Branch:      yt-3.0
User:        drudd
Date:        2013-08-14 23:48:12
Summary:     Fixed bug with periodicity check in RegionSelector
Affected #:  1 file

diff -r 02acc0921a629c73055e5bff67416d60adfed2af -r b93fb828bc3e8aea735a781eda210132f9b56bc3 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -531,6 +531,7 @@
             domain_width = dobj.pf.domain_right_edge[i] - dobj.pf.domain_left_edge[i]
 
             if region_width <= 0 or region_width > domain_width:
+                print "Error: bad region width", region_width, domain_width
                 raise RuntimeError
 
             if dobj.pf.periodicity[i]:
@@ -542,8 +543,10 @@
                     dobj.left_edge[i] += domain_width
                     dobj.right_edge[i] += domain_width
             else:
-                if dobj.left_edge[i] < dobj.pf.domain_left_edge or \
-                   dobj.right_edge[i] > dobj.pf.domain_right_edge:
+                if dobj.left_edge[i] < dobj.pf.domain_left_edge[i] or \
+                   dobj.right_edge[i] > dobj.pf.domain_right_edge[i]:
+                    print "Error: bad Region in non-periodic domain:", dobj.left_edge[i], \
+                        dobj.pf.domain_left_edge[i], dobj.right_edge[i], dobj.pf.domain_right_edge[i]
                     raise RuntimeError
                 
             self.left_edge[i] = dobj.left_edge[i]


https://bitbucket.org/yt_analysis/yt-3.0/commits/b91299c2d7fa/
Changeset:   b91299c2d7fa
Branch:      yt-3.0
User:        drudd
Date:        2013-08-15 21:10:30
Summary:     Changed checks to allow RegionSelector to operate on regions larger than the domain (when the domain is periodic).  Passes all tests
Affected #:  1 file

diff -r b93fb828bc3e8aea735a781eda210132f9b56bc3 -r b91299c2d7facaf2216fab03b7dbd87baa78b295 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -526,12 +526,13 @@
         cdef int i
         cdef np.float64_t region_width, domain_width
         self.dx_pad =dobj._dx_pad
+
         for i in range(3):
             region_width = dobj.right_edge[i] - dobj.left_edge[i]
             domain_width = dobj.pf.domain_right_edge[i] - dobj.pf.domain_left_edge[i]
 
-            if region_width <= 0 or region_width > domain_width:
-                print "Error: bad region width", region_width, domain_width
+            if region_width <= 0:
+                print "Error: region right edge < left edge", region_width
                 raise RuntimeError
 
             if dobj.pf.periodicity[i]:


https://bitbucket.org/yt_analysis/yt-3.0/commits/0103d80c177d/
Changeset:   0103d80c177d
Branch:      yt-3.0
User:        drudd
Date:        2013-08-16 20:48:25
Summary:     Added optimized count_cells and fill_mask to SliceSelector
Affected #:  1 file

diff -r b91299c2d7facaf2216fab03b7dbd87baa78b295 -r 0103d80c177dfe60a078055a58e0d1a6ca51f892 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -328,7 +328,6 @@
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         child_mask = gobj.child_mask
         cdef np.ndarray[np.uint8_t, ndim=3] mask
-        cdef int ind[3][2]
         cdef int dim[3]
         cdef np.ndarray[np.float64_t, ndim=1] odds = gobj.dds
         cdef np.ndarray[np.float64_t, ndim=1] left_edge = gobj.LeftEdge
@@ -786,11 +785,63 @@
 cdef class SliceSelector(SelectorObject):
     cdef int axis
     cdef np.float64_t coord
+    cdef int ax, ay
 
     def __init__(self, dobj):
         self.axis = dobj.axis
         self.coord = dobj.coord
 
+        ax = (self.axis+1) % 3
+        ay = (self.axis+2) % 3
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    def count_cells(self, gobj):
+        # optimization if we can ignore the child mask
+        if gobj.level < self.min_level or gobj.level > self.max_level:
+            return 0
+        elif gobj.level == self.max_level:
+            return gobj.ActiveDimensions[self.ax]*gobj.ActiveDimensions[self.ay]
+        else:
+            return super(SliceSelector, self).count_cells(gobj)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    def fill_mask(self, gobj):
+        cdef np.ndarray[np.uint8_t, ndim=3] mask
+        cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
+        cdef int i, j, k
+        cdef int total = 0
+        cdef int this_level = 0
+        cdef int ind[3][2]
+        cdef np.int32_t level = gobj.Level
+
+        if level < self.min_level or level > self.max_level:
+            return None
+        else:
+            child_mask = gobj.child_mask
+            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8 )
+            if level == self.max_level:
+                this_level = 1
+            for i in range(3):
+                if i == self.axis:
+                    ind[i][0] = <int> ((self.coord - gobj.LeftEdge[i])/gobj.dds[i])
+                    ind[i][1] = ind[i][0] + 1
+                else:
+                    ind[i][0] = 0
+                    ind[i][1] = gobj.ActiveDimensions[i]
+            with nogil:
+                for i in range(ind[0][0],ind[0][1]):
+                    for j in range(ind[1][0],ind[1][1]):
+                        for k in range(ind[2][0],ind[2][1]):
+                            if this_level == 1 or child_mask[i,j,k]:
+                                mask[i,j,k] = 1
+                                total += 1
+            if total == 0: return None
+            return mask.astype("bool")
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)


https://bitbucket.org/yt_analysis/yt-3.0/commits/7007e3a7d9e9/
Changeset:   7007e3a7d9e9
Branch:      yt-3.0
User:        drudd
Date:        2013-08-16 21:49:48
Summary:     Added optimized count_cells and fill_mask to OrthoRaySelector
Affected #:  1 file

diff -r 0103d80c177dfe60a078055a58e0d1a6ca51f892 -r 7007e3a7d9e9e05491228058dbae4e5f79aa400b yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -896,6 +896,56 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
+    def count_cells(self, gobj):
+        # optimization if we can ignore the child mask
+        if gobj.level < self.min_level or gobj.level > self.max_level:
+            return 0
+        elif gobj.level == self.max_level:
+            return gobj.ActiveDimensions[self.axis]
+        else:
+            return super(OrthoRaySelector, self).count_cells(gobj)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    def fill_mask(self, gobj):
+        cdef np.ndarray[np.uint8_t, ndim=3] mask
+        cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
+        cdef int i, j, k
+        cdef int total = 0
+        cdef int this_level = 0
+        cdef int ind[3][2]
+        cdef np.int32_t level = gobj.Level
+
+        if level < self.min_level or level > self.max_level:
+            return None
+        else:
+            child_mask = gobj.child_mask
+            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8 )
+            if level == self.max_level:
+                this_level = 1
+            ind[self.axis][0] = 0
+            ind[self.axis][1] = gobj.ActiveDimensions[self.axis]
+            ind[self.px_ax][0] = <int> ((self.px - gobj.LeftEdge[self.px_ax]) /
+                                        gobj.dds[self.px_ax])
+            ind[self.px_ax][1] = ind[self.px_ax][0] + 1
+            ind[self.py_ax][0] = <int> ((self.py - gobj.LeftEdge[self.py_ax]) /
+                                        gobj.dds[self.py_ax])
+            ind[self.py_ax][1] = ind[self.py_ax][0] + 1
+
+            with nogil:
+                for i in range(ind[0][0],ind[0][1]):
+                    for j in range(ind[1][0],ind[1][1]):
+                        for k in range(ind[2][0],ind[2][1]):
+                            if this_level == 1 or child_mask[i,j,k]:
+                                mask[i,j,k] = 1
+                                total += 1
+            if total == 0: return None
+            return mask.astype("bool")
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
            self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
@@ -975,6 +1025,7 @@
         cdef np.ndarray[np.float64_t, ndim=3] t, dt
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         cdef int i
+        cdef int total = 0
         cdef IntegrationAccumulator ia
         cdef VolumeContainer vc
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
@@ -997,13 +1048,14 @@
                 for k in range(dt.shape[2]):
                     if dt[i,j,k] >= 0:
                         mask[i,j,k] = 1
+                        total += 1
+        if total == 0: return None
         return mask.astype("bool")
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def count_cells(self, gobj):
-        return self.fill_mask(gobj).sum()
+        mask = self.fill_mask(gobj)
+        if mask is None: return 0
+        return mask.sum()
     
     @cython.boundscheck(False)
     @cython.wraparound(False)


https://bitbucket.org/yt_analysis/yt-3.0/commits/483f2bdda2da/
Changeset:   483f2bdda2da
Branch:      yt-3.0
User:        drudd
Date:        2013-08-16 21:50:50
Summary:     Removed reslice from YTFixedResCuttingPlaneBase
Affected #:  1 file

diff -r 7007e3a7d9e9e05491228058dbae4e5f79aa400b -r 483f2bdda2da95e6b308b17705bdd6555941047a yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -644,38 +644,6 @@
             raise SyntaxError("Making a fixed resolution slice with "
                               "particles isn't supported yet.")
 
-    def reslice(self, normal, center, width):
-
-        # Cleanup
-        del self._coord
-        del self._pixelmask
-
-        self.center = center
-        self.width = width
-        self.dds = self.width / self.dims
-        self.set_field_parameter('center', center)
-        self._norm_vec = normal/np.sqrt(np.dot(normal,normal))
-        self._d = -1.0 * np.dot(self._norm_vec, self.center)
-        # First we try all three, see which has the best result:
-        vecs = np.identity(3)
-        _t = np.cross(self._norm_vec, vecs).sum(axis=1)
-        ax = _t.argmax()
-        self._x_vec = np.cross(vecs[ax,:], self._norm_vec).ravel()
-        self._x_vec /= np.sqrt(np.dot(self._x_vec, self._x_vec))
-        self._y_vec = np.cross(self._norm_vec, self._x_vec).ravel()
-        self._y_vec /= np.sqrt(np.dot(self._y_vec, self._y_vec))
-        self.set_field_parameter('cp_x_vec',self._x_vec)
-        self.set_field_parameter('cp_y_vec',self._y_vec)
-        self.set_field_parameter('cp_z_vec',self._norm_vec)
-        # Calculate coordinates of each pixel
-        _co = self.dds * \
-              (np.mgrid[-self.dims/2 : self.dims/2,
-                        -self.dims/2 : self.dims/2] + 0.5)
-
-        self._coord = self.center + np.outer(_co[0,:,:], self._x_vec) + \
-                      np.outer(_co[1,:,:], self._y_vec)
-        self._pixelmask = np.ones(self.dims*self.dims, dtype='int8')
-
     def get_data(self, fields):
         """
         Iterates over the list of fields and generates/reads them all.


https://bitbucket.org/yt_analysis/yt-3.0/commits/b13febd90137/
Changeset:   b13febd90137
Branch:      yt-3.0
User:        drudd
Date:        2013-08-16 21:54:14
Summary:     Removed dx_pad from RegionSelector
Affected #:  2 files

diff -r 483f2bdda2da95e6b308b17705bdd6555941047a -r b13febd90137f0acac6088414f3a3eabedf74fb6 yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -828,7 +828,6 @@
     """
     _type_name = "region"
     _con_args = ('center', 'left_edge', 'right_edge')
-    _dx_pad = 0.5
     def __init__(self, center, left_edge, right_edge, fields = None,
                  pf = None, **kwargs):
         YTSelectionContainer3D.__init__(self, center, fields, pf, **kwargs)

diff -r 483f2bdda2da95e6b308b17705bdd6555941047a -r b13febd90137f0acac6088414f3a3eabedf74fb6 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -519,12 +519,10 @@
     cdef np.float64_t left_edge[3]
     cdef np.float64_t right_edge[3]
     cdef np.float64_t right_edge_shift[3]
-    cdef np.float64_t dx_pad
 
     def __init__(self, dobj):
         cdef int i
         cdef np.float64_t region_width, domain_width
-        self.dx_pad =dobj._dx_pad
 
         for i in range(3):
             region_width = dobj.right_edge[i] - dobj.left_edge[i]
@@ -571,14 +569,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
-        cdef int i
-        cdef np.float64_t LE[3], RE[3]
-        if self.dx_pad == 0.0:
-            return self.select_point(pos)
-        for i in range(3):
-            LE[i] = pos[i] - self.dx_pad * dds[i]
-            RE[i] = pos[i] + self.dx_pad * dds[i]
-        return self.select_bbox(LE, RE)
+        return self.select_point(pos)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -593,8 +584,7 @@
 
     def _hash_vals(self):
         return (self.left_edge[0], self.left_edge[1], self.left_edge[2],
-                self.right_edge[0], self.right_edge[1], self.right_edge[2],
-                self.dx_pad)
+                self.right_edge[0], self.right_edge[1], self.right_edge[2])
 
 region_selector = RegionSelector
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/d12b4f6da295/
Changeset:   d12b4f6da295
Branch:      yt-3.0
User:        drudd
Date:        2013-08-16 22:48:06
Summary:     Removed count_cells function from all Selector objects
Affected #:  1 file

diff -r b13febd90137f0acac6088414f3a3eabedf74fb6 -r d12b4f6da2954ab28e5b953ace249c05617cdd34 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -287,43 +287,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        cdef np.ndarray[np.float64_t, ndim=1] odds = gobj.dds
-        cdef np.ndarray[np.float64_t, ndim=1] left_edge = gobj.LeftEdge
-        cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
-        cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
-        cdef np.float64_t dds[3], pos[3]
-        cdef int i, j, k, dim[3]
-        child_mask = gobj.child_mask
-        for i in range(3):
-            dim[i] = gobj.ActiveDimensions[i]
-            dds[i] = odds[i]
-        cdef int count = 0
-        # Check for the level bounds
-        cdef np.int32_t level = gobj.Level
-        if level < self.min_level or level > self.max_level:
-            return count
-        # We set this to 1 if we ignore child_mask
-        cdef int this_level = 0
-        if level == self.max_level:
-            this_level = 1
-        with nogil:
-            pos[0] = left_edge[0] + dds[0] * 0.5
-            for i in range(dim[0]):
-                pos[1] = left_edge[1] + dds[1] * 0.5
-                for j in range(dim[1]):
-                    pos[2] = left_edge[2] + dds[2] * 0.5
-                    for k in range(dim[2]):
-                        if child_mask[i,j,k] == 1 or this_level == 1:
-                            count += self.select_cell(pos, dds)
-                        pos[2] += dds[1]
-                    pos[1] += dds[1]
-                pos[0] += dds[0]
-        return count
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         child_mask = gobj.child_mask
@@ -787,18 +750,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        # optimization if we can ignore the child mask
-        if gobj.level < self.min_level or gobj.level > self.max_level:
-            return 0
-        elif gobj.level == self.max_level:
-            return gobj.ActiveDimensions[self.ax]*gobj.ActiveDimensions[self.ay]
-        else:
-            return super(SliceSelector, self).count_cells(gobj)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3] mask
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
@@ -886,18 +837,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        # optimization if we can ignore the child mask
-        if gobj.level < self.min_level or gobj.level > self.max_level:
-            return 0
-        elif gobj.level == self.max_level:
-            return gobj.ActiveDimensions[self.axis]
-        else:
-            return super(OrthoRaySelector, self).count_cells(gobj)
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3] mask
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
@@ -1042,11 +981,6 @@
         if total == 0: return None
         return mask.astype("bool")
 
-    def count_cells(self, gobj):
-        mask = self.fill_mask(gobj)
-        if mask is None: return 0
-        return mask.sum()
-    
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -1165,12 +1099,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        return gobj.ActiveDimensions.prod()
-    
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3] mask 
         mask = np.ones(gobj.ActiveDimensions, dtype='uint8')
@@ -1287,12 +1215,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        return gobj.ActiveDimensions.prod()
-    
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         return np.ones(gobj.ActiveDimensions, dtype='bool')
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/beb5c6a5d35e/
Changeset:   beb5c6a5d35e
Branch:      yt-3.0
User:        drudd
Date:        2013-08-16 23:05:20
Summary:     Formatting fixes
Affected #:  2 files

diff -r d12b4f6da2954ab28e5b953ace249c05617cdd34 -r beb5c6a5d35ef0c5b9febaf407acfba8043f54c4 yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -45,10 +45,10 @@
                                np.int32_t level, Oct *o = ?) nogil
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil
+    cdef int select_point(self, np.float64_t pos[3]) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil
     cdef int select_bbox(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3]) nogil
 
-	# compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
+    # compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
     cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil

diff -r d12b4f6da2954ab28e5b953ace249c05617cdd34 -r beb5c6a5d35ef0c5b9febaf407acfba8043f54c4 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -74,7 +74,7 @@
     for i in range(mask.shape[0]):
         for j in range(mask.shape[1]):
             for k in range(mask.shape[2]):
-                if mask[i,j,k] == 1:
+                if mask[i, j, k] == 1:
                     if transpose == 1:
                         indices[cpos, 0] = k
                         indices[cpos, 1] = j
@@ -99,8 +99,8 @@
     for i in range(mask.shape[0]):
         for j in range(mask.shape[1]):
             for k in range(mask.shape[2]):
-                if mask[i,j,k] == 1:
-                    out[offset + count] = vals[i,j,k]
+                if mask[i, j, k] == 1:
+                    out[offset + count] = vals[i, j, k]
                     count += 1
     return count
 
@@ -145,7 +145,7 @@
                 for i in range(3):
                     LE[i] = left_edges[n, i]
                     RE[i] = right_edges[n, i]
-                gridi[n] = self.select_grid(LE, RE, levels[n,0])
+                gridi[n] = self.select_grid(LE, RE, levels[n, 0])
         return gridi.astype("bool")
 
     def count_octs(self, OctreeContainer octree, int domain_id = -1):
@@ -221,7 +221,7 @@
                     for k in range(2):
                         ch = NULL
                         if root.children != NULL:
-                            ch = root.children[cind(i,j,k)]
+                            ch = root.children[cind(i, j, k)]
                         if iter == 1 and next_level == 1 and ch != NULL:
                             data.pos[0] = (data.pos[0] << 1) + i
                             data.pos[1] = (data.pos[1] << 1) + j
@@ -257,15 +257,15 @@
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
         if level < self.min_level or level > self.max_level: return 0
-        return self.select_bbox(left_edge,right_edge)
+        return self.select_bbox(left_edge, right_edge)
  
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         return 0
 
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         return 0
 
     cdef int select_bbox(self, np.float64_t left_edge[3],
@@ -318,9 +318,9 @@
                 for j in range(dim[1]):
                     pos[2] = left_edge[2] + dds[2] * 0.5
                     for k in range(dim[2]):
-                        if child_mask[i,j,k] == 1 or this_level == 1:
-                            mask[i,j,k] = self.select_cell(pos, dds)
-                            total += mask[i,j,k]
+                        if child_mask[i, j, k] == 1 or this_level == 1:
+                            mask[i, j, k] = self.select_cell(pos, dds)
+                            total += mask[i, j, k]
                         pos[2] += dds[1]
                     pos[1] += dds[1]
                 pos[0] += dds[0]
@@ -570,7 +570,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
-        return self.select_point( pos ) 
+        return self.select_point(pos) 
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -590,7 +590,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         cdef np.float64_t h, d, r2, temp
         cdef int i
         h = d = 0
@@ -607,7 +607,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil:
+                               np.float64_t right_edge[3]) nogil:
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3], H, D, R2, temp
         cdef int i, j, k, n
@@ -679,14 +679,14 @@
             right_edge[i] = pos[i] + 0.5*dds[i]
         return self.select_bbox(left_edge, right_edge)
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         cdef int i
         cdef np.float64_t height = self.d
         for i in range(3) :
@@ -698,7 +698,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil:
+                               np.float64_t right_edge[3]) nogil:
         cdef int i, j, k, n
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3]
@@ -763,7 +763,7 @@
             return None
         else:
             child_mask = gobj.child_mask
-            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8 )
+            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8)
             if level == self.max_level:
                 this_level = 1
             for i in range(3):
@@ -774,11 +774,11 @@
                     ind[i][0] = 0
                     ind[i][1] = gobj.ActiveDimensions[i]
             with nogil:
-                for i in range(ind[0][0],ind[0][1]):
-                    for j in range(ind[1][0],ind[1][1]):
-                        for k in range(ind[2][0],ind[2][1]):
-                            if this_level == 1 or child_mask[i,j,k]:
-                                mask[i,j,k] = 1
+                for i in range(ind[0][0], ind[0][1]):
+                    for j in range(ind[1][0], ind[1][1]):
+                        for k in range(ind[2][0], ind[2][1]):
+                            if this_level == 1 or child_mask[i, j, k]:
+                                mask[i, j, k] = 1
                                 total += 1
             if total == 0: return None
             return mask.astype("bool")
@@ -792,14 +792,14 @@
             return 1
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         cdef np.float64_t dist = self.difference(pos[self.axis], self.coord, self.axis)
         if dist*dist < radius*radius:
             return 1
@@ -809,7 +809,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil:
+                               np.float64_t right_edge[3]) nogil:
         if left_edge[self.axis] <= self.coord < right_edge[self.axis]:
             return 1
         return 0
@@ -850,7 +850,7 @@
             return None
         else:
             child_mask = gobj.child_mask
-            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8 )
+            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8)
             if level == self.max_level:
                 this_level = 1
             ind[self.axis][0] = 0
@@ -863,11 +863,11 @@
             ind[self.py_ax][1] = ind[self.py_ax][0] + 1
 
             with nogil:
-                for i in range(ind[0][0],ind[0][1]):
-                    for j in range(ind[1][0],ind[1][1]):
-                        for k in range(ind[2][0],ind[2][1]):
-                            if this_level == 1 or child_mask[i,j,k]:
-                                mask[i,j,k] = 1
+                for i in range(ind[0][0], ind[0][1]):
+                    for j in range(ind[1][0], ind[1][1]):
+                        for k in range(ind[2][0], ind[2][1]):
+                            if this_level == 1 or child_mask[i, j, k]:
+                                mask[i, j, k] = 1
                                 total += 1
             if total == 0: return None
             return mask.astype("bool")
@@ -883,14 +883,14 @@
             return 1
         return 0
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         cdef np.float64_t dx = self.difference(pos[self.px_ax], self.px, self.px_ax)
         cdef np.float64_t dy = self.difference(pos[self.py_ax], self.py, self.py_ax)
         if dx*dx + dy*dy < radius*radius:
@@ -901,7 +901,7 @@
     @cython.wraparound(False)
     @cython.cdivision(True)
     cdef int select_bbox(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3] ) nogil:
+                               np.float64_t right_edge[3]) nogil:
         if left_edge[self.px_ax] <= self.px < right_edge[self.px_ax] and \
            left_edge[self.py_ax] <= self.py < right_edge[self.py_ax] :
             return 1
@@ -975,8 +975,8 @@
         for i in range(dt.shape[0]):
             for j in range(dt.shape[1]):
                 for k in range(dt.shape[2]):
-                    if dt[i,j,k] >= 0:
-                        mask[i,j,k] = 1
+                    if dt[i, j, k] >= 0:
+                        mask[i, j, k] = 1
                         total += 1
         if total == 0: return None
         return mask.astype("bool")
@@ -1011,19 +1011,19 @@
         for i in range(dt.shape[0]):
             for j in range(dt.shape[1]):
                 for k in range(dt.shape[2]):
-                    if dt[i,j,k] >= 0:
-                        tr[ni] = t[i,j,k]
-                        dtr[ni] = dt[i,j,k]
+                    if dt[i, j, k] >= 0:
+                        tr[ni] = t[i, j, k]
+                        dtr[ni] = dt[i, j, k]
                         ni += 1
         if not (ni == ia.hits):
             print ni, ia.hits
         return dtr, tr
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         # two 0-volume constructs don't intersect
         return 0
 
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         # not implemented
         return 0        
 
@@ -1224,7 +1224,7 @@
     cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         # we apparently don't check if the point actually lies in the grid..
         return 1
 
@@ -1256,7 +1256,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         return 1
 
     @cython.boundscheck(False)
@@ -1322,7 +1322,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         return 1
 
     @cython.boundscheck(False)
@@ -1383,10 +1383,10 @@
                          Oct *o = NULL) nogil:
         return 1
 
-    cdef int select_point(self, np.float64_t pos[3] ) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         return 1
 
-    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius ) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         return 1
 
     cdef int select_bbox(self, np.float64_t left_edge[3],


https://bitbucket.org/yt_analysis/yt-3.0/commits/683de674b308/
Changeset:   683de674b308
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 03:29:20
Summary:     Merging with selector_generalize.

Note that ARTIO is giving slightly different results in some cases, so this may
not be completely finished.
Affected #:  15 files

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -498,10 +498,13 @@
     def _fill_fields(self, fields):
         output_fields = [np.zeros(self.ActiveDimensions, dtype="float64")
                          for field in fields]
+        domain_dims = self.pf.domain_dimensions.astype("int64") \
+                    * self.pf.refine_by**self.level
         for chunk in self._data_source.chunks(fields, "io"):
             input_fields = [chunk[field] for field in fields]
             fill_region(input_fields, output_fields, self.level,
-                        self.global_startindex, chunk.icoords, chunk.ires)
+                        self.global_startindex, chunk.icoords, chunk.ires,
+                        domain_dims, self.pf.refine_by)
         for name, v in zip(fields, output_fields):
             self[name] = v
 
@@ -654,13 +657,14 @@
     def _fill_fields(self, fields):
         ls = self._initialize_level_state(fields)
         for level in range(self.level + 1):
-            tot = 0
+            domain_dims = self.pf.domain_dimensions.astype("int64") \
+                        * self.pf.refine_by**level
             for chunk in ls.data_source.chunks(fields, "io"):
                 chunk[fields[0]]
                 input_fields = [chunk[field] for field in fields]
-                tot += fill_region(input_fields, ls.fields, ls.current_level,
+                fill_region(input_fields, ls.fields, ls.current_level,
                             ls.global_startindex, chunk.icoords,
-                            chunk.ires)
+                            chunk.ires, domain_dims, self.pf.refine_by)
             self._update_level_state(ls)
         for name, v in zip(fields, ls.fields):
             if self.level > 0: v = v[1:-1,1:-1,1:-1]

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -497,11 +497,11 @@
         yield self, mask
 
     def _get_selector_mask(self, selector):
-        if id(selector) == self._last_selector_id:
+        if hash(selector) == self._last_selector_id:
             mask = self._last_mask
         else:
             self._last_mask = mask = selector.fill_mask(self)
-            self._last_selector_id = id(selector)
+            self._last_selector_id = hash(selector)
             if mask is None:
                 self._last_count = 0
             else:

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -183,7 +183,7 @@
         return n
 
     def count(self, selector):
-        if id(selector) == self._last_selector_id:
+        if hash(selector) == self._last_selector_id:
             if self._last_mask is None: return 0
             return self._last_mask.sum()
         self.select(selector)

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -248,33 +248,6 @@
         self._set_center(center)
         self.coord = coord
 
-    def reslice(self, coord):
-        """
-        Change the entire dataset, clearing out the current data and slicing at
-        a new location.  Not terribly useful except for in-place plot changes.
-        """
-        mylog.debug("Setting coordinate to %0.5e" % coord)
-        self.coord = coord
-        self.field_data.clear()
-
-    def shift(self, val):
-        """
-        Moves the slice coordinate up by either a floating point value, or an
-        integer number of indices of the finest grid.
-        """
-        if isinstance(val, types.FloatType):
-            # We add the dx
-            self.coord += val
-        elif isinstance(val, types.IntType):
-            # Here we assume that the grid is the max level
-            level = self.hierarchy.max_level
-            self.coord
-            dx = self.hierarchy.select_grids(level)[0].dds[self.axis]
-            self.coord += dx * val
-        else:
-            raise ValueError(val)
-        self.field_data.clear()
-
     def _generate_container_field(self, field):
         if self._current_chunk is None:
             self.hierarchy._identify_base_chunk(self)
@@ -375,7 +348,6 @@
         self._d = -1.0 * np.dot(self._norm_vec, self.center)
         self._x_vec = self.orienter.unit_vectors[0]
         self._y_vec = self.orienter.unit_vectors[1]
-        self._d = -1.0 * np.dot(self._norm_vec, self.center)
         # First we try all three, see which has the best result:
         vecs = np.identity(3)
         self._rot_mat = np.array([self._x_vec,self._y_vec,self._norm_vec])
@@ -672,38 +644,6 @@
             raise SyntaxError("Making a fixed resolution slice with "
                               "particles isn't supported yet.")
 
-    def reslice(self, normal, center, width):
-
-        # Cleanup
-        del self._coord
-        del self._pixelmask
-
-        self.center = center
-        self.width = width
-        self.dds = self.width / self.dims
-        self.set_field_parameter('center', center)
-        self._norm_vec = normal/np.sqrt(np.dot(normal,normal))
-        self._d = -1.0 * np.dot(self._norm_vec, self.center)
-        # First we try all three, see which has the best result:
-        vecs = np.identity(3)
-        _t = np.cross(self._norm_vec, vecs).sum(axis=1)
-        ax = _t.argmax()
-        self._x_vec = np.cross(vecs[ax,:], self._norm_vec).ravel()
-        self._x_vec /= np.sqrt(np.dot(self._x_vec, self._x_vec))
-        self._y_vec = np.cross(self._norm_vec, self._x_vec).ravel()
-        self._y_vec /= np.sqrt(np.dot(self._y_vec, self._y_vec))
-        self.set_field_parameter('cp_x_vec',self._x_vec)
-        self.set_field_parameter('cp_y_vec',self._y_vec)
-        self.set_field_parameter('cp_z_vec',self._norm_vec)
-        # Calculate coordinates of each pixel
-        _co = self.dds * \
-              (np.mgrid[-self.dims/2 : self.dims/2,
-                        -self.dims/2 : self.dims/2] + 0.5)
-
-        self._coord = self.center + np.outer(_co[0,:,:], self._x_vec) + \
-                      np.outer(_co[1,:,:], self._y_vec)
-        self._pixelmask = np.ones(self.dims*self.dims, dtype='int8')
-
     def get_data(self, fields):
         """
         Iterates over the list of fields and generates/reads them all.
@@ -888,7 +828,6 @@
     """
     _type_name = "region"
     _con_args = ('center', 'left_edge', 'right_edge')
-    _dx_pad = 0.5
     def __init__(self, center, left_edge, right_edge, fields = None,
                  pf = None, **kwargs):
         YTSelectionContainer3D.__init__(self, center, fields, pf, **kwargs)

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/data_objects/tests/test_ellipsoid.py
--- a/yt/data_objects/tests/test_ellipsoid.py
+++ b/yt/data_objects/tests/test_ellipsoid.py
@@ -5,13 +5,23 @@
     ytcfg["yt","loglevel"] = "50"
     ytcfg["yt","__withintesting"] = "True"
 
+def _difference(x1, x2, dw):
+    rel = x1 - x2
+    rel[rel >  dw/2.0] -= dw
+    rel[rel < -dw/2.0] += dw
+    return rel
+
 def test_ellipsoid():
     # We decompose in different ways
-    cs = [np.array([0.5, 0.5, 0.5]),
+    cs = [
+          np.array([0.5, 0.5, 0.5]),
           np.array([0.1, 0.2, 0.3]),
-          np.array([0.8, 0.8, 0.8])]
+          np.array([0.8, 0.8, 0.8])
+          ]
+    np.random.seed(int(0x4d3d3d3))
     for nprocs in [1, 2, 4, 8]:
         pf = fake_random_pf(64, nprocs = nprocs)
+        DW = pf.domain_right_edge - pf.domain_left_edge
         min_dx = 2.0/pf.domain_dimensions
         ABC = np.random.random((3, 12)) * 0.1
         e0s = np.random.random((3, 12))
@@ -26,10 +36,17 @@
                 e0 = e0s[:,i]
                 tilt = tilts[i]
                 ell = pf.h.ellipsoid(c, A, B, C, e0, tilt)
-                yield assert_equal, np.all(ell["Radius"] <= A), True
+                yield assert_array_less, ell["Radius"], A
                 p = np.array([ell[ax] for ax in 'xyz'])
-                v  = np.zeros_like(ell["Radius"])
-                v += (((p - c[:,None]) * ell._e0[:,None]).sum(axis=0) / ell._A)**2
-                v += (((p - c[:,None]) * ell._e1[:,None]).sum(axis=0) / ell._B)**2
-                v += (((p - c[:,None]) * ell._e2[:,None]).sum(axis=0) / ell._C)**2
-                yield assert_equal, np.all(np.sqrt(v) <= 1.0), True
+                dot_evec = [np.zeros_like(ell["Radius"]) for i in range(3)]
+                vecs = [ell._e0, ell._e1, ell._e2]
+                mags = [ell._A, ell._B, ell._C]
+                my_c = np.array([c]*p.shape[1]).transpose()
+                for ax_i in range(3):
+                    dist = _difference(p[ax_i,:], my_c[ax_i,:], DW[ax_i])
+                    for ax_j in range(3):
+                        dot_evec[ax_j] += dist * vecs[ax_j][ax_i]
+                dist = 0
+                for ax_i in range(3):
+                    dist += dot_evec[ax_i]**2.0 / mags[ax_i]**2.0
+                yield assert_array_less, dist, 1.0

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/data_objects/tests/test_fields.py
--- a/yt/data_objects/tests/test_fields.py
+++ b/yt/data_objects/tests/test_fields.py
@@ -24,6 +24,7 @@
 _base_fields = ["Density", "x-velocity", "y-velocity", "z-velocity"]
 
 def realistic_pf(fields, nprocs):
+    np.random.seed(int(0x4d3d3d3))
     pf = fake_random_pf(16, fields = fields, nprocs = nprocs)
     pf.parameters["HydroMethod"] = "streaming"
     pf.parameters["Gamma"] = 5.0/3.0
@@ -52,7 +53,7 @@
     def __call__(self):
         field = FieldInfo[self.field_name]
         deps = field.get_dependencies()
-        fields = deps.requested + _base_fields
+        fields = list(set(deps.requested + _base_fields))
         skip_grids = False
         needs_spatial = False
         for v in field.validators:
@@ -100,3 +101,8 @@
         for nproc in [1, 4, 8]:
             test_all_fields.__name__ = "%s_%s" % (field, nproc)
             yield TestFieldAccess(field, nproc)
+
+if __name__ == "__main__":
+    setup()
+    for t in test_all_fields():
+        t()

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/frontends/artio/_artio_caller.pyx
--- a/yt/frontends/artio/_artio_caller.pyx
+++ b/yt/frontends/artio/_artio_caller.pyx
@@ -204,8 +204,7 @@
         status = artio_fileset_open_particles( self.handle )
         check_artio_status(status)
    
-    # this should possibly be __dealloc__ 
-    def __del__(self) :
+    def __dealloc__(self) :
         if self.num_octs_per_level : free(self.num_octs_per_level)
         if self.grid_variables : free(self.grid_variables)
 
@@ -274,9 +273,6 @@
 
         cdef int num_fields = len(fields)
         cdef np.float64_t pos[3]
-        cdef np.float64_t dds[3]
-        cdef int eterm[3]
-        for i in range(3) : dds[i] = 0
 
         data = {}
         accessed_species = np.zeros( self.num_species, dtype="int")
@@ -322,7 +318,7 @@
 
             for ispec in range(self.num_species) : 
                 if accessed_species[ispec] :
-                    status = artio_particle_read_species_begin(self.handle, ispec);
+                    status = artio_particle_read_species_begin(self.handle, ispec)
                     check_artio_status(status)
  
                     for particle in range( self.num_particles_per_species[ispec] ) :
@@ -332,9 +328,9 @@
                         check_artio_status(status)
 
                         for i in range(3) :
-                            pos[i] = self.primary_variables[self.particle_position_index[3*ispec+i]] 
+                            pos[i] = self.primary_variables[self.particle_position_index[3*ispec+i]]
 
-                        if selector.select_cell(pos,dds,eterm) :
+                        if selector.select_point(pos) :
                             # loop over primary variables
                             for i,field in selected_primary[ispec] :
                                 count = len(data[field])
@@ -379,9 +375,10 @@
         cdef int64_t count
         cdef int64_t max_octs
         cdef double dpos[3]
-        cdef np.float64_t pos[3]
+        cdef np.float64_t left[3]
+        cdef np.float64_t right[3]
         cdef np.float64_t dds[3]
-        cdef int eterm[3]
+
         cdef int *field_order
         cdef int num_fields  = len(fields)
         field_order = <int*>malloc(sizeof(int)*num_fields)
@@ -443,12 +440,13 @@
                     for child in range(8) :
                         if not refined[child] :
                             for i in range(3) :
-                                pos[i] = dpos[i] + dds[i]*(0.5 if (child & (1<<i)) else -0.5)
+                                left[i] = (dpos[i]-dds[i]) if (child & (i<<1)) else dpos[i]
+                                right[i] = left[i] + dds[i]
 
-                            if selector.select_cell( pos, dds, eterm ) :
+                            if selector.select_bbox(left,right) :
                                 fcoords.resize((count+1, 3))
                                 for i in range(3) :
-                                    fcoords[count][i] = pos[i]
+                                    fcoords[count][i] = left[i]+0.5*dds[i]
                                 ires.resize(count+1)
                                 ires[count] = level
                                 for i in range(num_fields) :
@@ -490,26 +488,28 @@
         cdef int max_range_size = 1024
         cdef int coords[3]
         cdef int64_t sfc_start, sfc_end
-        cdef np.float64_t pos[3]
+        cdef np.float64_t left[3]
+        cdef np.float64_t right[3]
         cdef np.float64_t dds[3]
-        cdef int eterm[3]
         cdef artio_selection *selection
         cdef int i, j, k
-        for i in range(3): dds[i] = 1.0
 
         sfc_ranges=[]
         selection = artio_selection_allocate(self.handle)
         for i in range(self.num_grid) :
             # stupid cython
             coords[0] = i
-            pos[0] = coords[0] + 0.5
+            left[0] = coords[0]
+            right[0] = left[0] + 1.0
             for j in range(self.num_grid) :
                 coords[1] = j
-                pos[1] = coords[1] + 0.5
+                left[1] = coords[1]
+                right[1] = left[1] + 1.0
                 for k in range(self.num_grid) :
                     coords[2] = k 
-                    pos[2] = coords[2] + 0.5
-                    if selector.select_cell(pos, dds, eterm) :
+                    left[2] = coords[2] 
+                    right[2] = left[2] + 1.0
+                    if selector.select_bbox(left,right) :
                         status = artio_selection_add_root_cell(selection, coords)
                         check_artio_status(status)
 
@@ -1013,7 +1013,7 @@
         cdef np.int64_t sfc
         cdef np.float64_t pos[3], right_edge[3]
         cdef int num_cells = 0
-        cdef int i, eterm[3]
+        cdef int i
         return self.mask(selector).sum()
 
     def icoords(self, SelectorObject selector, np.int64_t num_octs = -1,
@@ -1096,7 +1096,7 @@
         cdef np.int64_t sfc
         cdef np.float64_t pos[3]
         cdef np.float64_t dpos[3]
-        cdef int dim, status, eterm[3], filled = 0
+        cdef int dim, status, filled = 0
         cdef int num_oct_levels, level
         cdef int max_level = self.artio_handle.max_level
         cdef int *num_octs_per_level = <int *>malloc(
@@ -1129,7 +1129,7 @@
         return filled
 
     def mask(self, SelectorObject selector, np.int64_t num_octs = -1):
-        cdef int i, status, eterm[3]
+        cdef int i, status
         cdef double dpos[3]
         cdef np.float64_t pos[3]
         if num_octs == -1:
@@ -1151,7 +1151,7 @@
             # Note that because we initialize to zeros, we can just continue if
             # it's not included.
             self.sfc_to_pos(sfc, pos)
-            if selector.select_cell(pos, self.dds, eterm) == 0: continue
+            if selector.select_cell(pos, self.dds) == 0: continue
             # Now we just need to check if the cells are refined.
             status = artio_grid_read_root_cell_begin( self.handle,
                 sfc, dpos, NULL, &num_oct_levels, num_octs_per_level)

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/geometry/selection_routines.pxd
--- a/yt/geometry/selection_routines.pxd
+++ b/yt/geometry/selection_routines.pxd
@@ -31,6 +31,8 @@
     cdef public np.int32_t min_level
     cdef public np.int32_t max_level
     cdef int overlap_cells
+    cdef np.float64_t domain_width[3]
+    cdef bint periodicity[3]
 
     cdef void recursively_visit_octs(self, Oct *root,
                         np.float64_t pos[3], np.float64_t dds[3],
@@ -41,11 +43,15 @@
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = ?) nogil
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil
+
+    cdef int select_point(self, np.float64_t pos[3]) nogil
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil
+
+    # compute periodic distance (if periodicity set) assuming 0->domain_width[i] coordinates
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil
 
 cdef class AlwaysSelector(SelectorObject):
     pass

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -74,7 +74,7 @@
     for i in range(mask.shape[0]):
         for j in range(mask.shape[1]):
             for k in range(mask.shape[2]):
-                if mask[i,j,k] == 1:
+                if mask[i, j, k] == 1:
                     if transpose == 1:
                         indices[cpos, 0] = k
                         indices[cpos, 1] = j
@@ -99,8 +99,8 @@
     for i in range(mask.shape[0]):
         for j in range(mask.shape[1]):
             for k in range(mask.shape[2]):
-                if mask[i,j,k] == 1:
-                    out[offset + count] = vals[i,j,k]
+                if mask[i, j, k] == 1:
+                    out[offset + count] = vals[i, j, k]
                     count += 1
     return count
 
@@ -122,6 +122,11 @@
         self.max_level = getattr(dobj, "max_level", 99)
         self.overlap_cells = 0
 
+        for i in range(3) :
+            self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
+                                   dobj.pf.domain_left_edge[i]
+            self.periodicity[i] = dobj.pf.periodicity[i]
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -140,7 +145,7 @@
                 for i in range(3):
                     LE[i] = left_edges[n, i]
                     RE[i] = right_edges[n, i]
-                gridi[n] = self.select_grid(LE, RE, levels[n,0])
+                gridi[n] = self.select_grid(LE, RE, levels[n, 0])
         return gridi.astype("bool")
 
     def count_octs(self, OctreeContainer octree, int domain_id = -1):
@@ -186,9 +191,7 @@
         res = self.select_grid(LE, RE, level, root)
         if res == 1 and data.domain > 0 and root.domain != data.domain:
             res = -1
-        cdef int eterm[3] 
         cdef int increment = 1
-        eterm[0] = eterm[1] = eterm[2] = 0
         cdef int next_level, this_level
         # next_level: an int that says whether or not we can progress to children
         # this_level: an int that says whether or not we can select from this
@@ -218,7 +221,7 @@
                     for k in range(2):
                         ch = NULL
                         if root.children != NULL:
-                            ch = root.children[cind(i,j,k)]
+                            ch = root.children[cind(i, j, k)]
                         if iter == 1 and next_level == 1 and ch != NULL:
                             data.pos[0] = (data.pos[0] << 1) + i
                             data.pos[1] = (data.pos[1] << 1) + j
@@ -232,7 +235,7 @@
                             data.pos[2] = (data.pos[2] >> 1)
                             data.level -= 1
                         elif this_level == 1:
-                            selected = self.select_cell(spos, sdds, eterm)
+                            selected = self.select_cell(spos, sdds)
                             if ch != NULL:
                                 selected *= self.overlap_cells
                             data.global_index += increment
@@ -247,70 +250,39 @@
             this_level = 0 # We turn this off for the second pass.
             iter += 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                                np.float64_t right_edge[3],
                                np.int32_t level, Oct *o = NULL) nogil:
+        if level < self.min_level or level > self.max_level: return 0
+        return self.select_bbox(left_edge, right_edge)
+ 
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 0
-    
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 0
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        return 0
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
         return 0
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        cdef np.ndarray[np.float64_t, ndim=1] odds = gobj.dds
-        cdef np.ndarray[np.float64_t, ndim=1] left_edge = gobj.LeftEdge
-        cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
-        cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
-        cdef np.float64_t dds[3], pos[3]
-        cdef int i, j, k, ind[3][2]
-        child_mask = gobj.child_mask
-        for i in range(3):
-            ind[i][0] = 0
-            ind[i][1] = gobj.ActiveDimensions[i]
-            dds[i] = odds[i]
-        cdef int count = 0
-        cdef int check = 1
-        # Check for the level bounds
-        cdef np.int32_t level = gobj.Level
-        if level < self.min_level or level > self.max_level:
-            return count
-        # We set this to 1 if we ignore child_mask
-        cdef int this_level = 0
-        if level == self.max_level:
-            this_level = 1
-        cdef int eterm[3]
-        self.set_bounds(<np.float64_t *> left_edge.data,
-                        <np.float64_t *> right_edge.data,
-                        dds, ind, &check)
-        with nogil:
-            if check == 1:
-                pos[0] = left_edge[0] + dds[0] * 0.5
-                for i in range(ind[0][0], ind[0][1]):
-                    eterm[0] = 0
-                    pos[1] = left_edge[1] + dds[1] * 0.5
-                    for j in range(ind[1][0], ind[1][1]):
-                        eterm[1] = 0
-                        pos[2] = left_edge[2] + dds[2] * 0.5
-                        for k in range(ind[2][0], ind[2][1]):
-                            eterm[2] = 0
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += self.select_cell(pos, dds, eterm)
-                            if eterm[2] == 1: break
-                            pos[2] += dds[1]
-                        if eterm[1] == 1: break
-                        pos[1] += dds[1]
-                    if eterm[0] == 1: break
-                    pos[0] += dds[0]
-            else:
-                for i in range(ind[0][0], ind[0][1]):
-                    for j in range(ind[1][0], ind[1][1]):
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                count += 1
-        return count
+    cdef np.float64_t difference(self, np.float64_t x1, np.float64_t x2, int d) nogil:
+        cdef np.float64_t rel = x1 - x2
+        if self.periodicity[d] :
+            if rel > self.domain_width[d]/2.0 :
+                rel -= self.domain_width[d]
+            elif rel < -self.domain_width[d]/2.0 :
+                rel += self.domain_width[d]
+        return rel
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
@@ -318,8 +290,8 @@
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         child_mask = gobj.child_mask
-        cdef np.ndarray[np.uint8_t, ndim=3] mask 
-        cdef int ind[3][2]
+        cdef np.ndarray[np.uint8_t, ndim=3] mask
+        cdef int dim[3]
         cdef np.ndarray[np.float64_t, ndim=1] odds = gobj.dds
         cdef np.ndarray[np.float64_t, ndim=1] left_edge = gobj.LeftEdge
         cdef np.ndarray[np.float64_t, ndim=1] right_edge = gobj.RightEdge
@@ -327,59 +299,34 @@
         cdef np.float64_t dds[3], pos[3]
         for i in range(3):
             dds[i] = odds[i]
-            ind[i][0] = 0
-            ind[i][1] = gobj.ActiveDimensions[i]
+            dim[i] = gobj.ActiveDimensions[i]
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
-        cdef int check = 1
         cdef int total = 0
-        cdef int eterm[3]
-        self.set_bounds(<np.float64_t *> left_edge.data,
-                        <np.float64_t *> right_edge.data,
-                        dds, ind, &check)
         cdef int temp
         # Check for the level bounds
         cdef np.int32_t level = gobj.Level
         if level < self.min_level or level > self.max_level:
-            return mask
+            return mask.astype("bool")
         # We set this to 1 if we ignore child_mask
         cdef int this_level = 0
         if level == self.max_level:
             this_level = 1
         with nogil:
-            if check == 1:
-                pos[0] = left_edge[0] + dds[0] * 0.5
-                for i in range(ind[0][0], ind[0][1]):
-                    eterm[0] = 0
-                    pos[1] = left_edge[1] + dds[1] * 0.5
-                    for j in range(ind[1][0], ind[1][1]):
-                        eterm[1] = 0
-                        pos[2] = left_edge[2] + dds[2] * 0.5
-                        for k in range(ind[2][0], ind[2][1]):
-                            eterm[2] = 0
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = self.select_cell(pos, dds, eterm)
-                                total += mask[i,j,k]
-                            if eterm[2] == 1: break
-                            pos[2] += dds[1]
-                        if eterm[1] == 1: break
-                        pos[1] += dds[1]
-                    if eterm[0] == 1: break
-                    pos[0] += dds[0]
-            else:
-                for i in range(ind[0][0], ind[0][1]):
-                    for j in range(ind[1][0], ind[1][1]):
-                        for k in range(ind[2][0], ind[2][1]):
-                            if child_mask[i,j,k] == 1 or this_level == 1:
-                                mask[i,j,k] = 1
-                            total += mask[i,j,k]
+            pos[0] = left_edge[0] + dds[0] * 0.5
+            for i in range(dim[0]):
+                pos[1] = left_edge[1] + dds[1] * 0.5
+                for j in range(dim[1]):
+                    pos[2] = left_edge[2] + dds[2] * 0.5
+                    for k in range(dim[2]):
+                        if child_mask[i, j, k] == 1 or this_level == 1:
+                            mask[i, j, k] = self.select_cell(pos, dds)
+                            total += mask[i, j, k]
+                        pos[2] += dds[1]
+                    pos[1] += dds[1]
+                pos[0] += dds[0]
         if total == 0: return None
         return mask.astype("bool")
 
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        return
-
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
@@ -389,15 +336,20 @@
                            np.float64_t radius = 0.0):
         cdef int count = 0
         cdef int i
-        cdef np.float64_t dds[3], pos[3]
-        dds[0] = dds[1] = dds[2] = radius
-        cdef int eterm[3]
+        cdef np.float64_t pos[3]
         with nogil:
-            for i in range(x.shape[0]):
-                pos[0] = x[i]
-                pos[1] = y[i]
-                pos[2] = z[i]
-                count += self.select_cell(pos, dds, eterm)
+            if radius == 0.0 :
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    count += self.select_point(pos)
+            else :
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    count += self.select_sphere(pos, radius)
         return count
 
     @cython.boundscheck(False)
@@ -409,43 +361,100 @@
                             np.float64_t radius = 0.0):
         cdef int count = 0
         cdef int i
-        cdef np.float64_t dds[3], pos[3]
-        dds[0] = dds[1] = dds[2] = radius
-        cdef int eterm[3]
+        cdef np.float64_t pos[3]
         cdef np.ndarray[np.uint8_t, ndim=1] mask 
         mask = np.zeros(x.shape[0], dtype='uint8')
+
+        # this is to allow selectors to optimize the point vs
+        # 0-radius sphere case.  These two may have different 
+        # effects for 0-volume selectors, however (collision 
+        # between a ray and a point is null, while ray and a
+        # sphere is allowed)
         with nogil:
-            for i in range(x.shape[0]):
-                pos[0] = x[i]
-                pos[1] = y[i]
-                pos[2] = z[i]
-                mask[i] = self.select_cell(pos, dds, eterm)
-                count += mask[i]
+            if radius == 0.0 :
+                for i in range(x.shape[0]) :
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    mask[i] = self.select_point(pos)
+                    count += mask[i]
+            else :
+                for i in range(x.shape[0]):
+                    pos[0] = x[i]
+                    pos[1] = y[i]
+                    pos[2] = z[i]
+                    mask[i] = self.select_sphere(pos, radius)
+                    count += mask[i]
         if count == 0: return None
         return mask.astype("bool")
 
+    def __hash__(self):
+        return hash(self._hash_vals() + self._base_hash())
+
+    def _hash_vals(self):
+        raise NotImplementedError
+
+    def _base_hash(self):
+        return (self.min_level, self.max_level, self.overlap_cells,
+                self.periodicity[0],
+                self.periodicity[1],
+                self.periodicity[2],
+                self.domain_width[0],
+                self.domain_width[1],
+                self.domain_width[2])
+
 cdef class SphereSelector(SelectorObject):
+    cdef np.float64_t radius
     cdef np.float64_t radius2
     cdef np.float64_t center[3]
-    cdef np.float64_t domain_width[3]
-    cdef bint periodicity[3]
 
     def __init__(self, dobj):
         for i in range(3):
             self.center[i] = dobj.center[i]
+        self.radius = dobj.radius
         self.radius2 = dobj.radius * dobj.radius
 
-        for i in range(3) :
-            self.domain_width[i] = dobj.pf.domain_right_edge[i] - \
-                                   dobj.pf.domain_left_edge[i]
-            self.periodicity[i] = dobj.pf.periodicity[i]
-        
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        # sphere center either inside cell or center of cell lies inside sphere
+        if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
+            pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
+            pos[2] - 0.5*dds[2] <= self.center[2] <= pos[2]+0.5*dds[2]):
+            return 1
+        return self.select_point(pos)
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        cdef int i
+        cdef np.float64_t dist, dist2 = 0
+        for i in range(3):
+            dist = self.difference(pos[i], self.center[i], i)
+            dist2 += dist*dist
+        if dist2 <= self.radius2: return 1
+        return 0
+   
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        cdef int i
+        cdef np.float64_t dist, dist2 = 0
+        for i in range(3):
+            dist = self.difference(pos[i], self.center[i], i) 
+            dist2 += dist*dist
+        dist = self.radius+radius
+        if dist2 <= dist*dist: return 1
+        return 0
+ 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
         cdef np.float64_t box_center, relcenter, closest, dist, edge
         cdef int i
         if (left_edge[0] <= self.center[0] <= right_edge[0] and
@@ -456,116 +465,96 @@
         dist = 0
         for i in range(3):
             box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.center[i] - box_center
-            if self.periodicity[i]:
-                if relcenter > self.domain_width[i]/2.0: 
-                    relcenter -= self.domain_width[i] 
-                elif relcenter < -self.domain_width[i]/2.0: 
-                    relcenter += self.domain_width[i] 
+            relcenter = self.difference(box_center, self.center[i], i)
             edge = right_edge[i] - left_edge[i]
             closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
-            dist += closest * closest
+            dist += closest*closest
         if dist <= self.radius2: return 1
         return 0
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t dist2, temp
-        cdef int i
-        if (pos[0] - 0.5*dds[0] <= self.center[0] <= pos[0]+0.5*dds[0] and
-            pos[1] - 0.5*dds[1] <= self.center[1] <= pos[1]+0.5*dds[1] and
-            pos[2] - 0.5*dds[2] <= self.center[2] <= pos[2]+0.5*dds[2]):
-            return 1
-        dist2 = 0
-        for i in range(3):
-            temp = self.center[i] - pos[i]
-            if self.periodicity[i]:
-                if temp > self.domain_width[i]/2.0:
-                    temp -= self.domain_width[i]
-                elif temp < -self.domain_width[i]/2.0:
-                    temp += self.domain_width[i]
-            #temp = temp - fclip(temp, -dds[i]/2.0, dds[i]/2.0)
-            dist2 += temp*temp
-        if dist2 <= self.radius2: return 1
-        return 0
+    def _hash_vals(self):
+        return (self.radius, self.radius2,
+                self.center[0], self.center[1], self.center[2])
 
 sphere_selector = SphereSelector
 
 cdef class RegionSelector(SelectorObject):
     cdef np.float64_t left_edge[3]
     cdef np.float64_t right_edge[3]
-    cdef np.float64_t dx_pad
+    cdef np.float64_t right_edge_shift[3]
 
     def __init__(self, dobj):
         cdef int i
-        self.dx_pad =dobj._dx_pad
+        cdef np.float64_t region_width, domain_width
+
         for i in range(3):
+            region_width = dobj.right_edge[i] - dobj.left_edge[i]
+            domain_width = dobj.pf.domain_right_edge[i] - dobj.pf.domain_left_edge[i]
+
+            if region_width <= 0:
+                print "Error: region right edge < left edge", region_width
+                raise RuntimeError
+
+            if dobj.pf.periodicity[i]:
+                # shift so left_edge guaranteed in domain
+                if dobj.left_edge[i] < dobj.pf.domain_left_edge[i]:
+                    dobj.left_edge[i] += domain_width
+                    dobj.right_edge[i] += domain_width
+                elif dobj.left_edge[i] > dobj.pf.domain_right_edge[i]:
+                    dobj.left_edge[i] += domain_width
+                    dobj.right_edge[i] += domain_width
+            else:
+                if dobj.left_edge[i] < dobj.pf.domain_left_edge[i] or \
+                   dobj.right_edge[i] > dobj.pf.domain_right_edge[i]:
+                    print "Error: bad Region in non-periodic domain:", dobj.left_edge[i], \
+                        dobj.pf.domain_left_edge[i], dobj.right_edge[i], dobj.pf.domain_right_edge[i]
+                    raise RuntimeError
+                
             self.left_edge[i] = dobj.left_edge[i]
             self.right_edge[i] = dobj.right_edge[i]
+            self.right_edge_shift[i] = dobj.right_edge[i] - domain_width
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        if level < self.min_level or level > self.max_level: return 0
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        cdef int i, shift, included
+        cdef np.float64_t LE, RE
         for i in range(3):
-            if left_edge[i] >= self.right_edge[i]: return 0
-            if right_edge[i] <= self.left_edge[i]: return 0
+            if (right_edge[i] < self.left_edge[i] and \
+                left_edge[i] >= self.right_edge_shift[i]) or \
+                left_edge[i] >= self.right_edge[i]:
+                return 0
         return 1
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t dxp
-        for i in range(3):
-            dxp = self.dx_pad * dds[i]
-            if pos[i] - dxp >= self.right_edge[i]:
-                eterm[i] = 1
-                return 0
-            if pos[i] + dxp <= self.left_edge[i]: return 0
-        return 1
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        return self.select_point(pos)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int temp, i, all_inside
-        # Left pos is left_edge + 0.5 * dds
-        # This means the grid is fully within the region
-        # Note vice versa!
-        all_inside = 1 
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        cdef int i
         for i in range(3):
-            # If the region starts after the grid does...
-            if self.left_edge[i] > left_edge[i]:
-                temp = <int> ((self.left_edge[i] - left_edge[i])/dds[i]) - 1
-                #ind[i][0] = iclip(temp, ind[i][0], ind[i][1])
-                all_inside = 0
-            # If the region ends before the grid does...
-            if self.right_edge[i] < right_edge[i]:
-                temp = <int> ((self.right_edge[i] - left_edge[i])/dds[i]) + 1
-                #ind[i][1] = iclip(temp, ind[i][0], ind[i][1])
-                all_inside = 0
-        if all_inside == 0:
-            check[0] = 1
-        else:
-            check[0] = 0
+            if (self.right_edge_shift[i] <= pos[i] < self.left_edge[i]) or \
+               pos[i] >= self.right_edge[i]:
+                return 0
+        return 1
+
+    def _hash_vals(self):
+        return (self.left_edge[0], self.left_edge[1], self.left_edge[2],
+                self.right_edge[0], self.right_edge[1], self.right_edge[2])
 
 region_selector = RegionSelector
 
 cdef class DiskSelector(SelectorObject):
     cdef np.float64_t norm_vec[3]
     cdef np.float64_t center[3]
-    cdef np.float64_t d
-    cdef np.float64_t radius2
+    cdef np.float64_t radius, radius2
     cdef np.float64_t height
 
     def __init__(self, dobj):
@@ -573,23 +562,74 @@
         for i in range(3):
             self.norm_vec[i] = dobj._norm_vec[i]
             self.center[i] = dobj.center[i]
-        self.d = dobj._d
+        self.radius = dobj._radius
         self.radius2 = dobj._radius * dobj._radius
         self.height = dobj._height
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        return self.select_point(pos) 
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        cdef np.float64_t h, d, r2, temp
+        cdef int i
+        h = d = 0
+        for i in range(3):
+            temp = self.difference(pos[i], self.center[i], i)
+            h += temp * self.norm_vec[i]
+            d += temp*temp
+        r2 = (d - h*h)
+        if fabs(h) <= self.height and r2 <= self.radius2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        cdef np.float64_t h, d, r2, temp
+        cdef int i
+        h = d = 0
+        for i in range(3):
+            temp = self.difference(pos[i], self.center[i], i)
+            h += pos[i] * self.norm_vec[i]
+            d += temp*temp
+        r2 = (d - h*h)
+        d = self.radius+radius
+        if fabs(h) <= self.height+radius and r2 <= d*d: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3], H, D, R2, temp
         cdef int i, j, k, n
+        cdef int all_under = 1
+        cdef int all_over = 1
+        cdef int any_radius = 0
+        # A moment of explanation (revised):
+        #    The disk and bounding box collide if any of the following are true:
+        #    1) the center of the disk is inside the bounding box
+        #    2) any corner of the box lies inside the disk
+        #    3) the box spans the plane (!all_under and !all_over) and at least
+        #       one corner is within the cylindrical radius
+
+        # check if disk center lies inside bbox
+        if left_edge[0] <= self.center[0] <= right_edge[0] and \
+           left_edge[1] <= self.center[1] <= right_edge[1] and \
+           left_edge[2] <= self.center[2] <= right_edge[2] :
+            return 1
+        
+        # check all corners
         arr[0] = left_edge
         arr[1] = right_edge
-        cdef int cond[2]
-        cond[0] = cond[1] = 0
         for i in range(2):
             pos[0] = arr[i][0]
             for j in range(2):
@@ -598,40 +638,22 @@
                     pos[2] = arr[k][2]
                     H = D = 0
                     for n in range(3):
-                        H += (pos[n] * self.norm_vec[n])
-                        temp = (pos[n] - self.center[n])
+                        temp = self.difference(pos[n], self.center[n], n)
+                        H += (temp * self.norm_vec[n])
                         D += temp*temp
-                    H += self.d
                     R2 = (D - H*H)
-                    if fabs(H) < self.height: cond[0] = 1
-                    if R2 < self.radius2: cond[1] = 1
-        # A moment of explanation:
-        #    We want our height to be less than the height AND our radius2 to be
-        #    less than radius2, so we set cond[0] equal to 1 if any corners
-        #    match that criteria.
-        # Note that we OVERSELECT grids, as we are selecting anything within
-        # the height and within the radius, which is kind of a funny thing.
-        # Cell selection takes care of the rest.
-        if cond[0] == 1 and cond[1] == 1:
-            return 1
+                    if R2 < self.radius2 :
+                        any_radius = 1
+                        if fabs(H) < self.height: return 1
+                    if H < 0: all_over = 0
+                    if H > 0: all_under = 0
+        if all_over == 0 and all_under == 0 and any_radius == 1: return 1
         return 0
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t h, d, r2, temp
-        cdef int i
-        h = d = 0
-        for i in range(3):
-            h += pos[i] * self.norm_vec[i]
-            temp = pos[i] - self.center[i]
-            d += temp*temp
-        h += self.d
-        r2 = (d - h*h)
-        if fabs(h) <= self.height and r2 <= self.radius2: return 1
-        return 0
+    def _hash_vals(self):
+        return (self.norm_vec[0], self.norm_vec[1], self.norm_vec[2],
+                self.center[0], self.center[1], self.center[2],
+                self.radius, self.radius2, self.height)
 
 disk_selector = DiskSelector
 
@@ -648,9 +670,35 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        cdef np.float64_t left_edge[3]
+        cdef np.float64_t right_edge[3]
+        cdef int i
+        for i in range(3):
+            left_edge[i] = pos[i] - 0.5*dds[i]
+            right_edge[i] = pos[i] + 0.5*dds[i]
+        return self.select_bbox(left_edge, right_edge)
+
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        cdef int i
+        cdef np.float64_t height = self.d
+        for i in range(3) :
+            height += pos[i] * self.norm_vec[i]
+        if height*height <= radius*radius : return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
         cdef int i, j, k, n
         cdef np.float64_t *arr[2]
         cdef np.float64_t pos[3]
@@ -669,71 +717,106 @@
                     gd = self.d
                     for n in range(3):
                         gd += pos[n] * self.norm_vec[n]
-                    if gd < 0: all_over = 0
-                    if gd > 0: all_under = 0
+                    # this allows corners and faces on the low-end to
+                    # collide, while not selecting cells on the high-side 
+                    if i == 0 and j == 0 and k == 0 :
+                        if gd <= 0: all_over = 0
+                        if gd >= 0: all_under = 0
+                    else :
+                        if gd < 0: all_over = 0
+                        if gd > 0: all_under = 0
         if all_over == 1 or all_under == 1:
             return 0
         return 1
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        cdef np.float64_t diag2, height
-        cdef int i
-        height = self.d
-        diag2 = 0
-        for i in range(3):
-            height += pos[i] * self.norm_vec[i]
-            diag2 += dds[i] * dds[i] * 0.25
-        if height * height <= diag2: return 1
-        return 0
+    def _hash_vals(self):
+        return (self.norm_vec[0], self.norm_vec[1], self.norm_vec[2],
+                self.d)
 
 cutting_selector = CuttingPlaneSelector
 
 cdef class SliceSelector(SelectorObject):
     cdef int axis
     cdef np.float64_t coord
+    cdef int ax, ay
 
     def __init__(self, dobj):
         self.axis = dobj.axis
         self.coord = dobj.coord
 
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int i
-        for i in range(3):
-            if self.axis == i:
-                ind[i][0] = <int> ((self.coord - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-        check[0] = 0
+        ax = (self.axis+1) % 3
+        ay = (self.axis+2) % 3
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        if right_edge[self.axis] > self.coord \
-           and left_edge[self.axis] <= self.coord:
-            return 1
-        return 0
-    
+    def fill_mask(self, gobj):
+        cdef np.ndarray[np.uint8_t, ndim=3] mask
+        cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
+        cdef int i, j, k
+        cdef int total = 0
+        cdef int this_level = 0
+        cdef int ind[3][2]
+        cdef np.int32_t level = gobj.Level
+
+        if level < self.min_level or level > self.max_level:
+            return None
+        else:
+            child_mask = gobj.child_mask
+            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8)
+            if level == self.max_level:
+                this_level = 1
+            for i in range(3):
+                if i == self.axis:
+                    ind[i][0] = <int> ((self.coord - gobj.LeftEdge[i])/gobj.dds[i])
+                    ind[i][1] = ind[i][0] + 1
+                else:
+                    ind[i][0] = 0
+                    ind[i][1] = gobj.ActiveDimensions[i]
+            with nogil:
+                for i in range(ind[0][0], ind[0][1]):
+                    for j in range(ind[1][0], ind[1][1]):
+                        for k in range(ind[2][0], ind[2][1]):
+                            if this_level == 1 or child_mask[i, j, k]:
+                                mask[i, j, k] = 1
+                                total += 1
+            if total == 0: return None
+            return mask.astype("bool")
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         if pos[self.axis] + 0.5*dds[self.axis] > self.coord \
            and pos[self.axis] - 0.5*dds[self.axis] <= self.coord:
             return 1
         return 0
 
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        cdef np.float64_t dist = self.difference(pos[self.axis], self.coord, self.axis)
+        if dist*dist < radius*radius:
+            return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        if left_edge[self.axis] <= self.coord < right_edge[self.axis]:
+            return 1
+        return 0
+
+    def _hash_vals(self):
+        return (self.axis, self.coord)
+
 slice_selector = SliceSelector
 
 cdef class OrthoRaySelector(SelectorObject):
@@ -754,44 +837,78 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        if (    (self.px >= left_edge[self.px_ax])
-            and (self.px < right_edge[self.px_ax])
-            and (self.py >= left_edge[self.py_ax])
-            and (self.py < right_edge[self.py_ax])):
-            return 1
-        return 0
-    
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
-        if (    (self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax])
-            and (self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax])
-            and (self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax])
-            and (self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax])):
-            return 1
-        return 0
+    def fill_mask(self, gobj):
+        cdef np.ndarray[np.uint8_t, ndim=3] mask
+        cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
+        cdef int i, j, k
+        cdef int total = 0
+        cdef int this_level = 0
+        cdef int ind[3][2]
+        cdef np.int32_t level = gobj.Level
 
+        if level < self.min_level or level > self.max_level:
+            return None
+        else:
+            child_mask = gobj.child_mask
+            mask = np.zeros(gobj.ActiveDimensions, dtype=np.uint8)
+            if level == self.max_level:
+                this_level = 1
+            ind[self.axis][0] = 0
+            ind[self.axis][1] = gobj.ActiveDimensions[self.axis]
+            ind[self.px_ax][0] = <int> ((self.px - gobj.LeftEdge[self.px_ax]) /
+                                        gobj.dds[self.px_ax])
+            ind[self.px_ax][1] = ind[self.px_ax][0] + 1
+            ind[self.py_ax][0] = <int> ((self.py - gobj.LeftEdge[self.py_ax]) /
+                                        gobj.dds[self.py_ax])
+            ind[self.py_ax][1] = ind[self.py_ax][0] + 1
+
+            with nogil:
+                for i in range(ind[0][0], ind[0][1]):
+                    for j in range(ind[1][0], ind[1][1]):
+                        for k in range(ind[2][0], ind[2][1]):
+                            if this_level == 1 or child_mask[i, j, k]:
+                                mask[i, j, k] = 1
+                                total += 1
+            if total == 0: return None
+            return mask.astype("bool")
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        cdef int i
-        for i in range(3):
-            if self.px_ax == i:
-                ind[i][0] = <int> ((self.px - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-            elif self.py_ax == i:
-                ind[i][0] = <int> ((self.py - left_edge[i])/dds[i])
-                ind[i][1] = ind[i][0] + 1
-        check[0] = 0
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        if self.px >= pos[self.px_ax] - 0.5*dds[self.px_ax] and \
+           self.px <  pos[self.px_ax] + 0.5*dds[self.px_ax] and \
+           self.py >= pos[self.py_ax] - 0.5*dds[self.py_ax] and \
+           self.py <  pos[self.py_ax] + 0.5*dds[self.py_ax]:
+            return 1
+        return 0
+
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        cdef np.float64_t dx = self.difference(pos[self.px_ax], self.px, self.px_ax)
+        cdef np.float64_t dy = self.difference(pos[self.py_ax], self.py, self.py_ax)
+        if dx*dx + dy*dy < radius*radius:
+            return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        if left_edge[self.px_ax] <= self.px < right_edge[self.px_ax] and \
+           left_edge[self.py_ax] <= self.py < right_edge[self.py_ax] :
+            return 1
+        return 0
+
+    def _hash_vals(self):
+        return (self.px_ax, self.py_ax, self.px, self.py, self.axis)
 
 ortho_ray_selector = OrthoRaySelector
 
@@ -833,57 +950,11 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        cdef int i, ax
-        cdef int i1, i2
-        cdef np.float64_t vs[3], t, v[3]
-        for ax in range(3):
-            i1 = (ax+1) % 3
-            i2 = (ax+2) % 3
-            t = (left_edge[ax] - self.p1[ax])/self.vec[ax]
-            for i in range(3):
-                vs[i] = t * self.vec[i] + self.p1[i]
-            if left_edge[i1] <= vs[i1] and \
-               right_edge[i1] >= vs[i1] and \
-               left_edge[i2] <= vs[i2] and \
-               right_edge[i2] >= vs[i2] and \
-               0.0 <= t <= 1.0:
-                return 1
-            t = (right_edge[ax] - self.p1[ax])/self.vec[ax]
-            for i in range(3):
-                vs[i] = t * self.vec[i] + self.p1[i]
-            if left_edge[i1] <= vs[i1] and \
-               right_edge[i1] >= vs[i1] and \
-               left_edge[i2] <= vs[i2] and \
-               right_edge[i2] >= vs[i2] and\
-               0.0 <= t <= 1.0:
-                return 1
-        # if the point is fully enclosed, we count the grid
-        if left_edge[0] <= self.p1[0] and \
-           right_edge[0] >= self.p1[0] and \
-           left_edge[1] <= self.p1[1] and \
-           right_edge[1] >= self.p1[1] and \
-           left_edge[2] <= self.p1[2] and \
-           right_edge[2] >= self.p1[2]:
-            return 1
-        if left_edge[0] <= self.p2[0] and \
-           right_edge[0] >= self.p2[0] and \
-           left_edge[1] <= self.p2[1] and \
-           right_edge[1] >= self.p2[1] and \
-           left_edge[2] <= self.p2[2] and \
-           right_edge[2] >= self.p2[2]:
-            return 1
-        return 0
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.float64_t, ndim=3] t, dt
         cdef np.ndarray[np.uint8_t, ndim=3, cast=True] child_mask
         cdef int i
+        cdef int total = 0
         cdef IntegrationAccumulator ia
         cdef VolumeContainer vc
         mask = np.zeros(gobj.ActiveDimensions, dtype='uint8')
@@ -904,19 +975,15 @@
         for i in range(dt.shape[0]):
             for j in range(dt.shape[1]):
                 for k in range(dt.shape[2]):
-                    if dt[i,j,k] >= 0:
-                        mask[i,j,k] = 1
+                    if dt[i, j, k] >= 0:
+                        mask[i, j, k] = 1
+                        total += 1
+        if total == 0: return None
         return mask.astype("bool")
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        return self.fill_mask(gobj).sum()
-    
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def get_dt(self, gobj):
         cdef np.ndarray[np.float64_t, ndim=3] t, dt
         cdef np.ndarray[np.float64_t, ndim=1] tr, dtr
@@ -944,14 +1011,65 @@
         for i in range(dt.shape[0]):
             for j in range(dt.shape[1]):
                 for k in range(dt.shape[2]):
-                    if dt[i,j,k] >= 0:
-                        tr[ni] = t[i,j,k]
-                        dtr[ni] = dt[i,j,k]
+                    if dt[i, j, k] >= 0:
+                        tr[ni] = t[i, j, k]
+                        dtr[ni] = dt[i, j, k]
                         ni += 1
         if not (ni == ia.hits):
             print ni, ia.hits
         return dtr, tr
-    
+
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        # two 0-volume constructs don't intersect
+        return 0
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        # not implemented
+        return 0        
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        cdef int i, ax
+        cdef int i1, i2
+        cdef np.float64_t vs[3], t, v[3]
+
+        # if either point is fully enclosed, we select the bounding box
+        if left_edge[0] <= self.p1[0] <= right_edge[0] and \
+           left_edge[1] <= self.p1[1] <= right_edge[1] and \
+           left_edge[2] <= self.p1[2] <= right_edge[2]:
+            return 1
+        if left_edge[0] <= self.p2[0] <= right_edge[0] and \
+           left_edge[1] <= self.p2[1] <= right_edge[1] and \
+           left_edge[2] <= self.p2[2] <= right_edge[2]:
+            return 1
+
+        for ax in range(3):
+            i1 = (ax+1) % 3
+            i2 = (ax+2) % 3
+            t = (left_edge[ax] - self.p1[ax])/self.vec[ax]
+            if 0.0 <= t <= 1.0 :
+                for i in range(3):
+                    vs[i] = t * self.vec[i] + self.p1[i]
+                if left_edge[i1] <= vs[i1] <= right_edge[i1] and \
+                   left_edge[i2] <= vs[i2] <= right_edge[i2] :
+                    return 1
+            t = (right_edge[ax] - self.p1[ax])/self.vec[ax]
+            if 0.0 <= t <= 1.0 :
+                for i in range(3):
+                    vs[i] = t * self.vec[i] + self.p1[i]
+                if left_edge[i1] <= vs[i1] <= right_edge[i1] and \
+                   left_edge[i2] <= vs[i2] <= right_edge[i2] :
+                    return 1
+        return 0
+
+    def _hash_vals(self):
+        return (self.p1[0], self.p1[1], self.p1[2],
+                self.p2[0], self.p2[1], self.p2[2],
+                self.vec[0], self.vec[1], self.vec[2])
+
 ray_selector = RaySelector
 
 cdef class DataCollectionSelector(SelectorObject):
@@ -965,15 +1083,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -984,25 +1093,20 @@
         cdef np.ndarray[np.int64_t, ndim=1] oids = self.obj_ids
         with nogil:
             for n in range(self.nids):
-                # Call our selector function
-                # Check if the sphere is inside the grid
                 gridi[oids[n]] = 1
         return gridi.astype("bool")
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        return gobj.ActiveDimensions.prod()
-    
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         cdef np.ndarray[np.uint8_t, ndim=3] mask 
         mask = np.ones(gobj.ActiveDimensions, dtype='uint8')
         return mask.astype("bool")
 
+    def _hash_vals(self):
+        return (hash(self.obj_ids.tostring()), self.nids)
+
 data_collection_selector = DataCollectionSelector
 
 cdef class EllipsoidSelector(SelectorObject):
@@ -1024,41 +1128,20 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_grid(self, np.float64_t left_edge[3],
-                               np.float64_t right_edge[3],
-                               np.int32_t level, Oct *o = NULL) nogil:
-        # This is the sphere selection
-        cdef np.float64_t radius2, box_center, relcenter, closest, dist, edge
-        return 1
-        radius2 = self.mag[0] * self.mag[0]
-        cdef int id
-        if (left_edge[0] <= self.center[0] <= right_edge[0] and
-            left_edge[1] <= self.center[1] <= right_edge[1] and
-            left_edge[2] <= self.center[2] <= right_edge[2]):
-            return 1
-        # http://www.gamedev.net/topic/335465-is-this-the-simplest-sphere-aabb-collision-test/
-        dist = 0
-        for i in range(3):
-            box_center = (right_edge[i] + left_edge[i])/2.0
-            relcenter = self.center[i] - box_center
-            edge = right_edge[i] - left_edge[i]
-            closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
-            dist += closest * closest
-        if dist < radius2: return 1
-        return 0
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        return self.select_point(pos)
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
         cdef np.float64_t dot_evec[3]
         cdef np.float64_t dist
         cdef int i, j
         dot_evec[0] = dot_evec[1] = dot_evec[2] = 0
         # Calculate the rotated dot product
         for i in range(3): # axis
-            dist = pos[i] - self.center[i]
+            dist = self.difference(pos[i], self.center[i], i)
             for j in range(3):
                 dot_evec[j] += dist * self.vec[j][i]
         dist = 0.0
@@ -1067,6 +1150,48 @@
         if dist <= 1.0: return 1
         return 0
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        # this is the sphere selection
+        cdef int i
+        cdef np.float64_t dist2 = 0
+        for i in range(3):
+            dist2 += self.difference(pos[i], self.center[i], i)**2
+        if dist2 <= (self.mag[0]+radius)**2: return 1
+        return 0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        # This is the sphere selection
+        cdef int i
+        cdef np.float64_t box_center, relcenter, closest, dist, edge
+        if left_edge[0] <= self.center[0] <= right_edge[0] and \
+           left_edge[1] <= self.center[1] <= right_edge[1] and \
+           left_edge[2] <= self.center[2] <= right_edge[2]:
+            return 1
+        # http://www.gamedev.net/topic/335465-is-this-the-simplest-sphere-aabb-collision-test/
+        dist = 0
+        for i in range(3):
+            box_center = (right_edge[i] + left_edge[i])/2.0
+            relcenter = self.difference(box_center, self.center[i], i)
+            edge = right_edge[i] - left_edge[i]
+            closest = relcenter - fclip(relcenter, -edge/2.0, edge/2.0)
+            dist += closest * closest
+        if dist <= self.mag[0]**2: return 1
+        return 0
+
+    def _hash_vals(self):
+        return (self.vec[0][0], self.vec[0][1], self.vec[0][2],
+                self.vec[1][0], self.vec[1][1], self.vec[1][2],
+                self.vec[2][0], self.vec[2][1], self.vec[2][2],
+                self.mag[0], self.mag[1], self.mag[2],
+                self.center[0], self.center[1], self.center[2])
+
 ellipsoid_selector = EllipsoidSelector
 
 cdef class GridSelector(SelectorObject):
@@ -1078,15 +1203,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1099,22 +1215,21 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_cells(self, gobj):
-        return gobj.ActiveDimensions.prod()
-    
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def fill_mask(self, gobj):
         return np.ones(gobj.ActiveDimensions, dtype='bool')
 
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        # we apparently don't check if the point actually lies in the grid..
+        return 1
+
+    def _hash_vals(self):
+        return (self.ind,)
 
 grid_selector = GridSelector
 
@@ -1130,15 +1245,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1148,10 +1254,31 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         return 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return self.base_selector.select_bbox(left_edge, right_edge)
+    
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
     cdef int select_grid(self, np.float64_t left_edge[3],
                          np.float64_t right_edge[3], np.int32_t level,
                          Oct *o = NULL) nogil:
@@ -1162,6 +1289,9 @@
         if res == 1 and o != NULL and o.domain != self.domain_id:
             return -1
         return res
+    
+    def _hash_vals(self):
+        return (hash(self.base_selector), self.domain_id)
 
 octree_subset_selector = OctreeSubsetSelector
 
@@ -1181,15 +1311,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1199,16 +1320,37 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
         return 1
 
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return self.base_selector.select_bbox(left_edge, right_edge)
+    
     cdef int select_grid(self, np.float64_t left_edge[3],
                          np.float64_t right_edge[3], np.int32_t level,
                          Oct *o = NULL) nogil:
         # Because visitors now use select_grid, we should be explicitly
         # checking this.
         return self.base_selector.select_grid(left_edge, right_edge, level, o)
+    
+    def _hash_vals(self):
+        return (hash(self.base_selector), self.min_ind, self.max_ind)
 
 indexed_octree_subset_selector = IndexedOctreeSubsetSelector
 
@@ -1220,15 +1362,6 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef void set_bounds(self,
-                         np.float64_t left_edge[3], np.float64_t right_edge[3],
-                         np.float64_t dds[3], int ind[3][2], int *check):
-        check[0] = 0
-        return
-
-    @cython.boundscheck(False)
-    @cython.wraparound(False)
-    @cython.cdivision(True)
     def select_grids(self,
                      np.ndarray[np.float64_t, ndim=2] left_edges,
                      np.ndarray[np.float64_t, ndim=2] right_edges,
@@ -1240,8 +1373,7 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3],
-                         int eterm[3]) nogil:
+    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
         return 1
 
     cdef int select_grid(self, np.float64_t left_edge[3],
@@ -1249,4 +1381,17 @@
                          Oct *o = NULL) nogil:
         return 1
 
+    cdef int select_point(self, np.float64_t pos[3]) nogil:
+        return 1
+
+    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
+        return 1
+
+    cdef int select_bbox(self, np.float64_t left_edge[3],
+                               np.float64_t right_edge[3]) nogil:
+        return 1
+
+    def _hash_vals(self):
+        return ("always", 1,)
+
 always_selector = AlwaysSelector

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 683de674b308a340c7bc89669e44e8202c36e289 yt/geometry/setup.py
--- a/yt/geometry/setup.py
+++ b/yt/geometry/setup.py
@@ -41,6 +41,7 @@
                 libraries=["m"],
                 depends=["yt/utilities/lib/fp_utils.pxd",
                          "yt/geometry/oct_container.pxd",
+                         "yt/geometry/selection_routines.pxd",
                          "yt/geometry/particle_deposit.pxd"])
     config.add_extension("fake_octree", 
                 ["yt/geometry/fake_octree.pyx"],

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

https://bitbucket.org/yt_analysis/yt-3.0/commits/82f7a1795c7a/
Changeset:   82f7a1795c7a
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 14:37:53
Summary:     Remove this line because new_fi will be added in a different way.

This fixes Enzo particle IO in some cases.
Affected #:  1 file

diff -r 0f157d8055c439fe1251710756d600308c6a141c -r 82f7a1795c7ad24cf6590300c5c2222735370050 yt/geometry/geometry_handler.py
--- a/yt/geometry/geometry_handler.py
+++ b/yt/geometry/geometry_handler.py
@@ -220,7 +220,6 @@
             for pt in self.parameter_file.particle_types:
                 new_fi = copy.copy(finfo)
                 new_fi.name = (pt, new_fi.name)
-                if new_fi.name in fi: continue
                 fi[new_fi.name] = new_fi
                 new_fields.append(new_fi.name)
             fields_to_check += new_fields


https://bitbucket.org/yt_analysis/yt-3.0/commits/eaebe7f6859d/
Changeset:   eaebe7f6859d
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 17:25:13
Summary:     Merging in a bug fix for Enzo particle IO
Affected #:  1 file

diff -r 683de674b308a340c7bc89669e44e8202c36e289 -r eaebe7f6859db3bc373e8f0da6340eb376cacd85 yt/geometry/geometry_handler.py
--- a/yt/geometry/geometry_handler.py
+++ b/yt/geometry/geometry_handler.py
@@ -220,7 +220,6 @@
             for pt in self.parameter_file.particle_types:
                 new_fi = copy.copy(finfo)
                 new_fi.name = (pt, new_fi.name)
-                if new_fi.name in fi: continue
                 fi[new_fi.name] = new_fi
                 new_fields.append(new_fi.name)
             fields_to_check += new_fields


https://bitbucket.org/yt_analysis/yt-3.0/commits/f6c18705bf76/
Changeset:   f6c18705bf76
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-17 17:47:21
Summary:     Merging with mainline, bringing in ARTIO spatial and selector generalization.
Affected #:  2 files

diff -r eaebe7f6859db3bc373e8f0da6340eb376cacd85 -r f6c18705bf76fa980051bd4cb8e1fd4b60d94563 yt/data_objects/profiles.py
--- a/yt/data_objects/profiles.py
+++ b/yt/data_objects/profiles.py
@@ -183,6 +183,8 @@
 
         # Get our bins
         if log_space:
+            if lower_bound <= 0.0 or upper_bound <= 0.0:
+                raise YTIllDefinedBounds(lower_bound, upper_bound)
             func = np.logspace
             lower_bound, upper_bound = np.log10(lower_bound), np.log10(upper_bound)
         else:
@@ -522,7 +524,10 @@
         return [self.x_bin_field, self.y_bin_field]
 
 def fix_bounds(upper, lower, logit):
-    if logit: return np.log10(upper), np.log10(lower)
+    if logit:
+        if lower <= 0.0 or upper <= 0.0:
+            raise YTIllDefinedBounds(lower, upper)
+        return np.log10(upper), np.log10(lower)
     return upper, lower
 
 class BinnedProfile2DInlineCut(BinnedProfile2D):

diff -r eaebe7f6859db3bc373e8f0da6340eb376cacd85 -r f6c18705bf76fa980051bd4cb8e1fd4b60d94563 yt/utilities/exceptions.py
--- a/yt/utilities/exceptions.py
+++ b/yt/utilities/exceptions.py
@@ -287,3 +287,14 @@
     def __str__(self):
         return "Filter '%s' ill-defined.  Applied to shape %s but is shape %s." % (
             self.filter, self.s1, self.s2)
+
+class YTIllDefinedBounds(YTException):
+    def __init__(self, lb, ub):
+        self.lb = lb
+        self.ub = ub
+
+    def __str__(self):
+        v =  "The bounds %0.3e and %0.3e are ill-defined. " % (self.lb, self.ub)
+        v += "Typically this happens when a log binning is specified "
+        v += "and zero or negative values are given for the bounds."
+        return v

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

--

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