<html><body>
<p>20 new commits in yt:</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/0ff2ad1af2c5/">https://bitbucket.org/yt_analysis/yt/commits/0ff2ad1af2c5/</a> Changeset:   0ff2ad1af2c5 Branch:      yt User:        atmyers Date:        2016-03-31 02:39:28+00:00 Summary:     hook up proper sampling for hex8 elements Affected #:  2 files</p>
<p>diff -r bd8a7c0ed718365c84f355f9b30a1a95bd77c98b -r 0ff2ad1af2c5131dfbe856fb04389264fcc36bc5 yt/utilities/lib/bounding_volume_hierarchy.pxd --- a/yt/utilities/lib/bounding_volume_hierarchy.pxd +++ b/yt/utilities/lib/bounding_volume_hierarchy.pxd @@ -38,6 +38,9 @@</p>
<pre>cdef class BVH:
    cdef BVHNode* root
    cdef Triangle* triangles</pre>
<p>+    cdef np.float64_t[:, ::1] vertices +    cdef np.int64_t[:, ::1] indices +    cdef np.float64_t[:, ::1] field_data</p>
<pre>     cdef np.int64_t _partition(self, np.int64_t begin, np.int64_t end,
np.int64_t ax, np.float64_t split) nogil
     cdef void intersect(self, Ray* ray) nogil</pre>
<p>diff -r bd8a7c0ed718365c84f355f9b30a1a95bd77c98b -r 0ff2ad1af2c5131dfbe856fb04389264fcc36bc5 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -5,6 +5,10 @@</p>
<pre>from libc.stdlib cimport malloc, free
from cython.parallel import parallel, prange
from vec3_ops cimport dot, subtract, cross</pre>
<p>+from yt.utilities.lib.element_mappings cimport ElementSampler, \ +    Q1Sampler3D + +cdef ElementSampler Q1Sampler = Q1Sampler3D()</p>
<pre>cdef extern from "mesh_construction.h":
    enum:</pre>
<p>@@ -104,6 +108,10 @@</p>
<pre>                  np.int64_t[:, ::1] indices,
                  np.float64_t[:, ::1] field_data):
</pre>
<p>+        self.vertices = vertices +        self.indices = indices +        self.field_data = field_data +</p>
<pre>        cdef np.int64_t num_elem = indices.shape[0]
        cdef np.int64_t num_tri = 12*num_elem
</pre>
<p>@@ -185,6 +193,33 @@</p>
<pre>@cython.cdivision(True)
cdef void intersect(self, Ray* ray) nogil:
    self._recursive_intersect(ray, self.root)</pre>
<p>+ +        if ray.elem_id < 0: +            return + +        cdef np.float64_t[3] position +        cdef np.float64_t[3] direction +        cdef np.float64_t[8] field_data +        cdef np.int64_t[8] element_indices +        cdef np.float64_t[24] vertices + +        cdef np.int64_t i +        for i in range(3): +            position[i] = ray.origin[i] + ray.t_far*ray.direction[i] + +        for i in range(8): +            element_indices[i] = self.indices[ray.elem_id][i] +            field_data[i]      = self.field_data[ray.elem_id][i] + +        for i in range(8): +            vertices[i*3]     = self.vertices[element_indices[i]][0] +            vertices[i*3 + 1] = self.vertices[element_indices[i]][1] +            vertices[i*3 + 2] = self.vertices[element_indices[i]][2] + +        cdef double mapped_coord[3] +        Q1Sampler.map_real_to_unit(mapped_coord, vertices, position) +        val = Q1Sampler.sample_at_unit_point(mapped_coord, field_data) +        ray.data_val = val</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -277,6 +312,7 @@</p>
<pre>ray.t_far = INF
ray.t_near = 0.0
ray.data_val = 0</pre>
<p>+            ray.elem_id = -1</p>
<pre>            bvh.intersect(ray)
            image[i] = ray.data_val
</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/a049e9a49d9a/">https://bitbucket.org/yt_analysis/yt/commits/a049e9a49d9a/</a> Changeset:   a049e9a49d9a Branch:      yt User:        atmyers Date:        2016-03-31 03:48:07+00:00 Summary:     Don't need data on the triangle nodes now Affected #:  2 files</p>
<p>diff -r 0ff2ad1af2c5131dfbe856fb04389264fcc36bc5 -r a049e9a49d9aaeb782cd718c8ac14cc261a0eb42 yt/utilities/lib/bounding_volume_hierarchy.pxd --- a/yt/utilities/lib/bounding_volume_hierarchy.pxd +++ b/yt/utilities/lib/bounding_volume_hierarchy.pxd @@ -30,7 +30,6 @@</p>
<pre>np.float64_t p0[3]
np.float64_t p1[3]
np.float64_t p2[3]</pre>
<ul><li><p>np.float64_t d0, d1, d2 np.int64_t elem_id np.float64_t centroid[3] BBox bbox</p></li></ul>
<p>diff -r 0ff2ad1af2c5131dfbe856fb04389264fcc36bc5 -r a049e9a49d9aaeb782cd718c8ac14cc261a0eb42 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -60,7 +60,6 @@</p>
<pre>if(t > DETERMINANT_EPS and t < ray.t_far):
    ray.t_far = t</pre>
<ul><li><p>ray.data_val = (1.0 – u – v)*tri.d0 + u*tri.d1 + v*tri.d2 ray.elem_id = tri.elem_id return True</p></li></ul>
<p>@@ -113,6 +112,7 @@</p>
<pre>        self.field_data = field_data

        cdef np.int64_t num_elem = indices.shape[0]</pre>
<p>+        cdef np.int64_t num_verts_per_elem = indices.shape[1]</p>
<pre>        cdef np.int64_t num_tri = 12*num_elem

        # fill our array of triangles</pre>
<p>@@ -130,9 +130,6 @@</p>
<pre>v0 = indices[i][triangulate_hex[j][0]]
v1 = indices[i][triangulate_hex[j][1]]
v2 = indices[i][triangulate_hex[j][2]]</pre>
<ul><li><p>tri.d0 = field_data[i][triangulate_hex[j][0]]</p></li>
<li><p>tri.d1 = field_data[i][triangulate_hex[j][1]]</p></li>
<li><p>tri.d2 = field_data[i][triangulate_hex[j][2]] for k in range(3):</p>
<pre>tri.p0[k] = vertices[v0][k]
tri.p1[k] = vertices[v1][k]</pre></li></ul>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/22f8c1d1a8c7/">https://bitbucket.org/yt_analysis/yt/commits/22f8c1d1a8c7/</a> Changeset:   22f8c1d1a8c7 Branch:      yt User:        atmyers Date:        2016-04-02 17:39:23+00:00 Summary:     pre-compute a flattened data structure for faster ray tracing. Affected #:  2 files</p>
<p>diff -r a049e9a49d9aaeb782cd718c8ac14cc261a0eb42 -r 22f8c1d1a8c78492d197d49a706cafd5c985bf3e yt/utilities/lib/bounding_volume_hierarchy.pxd --- a/yt/utilities/lib/bounding_volume_hierarchy.pxd +++ b/yt/utilities/lib/bounding_volume_hierarchy.pxd @@ -1,6 +1,7 @@</p>
<pre>cimport cython
import numpy as np
cimport numpy as np</pre>
<p>+from yt.utilities.lib.element_mappings cimport ElementSampler</p>
<pre># ray data structure
cdef struct Ray:</pre>
<p>@@ -37,9 +38,13 @@</p>
<pre>cdef class BVH:
    cdef BVHNode* root
    cdef Triangle* triangles</pre>
<ul><li><p>cdef np.float64_t[:, ::1] vertices</p></li>
<li><p>cdef np.int64_t[:, ::1] indices</p></li>
<li><p>cdef np.float64_t[:, ::1] field_data</p></li></ul>
<p>+    cdef np.float64_t* vertices +    cdef np.float64_t* field_data +    cdef np.int64_t num_tri_per_elem +    cdef np.int64_t num_tri +    cdef np.int64_t num_elem +    cdef np.int64_t num_verts_per_elem +    cdef ElementSampler sampler</p>
<pre>     cdef np.int64_t _partition(self, np.int64_t begin, np.int64_t end,
np.int64_t ax, np.float64_t split) nogil
     cdef void intersect(self, Ray* ray) nogil</pre>
<p>diff -r a049e9a49d9aaeb782cd718c8ac14cc261a0eb42 -r 22f8c1d1a8c78492d197d49a706cafd5c985bf3e yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -5,10 +5,16 @@</p>
<pre>from libc.stdlib cimport malloc, free
from cython.parallel import parallel, prange
from vec3_ops cimport dot, subtract, cross</pre>
<p>-from yt.utilities.lib.element_mappings cimport ElementSampler, \</p>
<ul><li><p>Q1Sampler3D</p></li></ul>
<p>+from yt.utilities.lib.element_mappings cimport \ +    ElementSampler, \ +    Q1Sampler3D, \ +    P1Sampler3D, \ +    Q1Sampler3D, \ +    W1Sampler3D</p>
<pre>cdef ElementSampler Q1Sampler = Q1Sampler3D()</pre>
<p>+cdef ElementSampler P1Sampler = P1Sampler3D() +cdef ElementSampler W1Sampler = W1Sampler3D()</p>
<pre>cdef extern from "mesh_construction.h":
    enum:</pre>
<p>@@ -103,27 +109,40 @@</p>
<pre>@cython.wraparound(False)
@cython.cdivision(True)
def __cinit__(self,</pre>
<ul><li><p>np.float64_t[:, ::1] vertices,</p></li>
<li><p>np.int64_t[:, ::1] indices,</p></li>
<li><p>np.float64_t[:, ::1] field_data):</p></li></ul>
<p>+                  np.float64_t[:, :] vertices, +                  np.int64_t[:, :] indices, +                  np.float64_t[:, :] field_data):</p>
<ul><li><p>self.vertices = vertices</p></li>
<li><p>self.indices = indices</p></li>
<li><p>self.field_data = field_data</p></li></ul>
<p>+        self.num_elem = indices.shape[0] +        self.num_verts_per_elem = indices.shape[1] +        self.num_tri_per_elem = 12 +        self.num_tri = self.num_tri_per_elem*self.num_elem +        self.sampler = Q1Sampler</p>
<ul><li><p>cdef np.int64_t num_elem = indices.shape[0]</p></li>
<li><p>cdef np.int64_t num_verts_per_elem = indices.shape[1]</p></li>
<li><p>cdef np.int64_t num_tri = 12*num_elem</p></li></ul>
<p>+        # allocate storage +        cdef np.int64_t size = self.num_verts_per_elem * self.num_elem +        self.vertices = <np.float64_t*> malloc(size * 3 * sizeof(np.float64_t)) +        self.field_data = <np.float64_t*> malloc(size * sizeof(np.float64_t)) + +        # create data buffers +        cdef np.int64_t i, j, k +        cdef np.int64_t field_offset, vertex_offset +        for i in range(self.num_elem): +            field_offset = i*self.num_verts_per_elem +            for j in range(self.num_verts_per_elem): +                vertex_offset = i*self.num_verts_per_elem*3 + j*3 +                self.field_data[field_offset + j] = field_data[i][j] +                for k in range(3): +                    self.vertices[vertex_offset + k] = vertices[indices[i,j]][k]</p>
<pre># fill our array of triangles</pre>
<ul><li><p>cdef np.int64_t i, j, k cdef np.int64_t offset, tri_index cdef np.int64_t v0, v1, v2 cdef Triangle* tri</p></li>
<li><p>self.triangles = <Triangle*> malloc(num_tri * sizeof(Triangle))</p></li>
<li><p>for i in range(num_elem):</p></li>
<li><p>offset = 12*i</p></li>
<li><p>for j in range(12):</p></li></ul>
<p>+        self.triangles = <Triangle*> malloc(self.num_tri * sizeof(Triangle)) +        for i in range(self.num_elem): +            offset = self.num_tri_per_elem*i +            for j in range(self.num_tri_per_elem):</p>
<pre>tri_index = offset + j
tri = &(self.triangles[tri_index])
tri.elem_id = i</pre>
<p>@@ -138,7 +157,7 @@</p>
<pre>                    tri.bbox.left_edge[k]  = fmin(fmin(tri.p0[k], tri.p1[k]), tri.p2[k])
                    tri.bbox.right_edge[k] = fmax(fmax(tri.p0[k], tri.p1[k]), tri.p2[k])
</pre>
<ul><li><p>self.root = self._recursive_build(0, num_tri)</p></li></ul>
<p>+        self.root = self._recursive_build(0, self.num_tri)</p>
<pre>cdef void _recursive_free(self, BVHNode* node) nogil:
    if node.end - node.begin > LEAF_SIZE:</pre>
<p>@@ -149,6 +168,8 @@</p>
<pre>def __dealloc__(self):
    self._recursive_free(self.root)
    free(self.triangles)</pre>
<p>+        free(self.field_data) +        free(self.vertices)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -195,28 +216,17 @@</p>
<pre>            return

        cdef np.float64_t[3] position</pre>
<ul><li><p>cdef np.float64_t[3] direction</p></li>
<li><p>cdef np.float64_t[8] field_data</p></li>
<li><p>cdef np.int64_t[8] element_indices</p></li>
<li><p>cdef np.float64_t[24] vertices</p></li></ul>
<p>–</p>
<pre>         cdef np.int64_t i
         for i in range(3):
position[i] = ray.origin[i] + ray.t_far*ray.direction[i]
</pre>
<ul><li><p>for i in range(8):</p></li>
<li><p>element_indices[i] = self.indices[ray.elem_id][i]</p></li>
<li><p>field_data[i]      = self.field_data[ray.elem_id][i]</p></li></ul>
<p>–</p>
<ul><li><p>for i in range(8):</p></li>
<li><p>vertices[i*3]     = self.vertices[element_indices[i]][0]</p></li>
<li><p>vertices[i*3 + 1] = self.vertices[element_indices[i]][1]</p></li>
<li><p>vertices[i*3 + 2] = self.vertices[element_indices[i]][2]</p></li></ul>
<p>–</p>
<ul><li><p>cdef double mapped_coord[3]</p></li>
<li><p>Q1Sampler.map_real_to_unit(mapped_coord, vertices, position)</p></li>
<li><p>val = Q1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li>
<li><p>ray.data_val = val</p></li></ul>
<p>+        cdef np.float64_t* vertex_ptr +        cdef np.float64_t* field_ptr +        vertex_ptr = self.vertices + ray.elem_id*self.num_verts_per_elem*3 +        field_ptr = self.field_data + ray.elem_id*self.num_verts_per_elem +        ray.data_val = self.sampler.sample_at_real_point(vertex_ptr, +                                                         field_ptr, +                                                         position)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/49944aba410d/">https://bitbucket.org/yt_analysis/yt/commits/49944aba410d/</a> Changeset:   49944aba410d Branch:      yt User:        atmyers Date:        2016-04-02 17:53:20+00:00 Summary:     allow bvh to work with other mesh types Affected #:  2 files</p>
<p>diff -r 22f8c1d1a8c78492d197d49a706cafd5c985bf3e -r 49944aba410d3708ab7ed03b421bd61226a5ce29 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -19,7 +19,16 @@</p>
<pre>cdef extern from "mesh_construction.h":
    enum:
        MAX_NUM_TRI</pre>
<p>+ +    int HEX_NV +    int HEX_NT +    int TETRA_NV +    int TETRA_NT +    int WEDGE_NV +    int WEDGE_NT</p>
<pre>int triangulate_hex[MAX_NUM_TRI][3]</pre>
<p>+    int triangulate_tetra[MAX_NUM_TRI][3] +    int triangulate_wedge[MAX_NUM_TRI][3]</p>
<pre># define some constants
cdef np.float64_t DETERMINANT_EPS = 1.0e-10</pre>
<p>@@ -115,9 +124,22 @@</p>
<pre>self.num_elem = indices.shape[0]
self.num_verts_per_elem = indices.shape[1]</pre>
<ul><li><p>self.num_tri_per_elem = 12</p></li></ul>
<p>+ +        # We need to figure out what kind of elements we've been handed. +        cdef int[MAX_NUM_TRI][3] tri_array +        if self.num_verts_per_elem == 8: +            self.num_tri_per_elem = HEX_NT +            tri_array = triangulate_hex +            self.sampler = Q1Sampler +        elif self.num_verts_per_elem == 6: +            self.num_tri_per_elem = WEDGE_NT +            tri_array = triangulate_wedge +            self.sampler = W1Sampler +        elif self.num_verts_per_elem == 4: +            self.num_tri_per_elem = TETRA_NT +            tri_array = triangulate_tetra +            self.sampler = P1Sampler</p>
<pre>self.num_tri = self.num_tri_per_elem*self.num_elem</pre>
<ul><li><p>self.sampler = Q1Sampler</p>
<p># allocate storage cdef np.int64_t size = self.num_verts_per_elem * self.num_elem</p></li></ul>
<p>@@ -146,9 +168,9 @@</p>
<pre>tri_index = offset + j
tri = &(self.triangles[tri_index])
tri.elem_id = i</pre>
<ul><li><p>v0 = indices[i][triangulate_hex[j][0]]</p></li>
<li><p>v1 = indices[i][triangulate_hex[j][1]]</p></li>
<li><p>v2 = indices[i][triangulate_hex[j][2]]</p></li></ul>
<p>+                v0 = indices[i][tri_array[j][0]] +                v1 = indices[i][tri_array[j][1]] +                v2 = indices[i][tri_array[j][2]]</p>
<pre>for k in range(3):
    tri.p0[k] = vertices[v0][k]
    tri.p1[k] = vertices[v1][k]</pre>
<p>diff -r 22f8c1d1a8c78492d197d49a706cafd5c985bf3e -r 49944aba410d3708ab7ed03b421bd61226a5ce29 yt/utilities/lib/mesh_construction.pyx --- a/yt/utilities/lib/mesh_construction.pyx +++ b/yt/utilities/lib/mesh_construction.pyx @@ -104,7 +104,7 @@</p>
<pre>                 np.ndarray indices,
                 np.ndarray data):
</pre>
<ul><li><p># We need now to figure out what kind of elements we've been handed.</p></li></ul>
<p>+        # We need to figure out what kind of elements we've been handed.</p>
<pre>         if indices.shape[1] == 8:
self.vpe = HEX_NV
self.tpe = HEX_NT</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/e0838f66ad6c/">https://bitbucket.org/yt_analysis/yt/commits/e0838f66ad6c/</a> Changeset:   e0838f66ad6c Branch:      yt User:        atmyers Date:        2016-04-02 22:38:10+00:00 Summary:     begin hooking up BVH to rest of volume rendering code. Affected #:  3 files</p>
<p>diff -r 49944aba410d3708ab7ed03b421bd61226a5ce29 -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 yt/utilities/lib/bounding_volume_hierarchy.pxd --- a/yt/utilities/lib/bounding_volume_hierarchy.pxd +++ b/yt/utilities/lib/bounding_volume_hierarchy.pxd @@ -12,6 +12,7 @@</p>
<pre>np.float64_t t_near
np.float64_t t_far
np.int64_t elem_id</pre>
<p>+    np.int64_t near_boundary</p>
<pre># axis-aligned bounding box
cdef struct BBox:</pre>
<p>diff -r 49944aba410d3708ab7ed03b421bd61226a5ce29 -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -1,4 +1,4 @@ -cimport cython +cimport cython</p>
<pre>import numpy as np
cimport numpy as np
from libc.math cimport fabs, fmax, fmin</pre>
<p>@@ -250,6 +250,8 @@</p>
<pre>                                                         field_ptr,
                                                         position)
</pre>
<p>+        ray.near_boundary = -1 +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>diff -r 49944aba410d3708ab7ed03b421bd61226a5ce29 -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 yt/utilities/lib/mesh_traversal.pyx --- a/yt/utilities/lib/mesh_traversal.pyx +++ b/yt/utilities/lib/mesh_traversal.pyx @@ -25,6 +25,7 @@</p>
<pre>    ImageContainer
from cython.parallel import prange, parallel, threadid
from yt.visualization.image_writer import apply_colormap</pre>
<p>+from yt.utilities.lib.bounding_volume_hierarchy cimport BVH, Ray</p>
<pre>rtc.rtcInit(NULL)
rtc.rtcSetErrorFunction(error_printer)</pre>
<p>@@ -109,3 +110,71 @@</p>
<pre>self.zbuffer = zbuffer
free(v_pos)
free(v_dir)</pre>
<p>+ + +cdef class BVHMeshSampler(ImageSampler): + +    cdef public object image_used +    cdef public object mesh_lines +    cdef public object zbuffer + +    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    def __call__(self, +                 BVH bvh, +                 int num_threads = 0): +        ''' + +        This function is supposed to cast the rays and return the +        image. + +        ''' + +        cdef int vi, vj, i, j +        cdef ImageContainer <strong>im = self.image +        cdef np.float64_t *v_pos +        cdef np.float64_t *v_dir +        cdef np.int64_t nx, ny, size +        cdef np.float64_t width[3] +        for i in range(3): +            width[i] = self.width[i] +        cdef np.ndarray[np.float64_t, ndim=1] data +        cdef np.ndarray[np.int64_t, ndim=1] used +        nx = im.nv[0] +        ny = im.nv[1] +        size = nx * ny +        used = np.empty(size, dtype="int64") +        mesh = np.empty(size, dtype="int64") +        data = np.empty(size, dtype="float64") +        zbuffer = np.empty(size, dtype="float64") +        cdef Ray</strong> ray +        with nogil, parallel(num_threads = num_threads): +            ray = <Ray *> malloc(sizeof(Ray)) +            v_pos = <np.float64_t *> malloc(3 * sizeof(np.float64_t)) +            v_dir = <np.float64_t *> malloc(3 * sizeof(np.float64_t)) +            for j in prange(size): +                vj = j % ny +                vi = (j – vj) / ny +                vj = vj +                self.vector_function(im, vi, vj, width, v_dir, v_pos) +                for i in range(3): +                    ray.origin[i] = v_pos[i] +                    ray.direction[i] = v_dir[i] +                    ray.inv_dir[i] = 1.0 / v_dir[i] +                ray.t_far = np.inf +                ray.t_near = 0.0 +                ray.data_val = 0 +                ray.elem_id = -1 +                bvh.intersect(ray) +                data[j] = ray.data_val +                used[j] = ray.elem_id +                mesh[j] = ray.near_boundary +                zbuffer[j] = ray.t_far +        self.aimage = data +        self.image_used = used +        self.mesh_lines = mesh +        self.zbuffer = zbuffer +        free(v_pos) +        free(v_dir) +        free(ray)</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/672764585671/">https://bitbucket.org/yt_analysis/yt/commits/672764585671/</a> Changeset:   672764585671 Branch:      yt User:        atmyers Date:        2016-04-03 20:52:13+00:00 Summary:     merging with tip Affected #:  17 files</p>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe doc/cheatsheet.tex --- a/doc/cheatsheet.tex +++ b/doc/cheatsheet.tex @@ -7,12 +7,12 @@</p>
<pre>% To make this come out properly in landscape mode, do one of the following
% 1.</pre>
<p>-%  pdflatex latexsheet.tex +%  pdflatex cheatsheet.tex</p>
<pre>%
% 2.</pre>
<p>-%  latex latexsheet.tex -%  dvips -P pdf  -t landscape latexsheet.dvi -%  ps2pdf latexsheet.ps +%  latex cheatsheet.tex +%  dvips -P pdf  -t landscape cheatsheet.dvi +%  ps2pdf cheatsheet.ps</p>
<pre>% If you're reading this, be prepared for confusion.  Making this was</pre>
<p>@@ -45,7 +45,7 @@</p>
<pre>% Turn off header and footer
\pagestyle{empty}</pre>
<p>– +</p>
<pre>% Redefine section commands to use less space
\makeatletter</pre>
<p>@@ -117,26 +117,26 @@</p>
<pre>including a list of the available flags.

\texttt{iyt}\textemdash\ Load yt and IPython. \\</pre>
<p>-\texttt{yt load} {\it dataset}   \textemdash\ Load a single dataset.  \\ +\texttt{yt load} \textit{dataset}   \textemdash\ Load a single dataset.  \\</p>
<pre>\texttt{yt help} \textemdash\ Print yt help information. \\</pre>
<p>-\texttt{yt stats} {\it dataset} \textemdash\ Print stats of a dataset. \\ +\texttt{yt stats} \textit{dataset} \textemdash\ Print stats of a dataset. \\</p>
<pre>\texttt{yt update} \textemdash\ Update yt to most recent version.\\
\texttt{yt update --all} \textemdash\ Update yt and dependencies to most recent version. \\
\texttt{yt version} \textemdash\ yt installation information. \\
\texttt{yt notebook} \textemdash\ Run the IPython notebook server. \\</pre>
<p>-\texttt{yt upload\_image} {\it image.png} \textemdash\ Upload PNG image to imgur.com. \\ -\texttt{yt upload\_notebook} {\it notebook.nb} \textemdash\ Upload IPython notebook to hub.yt-project.org.\\ -\texttt{yt plot} {\it dataset} \textemdash\ Create a set of images.\\ -\texttt{yt render} {\it dataset} \textemdash\ Create a simple +\texttt{yt upload\_image} \textit{image.png} \textemdash\ Upload PNG image to imgur.com. \\ +\texttt{yt upload\_notebook} \textit{notebook.nb} \textemdash\ Upload IPython notebook to hub.yt-project.org.\\ +\texttt{yt plot} \textit{dataset} \textemdash\ Create a set of images.\\ +\texttt{yt render} \textit{dataset} \textemdash\ Create a simple</p>
<pre>volume rendering. \\</pre>
<p>-\texttt{yt mapserver} {\it dataset} \textemdash\ View a plot/projection in a Gmaps-like +\texttt{yt mapserver} \textit{dataset} \textemdash\ View a plot/projection in a Gmaps-like</p>
<pre>interface. \\</pre>
<p>-\texttt{yt pastebin} {\it text.out} \textemdash\ Post text to the pastebin at</p>
<ul><li><p>paste.yt-project.org. \\</p></li></ul>
<p>-\texttt{yt pastebin\_grab} {\it identifier} \textemdash\ Print content of pastebin to +\texttt{yt pastebin} \textit{text.out} \textemdash\ Post text to the pastebin at + paste.yt-project.org. \\ +\texttt{yt pastebin\_grab} \textit{identifier} \textemdash\ Print content of pastebin to</p>
<pre> STDOUT. \\
\texttt{yt bugreport} \textemdash\ Report a yt bug. \\</pre>
<p>-\texttt{yt hop} {\it dataset} \textemdash\  Run hop on a dataset. \\ +\texttt{yt hop} \textit{dataset} \textemdash\  Run hop on a dataset. \\</p>
<pre>\subsection{yt Imports}
In order to use yt, Python must load the relevant yt modules into memory.</pre>
<p>@@ -144,15 +144,15 @@</p>
<pre>used as part of a script.
\newlength{\MyLen}
\settowidth{\MyLen}{\texttt{letterpaper}/\texttt{a4paper} \ }</pre>
<p>-\texttt{import yt}  \textemdash\ +\texttt{import yt}  \textemdash\</p>
<pre>Load yt. \\</pre>
<p>-\texttt{from yt.config import ytcfg}  \textemdash\ +\texttt{from yt.config import ytcfg}  \textemdash\</p>
<pre>Used to set yt configuration options.
If used, must be called before importing any other module.\\</pre>
<p>-\texttt{from yt.analysis\_modules.\emph{halo\_finding}.api import \textasteriskcentered}  \textemdash\ +\texttt{from yt.analysis\_modules.\emph{halo\_finding}.api import \textasteriskcentered}  \textemdash\</p>
<pre>Load halo finding modules. Other modules</pre>
<p>-are loaded in a similar way by swapping the -{\em emphasized} text. +are loaded in a similar way by swapping the +\emph{emphasized} text.</p>
<pre>See the \textbf{Analysis Modules} section for a listing and short descriptions of each.

\subsection{YTArray}</pre>
<p>@@ -163,32 +163,32 @@</p>
<pre>very brief list of some useful ones.
\settowidth{\MyLen}{\texttt{multicol} }\\
\texttt{v = a.in\_cgs()} \textemdash\ Return the array in CGS units \\</pre>
<p>-\texttt{v = a.in\_units('Msun/pc**3')} \textemdash\ Return the array in solar masses per cubic parsec \\ +\texttt{v = a.in\_units('Msun/pc**3')} \textemdash\ Return the array in solar masses per cubic parsec \\</p>
<pre>\texttt{v = a.max(), a.min()} \textemdash\ Return maximum, minimum of \texttt{a}. \\
\texttt{index = a.argmax(), a.argmin()} \textemdash\ Return index of max,
min value of \texttt{a}.\\</pre>
<p>-\texttt{v = a[}{\it index}\texttt{]} \textemdash\ Select a single value from \texttt{a} at location {\it index}.\\ -\texttt{b = a[}{\it i:j}\texttt{]} \textemdash\ Select the slice of values from +\texttt{v = a[}\textit{index}\texttt{]} \textemdash\ Select a single value from \texttt{a} at location \textit{index}.\\ +\texttt{b = a[}\textit{i:j}\texttt{]} \textemdash\ Select the slice of values from</p>
<pre>\texttt{a} between</pre>
<p>-locations {\it i} to {\it j-1} saved to a new Numpy array \texttt{b} with length {\it j-i}. \\ +locations \textit{i} to \textit{j-1} saved to a new Numpy array \texttt{b} with length \textit{j-i}. \\</p>
<pre>\texttt{sel = (a > const)} \textemdash\ Create a new boolean Numpy array
\texttt{sel}, of the same shape as \texttt{a},
that marks which values of \texttt{a > const}. Other operators (e.g. \textless, !=, \%) work as well.\\
\texttt{b = a[sel]} \textemdash\ Create a new Numpy array \texttt{b} made up of
elements from \texttt{a} that correspond to elements of \texttt{sel}</pre>
<p>-that are {\it True}. In the above example \texttt{b} would be all elements of \texttt{a} that are greater than \texttt{const}.\\ -\texttt{a.write\_hdf5({\it filename.h5})} \textemdash\ Save \texttt{a} to the hdf5 file {\it filename.h5}.\\ +that are \textit{True}. In the above example \texttt{b} would be all elements of \texttt{a} that are greater than \texttt{const}.\\ +\texttt{a.write\_hdf5(\textit{filename.h5})} \textemdash\ Save \texttt{a} to the hdf5 file \textit{filename.h5}.\\</p>
<pre>\subsection{IPython Tips}
\settowidth{\MyLen}{\texttt{multicol} }
These tips work if IPython has been loaded, typically either by invoking
\texttt{iyt} or \texttt{yt load} on the command line, or using the IPython notebook (\texttt{yt notebook}).
\texttt{Tab complete} \textemdash\ IPython will attempt to auto-complete a</pre>
<p>-variable or function name when the \texttt{Tab} key is pressed, e.g. {\it HaloFi}\textendash\texttt{Tab} would auto-complete -to {\it HaloFinder}. This also works with imports, e.g. {\it from numpy.random.}\textendash\texttt{Tab} +variable or function name when the \texttt{Tab} key is pressed, e.g. \textit{HaloFi}\textendash\texttt{Tab} would auto-complete +to \textit{HaloFinder}. This also works with imports, e.g. \textit{from numpy.random.}\textendash\texttt{Tab}</p>
<pre>would give you a list of random functions (note the trailing period before hitting \texttt{Tab}).\\
\texttt{?, ??} \textemdash\ Appending one or two question marks at the end of any object gives you</pre>
<p>-detailed information about it, e.g. {\it variable\_name}?.\\ +detailed information about it, e.g. \textit{variable\_name}?.\\</p>
<pre>Below a few IPython ``magics'' are listed, which are IPython-specific shortcut commands.\\
\texttt{\%paste} \textemdash\ Paste content from the system clipboard into the IPython shell.\\
\texttt{\%hist} \textemdash\ Print recent command history.\\</pre>
<p>@@ -204,40 +204,40 @@</p>
<pre>\subsection{Load and Access Data}
The first step in using yt is to reference a simulation snapshot.</pre>
<p>-After that, simulation data is generally accessed in yt using {\it Data Containers} which are Python objects +After that, simulation data is generally accessed in yt using \textit{Data Containers} which are Python objects</p>
<pre>that define a region of simulation space from which data should be selected.
\settowidth{\MyLen}{\texttt{multicol} }</pre>
<p>-\texttt{ds = yt.load(}{\it dataset}\texttt{)} \textemdash\   Reference a single snapshot.\\ +\texttt{ds = yt.load(}\textit{dataset}\texttt{)} \textemdash\   Reference a single snapshot.\\</p>
<pre>\texttt{dd = ds.all\_data()} \textemdash\ Select the entire volume.\\</pre>
<p>-\texttt{a = dd[}{\it field\_name}\texttt{]} \textemdash\ Copies the contents of {\it field} into the +\texttt{a = dd[}\textit{field\_name}\texttt{]} \textemdash\ Copies the contents of \textit{field} into the</p>
<pre>YTArray \texttt{a}. Similarly for other data containers.\\
\texttt{ds.field\_list} \textemdash\ A list of available fields in the snapshot. \\
\texttt{ds.derived\_field\_list} \textemdash\ A list of available derived fields
in the snapshot. \\
\texttt{val, loc = ds.find\_max("Density")} \textemdash\ Find the \texttt{val}ue of
the maximum of the field \texttt{Density} and its \texttt{loc}ation. \\</pre>
<p>-\texttt{sp = ds.sphere(}{\it cen}\texttt{,}{\it radius}\texttt{)} \textemdash\   Create a spherical data -container. {\it cen} may be a coordinate, or ``max'' which -centers on the max density point. {\it radius} may be a float in -code units or a tuple of ({\it length, unit}).\\ +\texttt{sp = ds.sphere(}\textit{cen}\texttt{,}\textit{radius}\texttt{)} \textemdash\   Create a spherical data +container. \textit{cen} may be a coordinate, or ``max'' which +centers on the max density point. \textit{radius} may be a float in +code units or a tuple of (\textit{length, unit}).\\</p>
<p>-\texttt{re = ds.region({\it cen}, {\it left edge}, {\it right edge})} \textemdash\ Create a -rectilinear data container. {\it cen} is required but not used. -{\it left} and {\it right edge} are coordinate values that define the region. +\texttt{re = ds.region(\textit{cen}, \textit{left edge}, \textit{right edge})} \textemdash\ Create a +rectilinear data container. \textit{cen} is required but not used. +\textit{left} and \textit{right edge} are coordinate values that define the region.</p>
<p>-\texttt{di = ds.disk({\it cen}, {\it normal}, {\it radius}, {\it height})} \textemdash\ -Create a cylindrical data container centered at {\it cen} along the -direction set by {\it normal},with total length</p>
<ul><li><p>2$\times${\it height} and with radius {\it radius}. \\</p></li></ul>
<p>– -\texttt{ds.save\_object(sp, {\it ``sp\_for\_later''})} \textemdash\ Save an object (\texttt{sp}) for later use.\\ -\texttt{sp = ds.load\_object({\it ``sp\_for\_later''})} \textemdash\ Recover a saved object.\\ +\texttt{di = ds.disk(\textit{cen}, \textit{normal}, \textit{radius}, \textit{height})} \textemdash\ +Create a cylindrical data container centered at \textit{cen} along the +direction set by \textit{normal},with total length + 2$\times$\textit{height} and with radius \textit{radius}. \\ + +\texttt{ds.save\_object(sp, \textit{``sp\_for\_later''})} \textemdash\ Save an object (\texttt{sp}) for later use.\\ +\texttt{sp = ds.load\_object(\textit{``sp\_for\_later''})} \textemdash\ Recover a saved object.\\</p>
<pre>\subsection{Defining New Fields}</pre>
<p>-\texttt{yt} expects on-disk fields, fields generated on-demand and in-memory. +\texttt{yt} expects on-disk fields, fields generated on-demand and in-memory.</p>
<pre>Field can either be created before a dataset is loaded using \texttt{add\_field}:</pre>
<p>-\texttt{def \_metal\_mass({\it field},{\it data})}\\ +\texttt{def \_metal\_mass(\textit{field},\textit{data})}\\</p>
<pre>\texttt{\hspace{4 mm} return data["metallicity"]*data["cell\_mass"]}\\
\texttt{add\_field("metal\_mass", units='g', function=\_metal\_mass)}\\
Or added to an existing dataset using \texttt{ds.add\_field}:</pre>
<p>@@ -245,34 +245,34 @@</p>
<pre>\subsection{Slices and Projections}
\settowidth{\MyLen}{\texttt{multicol} }</pre>
<p>-\texttt{slc = yt.SlicePlot(ds, {\it axis or normal vector}, {\it field}, {\it center=}, {\it width=}, {\it weight\_field=}, {\it additional parameters})} \textemdash\ Make a slice plot -perpendicular to {\it axis} (specified via ‘x’, ‘y’, or ‘z’) or a normal vector for an off-axis slice of {\it field} weighted by {\it weight\_field} at (code-units) {\it center} with -{\it width} in code units or a (value, unit) tuple. Hint: try {\it yt.SlicePlot?} in IPython to see additional parameters.\\ -\texttt{slc.save({\it file\_prefix})} \textemdash\ Save the slice to a png with name prefix {\it file\_prefix}. +\texttt{slc = yt.SlicePlot(ds, \textit{axis or normal vector}, \textit{field}, \textit{center=}, \textit{width=}, \textit{weight\_field=}, \textit{additional parameters})} \textemdash\ Make a slice plot +perpendicular to \textit{axis} (specified via ‘x’, ‘y’, or ‘z’) or a normal vector for an off-axis slice of \textit{field} weighted by \textit{weight\_field} at (code-units) \textit{center} with +\textit{width} in code units or a (value, unit) tuple. Hint: try \textit{yt.SlicePlot?} in IPython to see additional parameters.\\ +\texttt{slc.save(\textit{file\_prefix})} \textemdash\ Save the slice to a png with name prefix \textit{file\_prefix}.</p>
<pre>\texttt{.save()} works similarly for the commands below.\\
</pre>
<p>-\texttt{prj = yt.ProjectionPlot(ds, {\it axis}, {\it field}, {\it addit. params})} \textemdash\ Make a projection. \\ -\texttt{prj = yt.OffAxisProjectionPlot(ds, {\it normal}, {\it fields}, {\it center=}, {\it width=}, {\it depth=},{\it north\_vector=},{\it weight\_field=})} \textemdash Make an off axis projection. Note this takes an array of fields. \\ +\texttt{prj = yt.ProjectionPlot(ds, \textit{axis}, \textit{field}, \textit{addit. params})} \textemdash\ Make a projection. \\ +\texttt{prj = yt.OffAxisProjectionPlot(ds, \textit{normal}, \textit{fields}, \textit{center=}, \textit{width=}, \textit{depth=},\textit{north\_vector=},\textit{weight\_field=})} \textemdash Make an off axis projection. Note this takes an array of fields. \\</p>
<pre>\subsection{Plot Annotations}
\settowidth{\MyLen}{\texttt{multicol} }</pre>
<p>-Plot callbacks are functions itemized in a registry that is attached to every plot object. They can be accessed and then called like \texttt{ prj.annotate\_velocity(factor=16, normalize=False)}. Most callbacks also accept a {\it plot\_args} dict that is fed to matplotlib annotator. \\ -\texttt{velocity({\it factor=},{\it scale=},{\it scale\_units=}, {\it normalize=})} \textemdash\ Uses field “x-velocity” to draw quivers\\ -\texttt{magnetic\_field({\it factor=},{\it scale=},{\it scale\_units=}, {\it normalize=})} \textemdash\ Uses field “Bx” to draw quivers\\ -\texttt{quiver({\it field\_x},{\it field\_y},{\it factor=},{\it scale=},{\it scale\_units=}, {\it normalize=})} \\ -\texttt{contour({\it field=},{\it ncont=},{\it factor=},{\it clim=},{\it take\_log=}, {\it additional parameters})} \textemdash Plots a number of contours {\it ncont} to interpolate {\it field} optionally using {\it take\_log}, upper and lower {\it c}ontour{\it lim}its and {\it factor} number of points in the interpolation.\\ -\texttt{grids({\it alpha=}, {\it draw\_ids=}, {\it periodic=}, {\it min\_level=}, {\it max\_level=})} \textemdash Add grid boundaries. \\ -\texttt{streamlines({\it field\_x},{\it field\_y},{\it factor=},{\it density=})}\\ -\texttt{clumps({\it clumplist})} \textemdash\ Generate {\it clumplist} using the clump finder and plot. \\ -\texttt{arrow({\it pos}, {\it code\_size})} Add an arrow at a {\it pos}ition. \\ -\texttt{point({\it pos}, {\it text})} \textemdash\ Add text at a {\it pos}ition. \\ -\texttt{marker({\it pos}, {\it marker=})} \textemdash\ Add a matplotlib-defined marker at a {\it pos}ition. \\ -\texttt{sphere({\it center}, {\it radius}, {\it text=})} \textemdash\ Draw a circle and append {\it text}.\\ -\texttt{hop\_circles({\it hop\_output}, {\it max\_number=}, {\it annotate=}, {\it min\_size=}, {\it max\_size=}, {\it font\_size=}, {\it print\_halo\_size=}, {\it fixed\_radius=}, {\it min\_mass=}, {\it print\_halo\_mass=}, {\it width=})} \textemdash\ Draw a halo, printing it's ID, mass, clipping halos depending on number of particles ({\it size}) and optionally fixing the drawn circle radius to be constant for all halos.\\ -\texttt{hop\_particles({\it hop\_output},{\it max\_number=},{\it p\_size=},\\ -{\it min\_size},{\it alpha=})} \textemdash\ Draw particle positions for member halos with a certain number of pixels per particle.\\ -\texttt{particles({\it width},{\it p\_size=},{\it col=}, {\it marker=}, {\it stride=}, {\it ptype=}, {\it stars\_only=}, {\it dm\_only=}, {\it minimum\_mass=}, {\it alpha=})}  \textemdash\  Draw particles of {\it p\_size} pixels in a slab of {\it width} with {\it col}or using a matplotlib {\it marker} plotting only every {\it stride} number of particles.\\ -\texttt{title({\it text})}\\ +Plot callbacks are functions itemized in a registry that is attached to every plot object. They can be accessed and then called like \texttt{ prj.annotate\_velocity(factor=16, normalize=False)}. Most callbacks also accept a \textit{plot\_args} dict that is fed to matplotlib annotator. \\ +\texttt{velocity(\textit{factor=},\textit{scale=},\textit{scale\_units=}, \textit{normalize=})} \textemdash\ Uses field “x-velocity” to draw quivers\\ +\texttt{magnetic\_field(\textit{factor=},\textit{scale=},\textit{scale\_units=}, \textit{normalize=})} \textemdash\ Uses field “Bx” to draw quivers\\ +\texttt{quiver(\textit{field\_x},\textit{field\_y},\textit{factor=},\textit{scale=},\textit{scale\_units=}, \textit{normalize=})} \\ +\texttt{contour(\textit{field=},\textit{ncont=},\textit{factor=},\textit{clim=},\textit{take\_log=}, \textit{additional parameters})} \textemdash Plots a number of contours \textit{ncont} to interpolate \textit{field} optionally using \textit{take\_log}, upper and lower \textit{c}ontour\textit{lim}its and \textit{factor} number of points in the interpolation.\\ +\texttt{grids(\textit{alpha=}, \textit{draw\_ids=}, \textit{periodic=}, \textit{min\_level=}, \textit{max\_level=})} \textemdash Add grid boundaries. \\ +\texttt{streamlines(\textit{field\_x},\textit{field\_y},\textit{factor=},\textit{density=})}\\ +\texttt{clumps(\textit{clumplist})} \textemdash\ Generate \textit{clumplist} using the clump finder and plot. \\ +\texttt{arrow(\textit{pos}, \textit{code\_size})} Add an arrow at a \textit{pos}ition. \\ +\texttt{point(\textit{pos}, \textit{text})} \textemdash\ Add text at a \textit{pos}ition. \\ +\texttt{marker(\textit{pos}, \textit{marker=})} \textemdash\ Add a matplotlib-defined marker at a \textit{pos}ition. \\ +\texttt{sphere(\textit{center}, \textit{radius}, \textit{text=})} \textemdash\ Draw a circle and append \textit{text}.\\ +\texttt{hop\_circles(\textit{hop\_output}, \textit{max\_number=}, \textit{annotate=}, \textit{min\_size=}, \textit{max\_size=}, \textit{font\_size=}, \textit{print\_halo\_size=}, \textit{fixed\_radius=}, \textit{min\_mass=}, \textit{print\_halo\_mass=}, \textit{width=})} \textemdash\ Draw a halo, printing it's ID, mass, clipping halos depending on number of particles (\textit{size}) and optionally fixing the drawn circle radius to be constant for all halos.\\ +\texttt{hop\_particles(\textit{hop\_output},\textit{max\_number=},\textit{p\_size=},\\ +\textit{min\_size},\textit{alpha=})} \textemdash\ Draw particle positions for member halos with a certain number of pixels per particle.\\ +\texttt{particles(\textit{width},\textit{p\_size=},\textit{col=}, \textit{marker=}, \textit{stride=}, \textit{ptype=}, \textit{stars\_only=}, \textit{dm\_only=}, \textit{minimum\_mass=}, \textit{alpha=})}  \textemdash\  Draw particles of \textit{p\_size} pixels in a slab of \textit{width} with \textit{col}or using a matplotlib \textit{marker} plotting only every \textit{stride} number of particles.\\ +\texttt{title(\textit{text})}\\</p>
<pre>\subsection{The $\sim$/.yt/ Directory}
\settowidth{\MyLen}{\texttt{multicol} }</pre>
<p>@@ -297,12 +297,12 @@</p>
<pre>\subsection{Parallel Analysis}</pre>
<p>-\settowidth{\MyLen}{\texttt{multicol}} +\settowidth{\MyLen}{\texttt{multicol}}</p>
<pre>Nearly all of yt is parallelized using</pre>
<p>-MPI.  The {\it mpi4py} package must be installed for parallelism in yt.  To -install {\it pip install mpi4py} on the command line usually works. +MPI\@.  The \textit{mpi4py} package must be installed for parallelism in yt.  To +install \textit{pip install mpi4py} on the command line usually works.</p>
<pre>Execute python in parallel similar to this:\\</pre>
<p>-{\it mpirun -n 12 python script.py}\\ +\textit{mpirun -n 12 python script.py}\\</p>
<pre>The file \texttt{script.py} must call the \texttt{yt.enable\_parallelism()} to
turn on yt's parallelism.  If this doesn't happen, all cores will execute the
same serial yt script.  This command may differ for each system on which you use</pre>
<p>@@ -320,12 +320,12 @@</p>
<pre>\texttt{hg clone https://bitbucket.org/yt\_analysis/yt} \textemdash\ Clone a copy of yt. \\
\texttt{hg status} \textemdash\ Files changed in working directory.\\
\texttt{hg diff} \textemdash\ Print diff of all changed files in working directory. \\</pre>
<p>-\texttt{hg diff -r{\it RevX} -r{\it RevY}} \textemdash\ Print diff of all changes between revision {\it RevX} and {\it RevY}.\\ +\texttt{hg diff -r\textit{RevX} -r\textit{RevY}} \textemdash\ Print diff of all changes between revision \textit{RevX} and \textit{RevY}.\\</p>
<pre>\texttt{hg log} \textemdash\ History of changes.\\</pre>
<p>-\texttt{hg cat -r{\it RevX file}} \textemdash\ Print the contents of {\it file} from revision {\it RevX}.\\ +\texttt{hg cat -r\textit{RevX file}} \textemdash\ Print the contents of \textit{file} from revision \textit{RevX}.\\</p>
<pre>\texttt{hg heads} \textemdash\ Print all the current heads. \\</pre>
<p>-\texttt{hg revert -r{\it RevX file}} \textemdash\ Revert {\it file} to revision {\it RevX}. On-disk changed version is -moved to {\it file.orig}. \\ +\texttt{hg revert -r\textit{RevX file}} \textemdash\ Revert \textit{file} to revision \textit{RevX}. On-disk changed version is +moved to \textit{file.orig}. \\</p>
<pre>\texttt{hg commit} \textemdash\ Commit changes to repository. \\
\texttt{hg push} \textemdash\ Push changes to default remote repository. \\
\texttt{hg pull} \textemdash\ Pull changes from default remote repository. \\</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe doc/source/analyzing/analysis_modules/halo_finders.rst --- a/doc/source/analyzing/analysis_modules/halo_finders.rst +++ b/doc/source/analyzing/analysis_modules/halo_finders.rst @@ -41,11 +41,11 @@</p>
<pre>   depending on the user-supplied over density
   threshold parameter. The default is 160.0.
</pre>
<p>-Please see the `HOP method paper -<<a href="http://adsabs.harvard.edu/abs/1998ApJ…498..137E">http://adsabs.harvard.edu/abs/1998ApJ…498..137E</a>>`_ for -full details and the -:class:`~yt.analysis_modules.halo_finding.halo_objects.HOPHalo` and -:class:`~yt.analysis_modules.halo_finding.halo_objects.Halo` classes. +Please see the `HOP method paper +<<a href="http://adsabs.harvard.edu/abs/1998ApJ…498..137E">http://adsabs.harvard.edu/abs/1998ApJ…498..137E</a>>`_ for +full details and the +:class:`~yt.analysis_modules.halo_finding.halo_objects.HOPHaloFinder` +documentation.</p>
<pre>.. _fof:
</pre>
<p>@@ -53,8 +53,8 @@</p>
<pre>---

A basic friends-of-friends halo finder is included.  See the</pre>
<p>-:class:`~yt.analysis_modules.halo_finding.halo_objects.FOFHalo` and -:class:`~yt.analysis_modules.halo_finding.halo_objects.Halo` classes. +:class:`~yt.analysis_modules.halo_finding.halo_objects.FOFHaloFinder` +documentation.</p>
<pre>.. _rockstar:
</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe doc/source/cookbook/tests/test_cookbook.py --- a/doc/source/cookbook/tests/test_cookbook.py +++ b/doc/source/cookbook/tests/test_cookbook.py @@ -11,16 +11,22 @@</p>
<pre>"""
import glob
import os</pre>
<p>+import sys</p>
<pre>import subprocess


PARALLEL_TEST = {"rockstar_nest.py": "3"}</pre>
<p>+BLACKLIST = ["opengl_ipython.py", “opengl_vr.py”]</p>
<p>+if sys.version_info >= (3,0,0): +    BLACKLIST.append("rockstar_nest.py")</p>
<pre>def test_recipe():
    '''Dummy test grabbing all cookbook's recipes'''
    for fname in glob.glob("doc/source/cookbook/*.py"):
        recipe = os.path.basename(fname)</pre>
<p>+        if recipe in BLACKLIST: +            continue</p>
<pre>         check_recipe.description = "Testing recipe: %s" % recipe
         if recipe in PARALLEL_TEST:
yield check_recipe, \</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe tests/tests_2.7.yaml --- a/tests/tests_2.7.yaml +++ b/tests/tests_2.7.yaml @@ -42,7 +42,7 @@</p>
<pre>local_tipsy_270:
  - yt/frontends/tipsy/tests/test_outputs.py
</pre>
<ul><li><p>local_varia_273:</p></li></ul>
<p>+  local_varia_274:</p>
<pre>- yt/analysis_modules/radmc3d_export
- yt/frontends/moab/tests/test_c5.py
- yt/analysis_modules/photon_simulator/tests/test_spectra.py</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe tests/tests_3.5.yaml --- a/tests/tests_3.5.yaml +++ b/tests/tests_3.5.yaml @@ -25,6 +25,8 @@</p>
<pre>local_halos_350:
  - yt/frontends/owls_subfind/tests/test_outputs.py</pre>
<p>+    – yt/frontends/gadget_fof/tests/test_outputs.py:test_fields_g5 +    – yt/frontends/gadget_fof/tests/test_outputs.py:test_fields_g42</p>
<pre>local_owls_350:
  - yt/frontends/owls/tests/test_outputs.py</pre>
<p>@@ -40,7 +42,7 @@</p>
<pre>local_tipsy_350:
  - yt/frontends/tipsy/tests/test_outputs.py
</pre>
<ul><li><p>local_varia_350:</p></li></ul>
<p>+  local_varia_351:</p>
<pre>- yt/analysis_modules/radmc3d_export
- yt/frontends/moab/tests/test_c5.py
- yt/analysis_modules/photon_simulator/tests/test_spectra.py</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/analysis_modules/halo_finding/halo_objects.py --- a/yt/analysis_modules/halo_finding/halo_objects.py +++ b/yt/analysis_modules/halo_finding/halo_objects.py @@ -59,7 +59,10 @@</p>
<pre>def __init__(self, halo_list, id, indices=None, size=None, CoM=None,
    max_dens_point=None, group_total_mass=None, max_radius=None,</pre>
<ul><li><p>bulk_vel=None, tasks=None, rms_vel=None, supp=None):</p></li></ul>
<p>+        bulk_vel=None, tasks=None, rms_vel=None, supp=None, ptype=None): +        if ptype is None: +            ptype = “all” +        self.ptype = ptype</p>
<pre>self.halo_list = halo_list
self._max_dens = halo_list._max_dens
self.id = id</pre>
<p>@@ -276,10 +279,7 @@</p>
<pre>        return r.max()

    def __getitem__(self, key):</pre>
<ul><li><p>if ytcfg.getboolean("yt", “inline”) is False:</p></li>
<li><p>return self.data[key][self.indices]</p></li>
<li><p>else:</p></li>
<li><p>return self.data[key][self.indices]</p></li></ul>
<p>+        return self.data[(self.ptype, key)][self.indices]</p>
<pre>def get_sphere(self, center_of_mass=True):
    r"""Returns a sphere source.</pre>
<p>@@ -954,7 +954,8 @@</p>
<pre>    _fields = ["particle_position_%s" % ax for ax in 'xyz']
</pre>
<ul><li><p>def __init__(self, data_source, dm_only=True, redshift=-1):</p></li></ul>
<p>+    def __init__(self, data_source, dm_only=True, redshift=-1, +                 ptype=None):</p>
<pre>"""
Run hop on *data_source* with a given density *threshold*.  If
*dm_only* is True (default), only run it on the dark matter particles,</pre>
<p>@@ -963,6 +964,9 @@</p>
<pre>"""
self._data_source = data_source
self.dm_only = dm_only</pre>
<p>+        if ptype is None: +            ptype = “all” +        self.ptype = ptype</p>
<pre>self._groups = []
self._max_dens = {}
self.__obtain_particles()</pre>
<p>@@ -979,14 +983,14 @@</p>
<pre>ii = slice(None)
         self.particle_fields = {}
         for field in self._fields:</pre>
<ul><li><p>tot_part = self._data_source[field].size</p></li></ul>
<p>+            tot_part = self._data_source[(self.ptype, field)].size</p>
<pre>if field == "particle_index":
    self.particle_fields[field] = \</pre>
<ul><li><p>self._data_source[field][ii].astype('int64')</p></li></ul>
<p>+                    self._data_source[(self.ptype, field)][ii].astype('int64')</p>
<pre>else:
    self.particle_fields[field] = \</pre>
<ul><li><p>self._data_source[field][ii].astype('float64')</p></li>
<li><p>del self._data_source[field]</p></li></ul>
<p>+                    self._data_source[(self.ptype, field)][ii].astype('float64') +            del self._data_source[(self.ptype, field)]</p>
<pre>        self._base_indices = np.arange(tot_part)[ii]
        gc.collect()
</pre>
<p>@@ -1014,11 +1018,12 @@</p>
<pre>    cp += counts[i + 1]
    continue
group_indices = grab_indices[cp:cp_c]</pre>
<ul><li><p>self._groups.append(self._halo_class(self, i, group_indices))</p></li></ul>
<p>+            self._groups.append(self._halo_class(self, i, group_indices, +                                                 ptype=self.ptype))</p>
<pre>md_i = np.argmax(dens[cp:cp_c])
px, py, pz = \
    [self.particle_fields['particle_position_%s' % ax][group_indices]</pre>
<ul><li><p>for ax in ‘xyz’]</p></li></ul>
<p>+                 for ax in ‘xyz’]</p>
<pre>self._max_dens[i] = (dens[cp:cp_c][md_i], px[md_i],
    py[md_i], pz[md_i])
cp += counts[i + 1]</pre>
<p>@@ -1260,10 +1265,11 @@</p>
<pre>    _fields = ["particle_position_%s" % ax for ax in 'xyz'] + \
              ["particle_mass"]
</pre>
<ul><li><p>def __init__(self, data_source, threshold=160.0, dm_only=True):</p></li></ul>
<p>+    def __init__(self, data_source, threshold=160.0, dm_only=True, +                 ptype=None):</p>
<pre>self.threshold = threshold
mylog.info("Initializing HOP")</pre>
<ul><li><p>HaloList.__init__(self, data_source, dm_only)</p></li></ul>
<p>+        HaloList.__init__(self, data_source, dm_only, ptype=ptype)</p>
<pre>def _run_finder(self):
    self.densities, self.tags = \</pre>
<p>@@ -1298,10 +1304,12 @@</p>
<pre>    _name = "FOF"
    _halo_class = FOFHalo
</pre>
<ul><li><p>def __init__(self, data_source, link=0.2, dm_only=True, redshift=-1):</p></li></ul>
<p>+    def __init__(self, data_source, link=0.2, dm_only=True, redshift=-1, +                 ptype=None):</p>
<pre>self.link = link
mylog.info("Initializing FOF")</pre>
<ul><li><p>HaloList.__init__(self, data_source, dm_only, redshift=redshift)</p></li></ul>
<p>+        HaloList.__init__(self, data_source, dm_only, redshift=redshift, +                          ptype=ptype)</p>
<pre>def _run_finder(self):
    self.tags = \</pre>
<p>@@ -1450,12 +1458,15 @@</p>
<pre>            halo += 1

class GenericHaloFinder(HaloList, ParallelAnalysisInterface):</pre>
<ul><li><p>def __init__(self, ds, data_source, dm_only=True, padding=0.0):</p></li></ul>
<p>+    def __init__(self, ds, data_source, padding=0.0, ptype=None):</p>
<pre>         ParallelAnalysisInterface.__init__(self)
         self.ds = ds
         self.index = ds.index
         self.center = (np.array(data_source.right_edge) +
np.array(data_source.left_edge)) / 2.0</pre>
<p>+        if ptype is None: +            ptype = “all” +        self.ptype = ptype</p>
<pre>def _parse_halolist(self, threshold_adjustment):
    groups = []</pre>
<p>@@ -1474,7 +1485,7 @@</p>
<pre>    threshold_adjustment
max_dens[hi] = [max_dens_temp] + \
    list(self._max_dens[halo.id])[1:4]</pre>
<ul><li><p>groups.append(self._halo_class(self, hi))</p></li></ul>
<p>+                groups.append(self._halo_class(self, hi, ptype=self.ptype))</p>
<pre>groups[-1].indices = halo.indices
self.comm.claim_object(groups[-1])
hi += 1</pre>
<p>@@ -1505,9 +1516,11 @@</p>
<pre># Note: we already know which halos we own!
after = my_first_id + len(self._groups)
# One single fake halo, not owned, does the trick</pre>
<ul><li><p>self._groups = [self._halo_class(self, i) for i in range(my_first_id)] + \</p></li></ul>
<p>+        self._groups = [self._halo_class(self, i, ptype=self.ptype) +                        for i in range(my_first_id)] + \</p>
<pre>self._groups + \</pre>
<ul><li><p>[self._halo_class(self, i) for i in range(after, nhalos)]</p></li></ul>
<p>+                       [self._halo_class(self, i, ptype=self.ptype) +                        for i in range(after, nhalos)]</p>
<pre>         id = 0
         for proc in sorted(halo_info.keys()):
for halo in self._groups[id:id + halo_info[proc]]:</pre>
<p>@@ -1540,7 +1553,7 @@</p>
<pre>LE, RE = bounds
dw = self.ds.domain_right_edge - self.ds.domain_left_edge
for i, ax in enumerate('xyz'):</pre>
<ul><li><p>arr = self._data_source["particle_position_%s" % ax]</p></li></ul>
<p>+            arr = self._data_source[self.ptype, “particle_position_%s” % ax]</p>
<pre>            arr[arr < LE[i] - self.padding] += dw[i]
            arr[arr > RE[i] + self.padding] -= dw[i]
</pre>
<p>@@ -1671,9 +1684,15 @@</p>
<pre>    to the full volume automatically.
threshold : float
    The density threshold used when building halos. Default = 160.0.</pre>
<ul><li><p>dm_only : bool</p></li></ul>
<p>+    dm_only : bool (deprecated)</p>
<pre>If True, only dark matter particles are used when building halos.</pre>
<p>+        This has been deprecated.  Instead, the ptype keyword should be +        used to specify a particle type.</p>
<pre>Default = True.</pre>
<p>+    ptype : string +        When dm_only is set to False, this sets the type of particle to be +        used for halo finding, with a default of “all”.  This should not be +        used when dm_only is set to True.</p>
<pre>padding : float
    When run in parallel, the finder needs to surround each subvolume
    with duplicated particles for halo finidng to work. This number</pre>
<p>@@ -1697,14 +1716,14 @@</p>
<pre>>>> halos = HaloFinder(ds)
"""
def __init__(self, ds, subvolume=None, threshold=160, dm_only=True,</pre>
<ul><li><p>padding=0.02, total_mass=None):</p></li></ul>
<p>+                 ptype=None, padding=0.02, total_mass=None):</p>
<pre>         if subvolume is not None:
ds_LE = np.array(subvolume.left_edge)
ds_RE = np.array(subvolume.right_edge)
         self.period = ds.domain_right_edge - ds.domain_left_edge
         self._data_source = ds.all_data()</pre>
<ul><li><p>GenericHaloFinder.__init__(self, ds, self._data_source, dm_only,</p></li>
<li><p>padding)</p></li></ul>
<p>+        GenericHaloFinder.__init__(self, ds, self._data_source, padding, +                                   ptype=ptype)</p>
<pre># do it once with no padding so the total_mass is correct
# (no duplicated particles), and on the entire volume, even if only
# a small part is actually going to be used.</pre>
<p>@@ -1712,6 +1731,21 @@</p>
<pre>         padded, LE, RE, self._data_source = \
self.partition_index_3d(ds=self._data_source,
    padding=self.padding)</pre>
<p>+ +        if dm_only: +            mylog.warn("dm_only is deprecated.  " + +                       “Use ptype to specify a particle type, instead.”) + +        # Don't allow dm_only=True and setting a ptype. +        if dm_only and ptype is not None: +            raise RuntimeError( +                “If dm_only is True, ptype must be None.  " + \ +                “dm_only must be False if ptype is set.”) + +        if ptype is None: +            ptype = "all” +        self.ptype = ptype +</p>
<pre>         # For scaling the threshold, note that it's a passthrough
         if total_mass is None:
if dm_only:</pre>
<p>@@ -1719,7 +1753,9 @@</p>
<pre>    total_mass = \
        self.comm.mpi_allreduce((self._data_source['all', "particle_mass"][select].in_units('Msun')).sum(dtype='float64'), op='sum')
else:</pre>
<ul><li><p>total_mass = self.comm.mpi_allreduce(self._data_source.quantities["TotalQuantity"]("particle_mass").in_units('Msun'), op='sum')</p></li></ul>
<p>+                total_mass = self.comm.mpi_allreduce( +                    self._data_source.quantities.total_quantity( +                        (self.ptype, "particle_mass")).in_units('Msun'), op='sum')</p>
<pre># MJT: Note that instead of this, if we are assuming that the particles
# are all on different processors, we should instead construct an
# object representing the entire domain and sum it "lazily" with</pre>
<p>@@ -1743,9 +1779,10 @@</p>
<pre>sub_mass = self._data_source["particle_mass"][select].in_units('Msun').sum(dtype='float64')
         else:
sub_mass = \</pre>
<ul><li><p>self._data_source.quantities["TotalQuantity"]("particle_mass").in_units('Msun')</p></li></ul>
<p>+                self._data_source.quantities.total_quantity( +                    (self.ptype, "particle_mass")).in_units('Msun')</p>
<pre>HOPHaloList.__init__(self, self._data_source,</pre>
<ul><li><p>threshold * total_mass / sub_mass, dm_only)</p></li></ul>
<p>+            threshold * total_mass / sub_mass, dm_only, ptype=self.ptype)</p>
<pre>        self._parse_halolist(total_mass / sub_mass)
        self._join_halolists()
</pre>
<p>@@ -1776,9 +1813,15 @@</p>
<pre>average) used to build the halos. If negative, this is taken to be
the *actual* linking length, and no other calculations will be
applied.  Default = 0.2.</pre>
<ul><li><p>dm_only : bool</p></li></ul>
<p>+    dm_only : bool (deprecated)</p>
<pre>If True, only dark matter particles are used when building halos.</pre>
<p>+        This has been deprecated.  Instead, the ptype keyword should be +        used to specify a particle type.</p>
<pre>Default = True.</pre>
<p>+    ptype : string +        When dm_only is set to False, this sets the type of particle to be +        used for halo finding, with a default of “all”.  This should not be +        used when dm_only is set to True.</p>
<pre>padding : float
    When run in parallel, the finder needs to surround each subvolume
    with duplicated particles for halo finidng to work. This number</pre>
<p>@@ -1791,7 +1834,7 @@</p>
<pre>>>> halos = FOFHaloFinder(ds)
"""
def __init__(self, ds, subvolume=None, link=0.2, dm_only=True,</pre>
<ul><li><p>padding=0.02):</p></li></ul>
<p>+                 ptype=None, padding=0.02):</p>
<pre>         if subvolume is not None:
ds_LE = np.array(subvolume.left_edge)
ds_RE = np.array(subvolume.right_edge)</pre>
<p>@@ -1800,13 +1843,27 @@</p>
<pre>self.index = ds.index
self.redshift = ds.current_redshift
self._data_source = ds.all_data()</pre>
<ul><li><p>GenericHaloFinder.__init__(self, ds, self._data_source, dm_only,</p></li>
<li><p>padding)</p></li></ul>
<p>+        GenericHaloFinder.__init__(self, ds, self._data_source, padding)</p>
<pre>         self.padding = 0.0  # * ds["unitary"] # This should be clevererer
         # get the total number of particles across all procs, with no padding
         padded, LE, RE, self._data_source = \
self.partition_index_3d(ds=self._data_source,
padding=self.padding)</pre>
<p>+ +        if dm_only: +            mylog.warn("dm_only is deprecated.  " + +                       “Use ptype to specify a particle type, instead.”) + +        # Don't allow dm_only=True and setting a ptype. +        if dm_only and ptype is not None: +            raise RuntimeError( +                “If dm_only is True, ptype must be None.  " + \ +                “dm_only must be False if ptype is set.”) + +        if ptype is None: +            ptype = "all” +        self.ptype = ptype +</p>
<pre>         if link > 0.0:
n_parts = self.comm.mpi_allreduce(self._data_source["particle_position_x"].size, op='sum')
# get the average spacing between particles</pre>
<p>@@ -1834,7 +1891,7 @@</p>
<pre># here is where the FOF halo finder is run
mylog.info("Using a linking length of %0.3e", linking_length)
FOFHaloList.__init__(self, self._data_source, linking_length, dm_only,</pre>
<ul><li><p>redshift=self.redshift)</p></li></ul>
<p>+                             redshift=self.redshift, ptype=self.ptype)</p>
<pre>        self._parse_halolist(1.)
        self._join_halolists()
</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/analysis_modules/halo_finding/tests/test_halo_finders.py --- /dev/null +++ b/yt/analysis_modules/halo_finding/tests/test_halo_finders.py @@ -0,0 +1,61 @@ +""" +Tests for HOP and FOF halo finders. + + + +""" + +#----------------------------------------------------------------------------- +# Copyright © 2016, yt Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +from yt.convenience import \ +    load +from yt.data_objects.particle_filters import \ +    add_particle_filter +from yt.analysis_modules.halo_analysis.api import \ +    HaloCatalog +from yt.testing import \ +    requires_file, \ +    assert_array_equal +from yt.utilities.answer_testing.framework import \ +    data_dir_load + +import tempfile +import os +import shutil + +def dm(pfilter, data): +    return data["creation_time"] <= 0. +add_particle_filter("dm", dm, filtered_type='all', +                    requires=["creation_time"]) + +enzotiny = “enzo_tiny_cosmology/DD0046/DD0046” +@requires_file(enzotiny) +def test_datacontainer_data(): +    tmpdir = tempfile.mkdtemp() +    curdir = os.getcwd() +    os.chdir(tmpdir) +    ds = data_dir_load(enzotiny) +    ds.add_particle_filter("dm") + +    for method in ["fof", “hop"]: +        hc = HaloCatalog(data_ds=ds, finder_method=method, +                         output_dir="hc1”, +                         finder_kwargs={"dm_only": True}) +        hc.create() +        hc = HaloCatalog(data_ds=ds, finder_method=method, +                         output_dir="hc2", +                         finder_kwargs={"dm_only": False, “ptype”: “dm"}) +        hc.create() + +        ds1 = load("hc1/hc1.0.h5”) +        ds2 = load("hc2/hc2.0.h5") +        assert_array_equal(ds1.r["particle_mass"], ds2.r["particle_mass"]) + +    os.chdir(curdir) +    shutil.rmtree(tmpdir)</p>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/frontends/gadget_fof/tests/test_outputs.py --- a/yt/frontends/gadget_fof/tests/test_outputs.py +++ b/yt/frontends/gadget_fof/tests/test_outputs.py @@ -62,7 +62,7 @@</p>
<pre>for hid in range(0, ds.index.particle_count["Group"]):
    my_h = ds.halo("Group", hid)
    h_ids = my_h["ID"]</pre>
<ul><li><p>for sid in range(my_h["subhalo_number"]):</p></li></ul>
<p>+        for sid in range(int(my_h["subhalo_number"][0])):</p>
<pre>my_s = ds.halo("Subhalo", (my_h.particle_identifier, sid))
total_sub += my_s["ID"].size
total_int += np.intersect1d(h_ids, my_s["ID"]).size</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/utilities/lib/grid_traversal.pyx --- a/yt/utilities/lib/grid_traversal.pyx +++ b/yt/utilities/lib/grid_traversal.pyx @@ -492,6 +492,15 @@</p>
<pre>    cdef void setup(self, PartitionedGrid pg):
        return
</pre>
<p>+    def __dealloc__(self): +        self.image.image = None +        self.image.vp_pos = None +        self.image.vp_dir = None +        self.image.zbuffer = None +        self.image.camera_data = None +        free(self.image) + +</p>
<pre>cdef void projection_sampler(
                 VolumeContainer *vc,
                 np.float64_t v_pos[3],</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/utilities/lib/mesh_construction.pxd --- a/yt/utilities/lib/mesh_construction.pxd +++ b/yt/utilities/lib/mesh_construction.pxd @@ -2,6 +2,7 @@</p>
<pre>Vertex, \
Triangle, \
Vec3f</pre>
<p>+cimport numpy as np</p>
<pre>ctypedef struct MeshDataContainer:
    Vertex* vertices       # array of triangle vertices</pre>
<p>@@ -14,6 +15,5 @@</p>
<pre>ctypedef struct Patch:
    float[8][3] v
    unsigned int geomID</pre>
<ul><li><p>long [:,:] indices</p></li>
<li><p>double [:,:] vertices</p></li>
<li><p>double [:,:] field_data</p></li></ul>
<p>+    np.float64_t* vertices +    np.float64_t* field_data</p>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/utilities/lib/mesh_construction.pyx --- a/yt/utilities/lib/mesh_construction.pyx +++ b/yt/utilities/lib/mesh_construction.pyx @@ -241,6 +241,8 @@</p>
<pre>    '''

    cdef Patch* patches</pre>
<p>+    cdef np.float64_t* vertices +    cdef np.float64_t* field_data</p>
<pre>cdef unsigned int mesh
# patches per element, vertices per element, and field points per
# element, respectively:</pre>
<p>@@ -265,11 +267,22 @@</p>
<pre>np.ndarray field_data):
         cdef int i, j, ind, idim
         cdef int ne = indices_in.shape[0]</pre>
<p>+        cdef int nv = vertices_in.shape[0]</p>
<pre>        cdef int npatch = 6*ne;

        cdef unsigned int mesh = rtcgu.rtcNewUserGeometry(scene.scene_i, npatch)
        cdef np.ndarray[np.float64_t, ndim=2] element_vertices</pre>
<ul><li><p>cdef Patch* patches = <Patch*> malloc(npatch * sizeof(Patch));</p></li></ul>
<p>+        cdef Patch* patches = <Patch*> malloc(npatch * sizeof(Patch)) +        self.vertices = <np.float64_t*> malloc(20 * ne * 3 * sizeof(np.float64_t)) +        self.field_data = <np.float64_t*> malloc(20 * ne * sizeof(np.float64_t)) + +        for i in range(ne): +            element_vertices = vertices_in[indices_in[i]] +            for j in range(20): +                self.field_data[i*20 + j] = field_data[i][j] +                for k in range(3): +                    self.vertices[i*20*3 + j*3 + k] = element_vertices[j][k] +</p>
<pre>         cdef Patch* patch
         for i in range(ne):  # for each element
element_vertices = vertices_in[indices_in[i]]</pre>
<p>@@ -280,9 +293,8 @@</p>
<pre>ind = hex20_faces[j][k]
for idim in range(3):  # for each spatial dimension (yikes)
    patch.v[k][idim] = element_vertices[ind][idim]</pre>
<ul><li><p>patch.indices = indices_in</p></li>
<li><p>patch.vertices = vertices_in</p></li>
<li><p>patch.field_data = field_data</p></li></ul>
<p>+                patch.vertices = self.vertices + i*20*3 +                patch.field_data = self.field_data + i*20</p>
<pre>self.patches = patches
self.mesh = mesh</pre>
<p>@@ -295,3 +307,5 @@</p>
<pre>def __dealloc__(self):
    free(self.patches)</pre>
<p>+        free(self.vertices) +        free(self.field_data)</p>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/utilities/lib/mesh_samplers.pyx --- a/yt/utilities/lib/mesh_samplers.pyx +++ b/yt/utilities/lib/mesh_samplers.pyx @@ -196,9 +196,6 @@</p>
<pre>rtcr.RTCRay& ray) nogil:
     cdef int ray_id, elem_id, i
     cdef double val</pre>
<ul><li><p>cdef double[20] field_data</p></li>
<li><p>cdef int[20] element_indices</p></li>
<li><p>cdef double[60] vertices cdef double[3] position cdef float[3] pos cdef Patch* data</p></li></ul>
<p>@@ -220,16 +217,10 @@</p>
<pre>   for i in range(3):
       position[i] = <double> pos[i]
</pre>
<ul><li><p>for i in range(20):</p></li>
<li><p>field_data[i] = patch.field_data[elem_id, i]</p></li>
<li><p>vertices[i*3    ] = patch.vertices[patch.indices[elem_id, i]][0]</p></li>
<li><p>vertices[i*3 + 1] = patch.vertices[patch.indices[elem_id, i]][1]</p></li>
<li><p>vertices[i*3 + 2] = patch.vertices[patch.indices[elem_id, i]][2]</p></li></ul>
<p>–</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[3]</pre>
<ul><li><p>S2Sampler.map_real_to_unit(mapped_coord, vertices, position)</p></li>
<li><p>val = S2Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    S2Sampler.map_real_to_unit(mapped_coord, patch.vertices, position) +    val = S2Sampler.sample_at_unit_point(mapped_coord, patch.field_data)</p>
<pre>    ray.time = val

    # we use ray.instID to pass back whether the ray is near the</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/utilities/lib/tests/test_bounding_volume_hierarchy.py --- a/yt/utilities/lib/tests/test_bounding_volume_hierarchy.py +++ b/yt/utilities/lib/tests/test_bounding_volume_hierarchy.py @@ -36,7 +36,8 @@</p>
<pre>    bvh = BVH(vertices, indices, field_data)
</pre>
<ul><li><p>cam = Camera(Scene())</p></li></ul>
<p>+    sc = Scene() +    cam = Camera(sc)</p>
<pre>cam.set_position(np.array([8.0, 8.0, 8.0]))
cam.focus = np.array([0.0, 0.0, 0.0])
origins, direction = get_rays(cam)</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/visualization/profile_plotter.py --- a/yt/visualization/profile_plotter.py +++ b/yt/visualization/profile_plotter.py @@ -462,7 +462,7 @@</p>
<pre>         """
         if field == "all":
self.x_log = log</pre>
<ul><li><p>for field in self.profiles[0].field_data.keys():</p></li></ul>
<p>+            for field in list(self.profiles[0].field_data.keys()):</p>
<pre>    self.y_log[field] = log
         else:
field, = self.profiles[0].data_source._determine_fields([field])</pre>
<p>@@ -578,7 +578,7 @@</p>
<pre>"""
if field is 'all':</pre>
<ul><li><p>fields = self.axes.keys()</p></li></ul>
<p>+            fields = list(self.axes.keys())</p>
<pre>         else:
fields = ensure_list(field)
         for profile in self.profiles:</pre>
<p>@@ -971,7 +971,7 @@</p>
<pre>        >>>  plot.annotate_text(1e-15, 5e4, "Hello YT")

        """</pre>
<ul><li><p>for f in self.data_source._determine_fields(self.plots.keys()):</p></li></ul>
<p>+        for f in self.data_source._determine_fields(list(self.plots.keys())):</p>
<pre>if self.plots[f].figure is not None and text is not None:
    self.plots[f].axes.text(xpos, ypos, text,
                            fontproperties=self._font_properties,</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/visualization/volume_rendering/camera.py --- a/yt/visualization/volume_rendering/camera.py +++ b/yt/visualization/volume_rendering/camera.py @@ -24,6 +24,7 @@</p>
<pre>    Lens
import numpy as np
from numbers import Number as numeric_type</pre>
<p>+import weakref</p>
<pre>def _sanitize_camera_property_units(value, scene):
    if iterable(value):</pre>
<p>@@ -126,7 +127,7 @@</p>
<pre>raise RuntimeError(
    'The first argument passed to the Camera initializer is a '
    '%s object, expected a %s object' % (type(scene), Scene))</pre>
<ul><li><p>self.scene = scene</p></li></ul>
<p>+        self.scene = weakref.proxy(scene)</p>
<pre>self.lens = None
self.north_vector = None
self.normal_vector = None</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/visualization/volume_rendering/tests/test_mesh_render.py --- a/yt/visualization/volume_rendering/tests/test_mesh_render.py +++ b/yt/visualization/volume_rendering/tests/test_mesh_render.py @@ -52,6 +52,7 @@</p>
<pre>    def mesh_render_image_func(filename_prefix):
        return im.write_image(filename_prefix)
</pre>
<p>+    mesh_render_image_func.__name__ = "func_{}".format(test_prefix)</p>
<pre>test = GenericImageTest(ds, mesh_render_image_func, decimals)
test.prefix = test_prefix
return test</pre>
<p>diff -r e0838f66ad6c7d2c10d4454b20272b0a33e22117 -r 672764585671c7d379c13c3537eebe2dde7dfcbe yt/visualization/volume_rendering/zbuffer_array.py --- a/yt/visualization/volume_rendering/zbuffer_array.py +++ b/yt/visualization/volume_rendering/zbuffer_array.py @@ -62,7 +62,7 @@</p>
<pre>rgba += (other.rgba * (1.0 - f)[:, None, :])
         else:
b = self.z > other.z</pre>
<ul><li><p>rgba = np.empty(self.rgba.shape)</p></li></ul>
<p>+            rgba = np.zeros(self.rgba.shape)</p>
<pre>rgba[f] = self.rgba[f]
rgba[b] = other.rgba[b]
         z = np.min([self.z, other.z], axis=0)</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/040184c871c8/">https://bitbucket.org/yt_analysis/yt/commits/040184c871c8/</a> Changeset:   040184c871c8 Branch:      yt User:        atmyers Date:        2016-04-03 23:00:26+00:00 Summary:     A BVH version of MeshSampler. Affected #:  4 files</p>
<p>diff -r 672764585671c7d379c13c3537eebe2dde7dfcbe -r 040184c871c896fd1d2889c1fe193f79396620af yt/utilities/lib/grid_traversal.pxd --- a/yt/utilities/lib/grid_traversal.pxd +++ b/yt/utilities/lib/grid_traversal.pxd @@ -25,6 +25,8 @@</p>
<pre>np.float64_t *center
np.float64_t[:,:,:] image
np.float64_t[:,:] zbuffer</pre>
<p>+    np.int64_t[:,:] image_used +    np.int64_t[:,:] mesh_lines</p>
<pre>np.float64_t pdx, pdy
np.float64_t bounds[4]
np.float64_t[:,:] camera_data   # position, width, unit_vec[0,2]</pre>
<p>@@ -59,6 +61,8 @@</p>
<pre>cdef sampler_function *sampler
cdef public object acenter, aimage, ax_vec, ay_vec
cdef public object azbuffer</pre>
<p>+    cdef public object aimage_used +    cdef public object amesh_lines</p>
<pre>cdef void *supp_data
cdef np.float64_t width[3]
cdef public object lens_type</pre>
<p>diff -r 672764585671c7d379c13c3537eebe2dde7dfcbe -r 040184c871c896fd1d2889c1fe193f79396620af yt/utilities/lib/grid_traversal.pyx --- a/yt/utilities/lib/grid_traversal.pyx +++ b/yt/utilities/lib/grid_traversal.pyx @@ -380,6 +380,8 @@</p>
<pre>*args, **kwargs):
         self.image = <ImageContainer *> calloc(sizeof(ImageContainer), 1)
         cdef np.float64_t[:,:] zbuffer</pre>
<p>+        cdef np.int64_t[:,:] image_used +        cdef np.int64_t[:,:] mesh_lines</p>
<pre>        cdef np.float64_t[:,:] camera_data
        cdef int i
</pre>
<p>@@ -390,6 +392,10 @@</p>
<pre>         zbuffer = kwargs.pop("zbuffer", None)
         if zbuffer is None:
zbuffer = np.ones((image.shape[0], image.shape[1]), "float64")</pre>
<p>+ +        image_used = np.zeros((image.shape[0], image.shape[1]), “int64”) +        mesh_lines = np.zeros((image.shape[0], image.shape[1]), “int64”) +</p>
<pre>         self.lens_type = kwargs.pop("lens_type", None)
         if self.lens_type == "plane-parallel":
self.extent_function = calculate_extent_plane_parallel</pre>
<p>@@ -397,7 +403,7 @@</p>
<pre>         else:
if not (vp_pos.shape[0] == vp_dir.shape[0] == image.shape[0]) or \
   not (vp_pos.shape[1] == vp_dir.shape[1] == image.shape[1]):</pre>
<ul><li><p>msg = “Bad lense shape / direction for %s\n” % (self.lens_type)</p></li></ul>
<p>+                msg = “Bad lens shape / direction for %s\n” % (self.lens_type)</p>
<pre>msg += "Shapes: (%s - %s - %s) and (%s - %s - %s)" % (
    vp_pos.shape[0], vp_dir.shape[0], image.shape[0],
    vp_pos.shape[1], vp_dir.shape[1], image.shape[1])</pre>
<p>@@ -423,7 +429,9 @@</p>
<pre>self.image.x_vec = <np.float64_t *> x_vec.data
self.ay_vec = y_vec
self.image.y_vec = <np.float64_t *> y_vec.data</pre>
<ul><li><p>self.image.zbuffer = zbuffer</p></li></ul>
<p>+        self.image.zbuffer = self.azbuffer = zbuffer +        self.image.image_used = self.aimage_used = image_used +        self.image.mesh_lines = self.amesh_lines = mesh_lines</p>
<pre>self.image.nv[0] = image.shape[0]
self.image.nv[1] = image.shape[1]
for i in range(4): self.image.bounds[i] = bounds[i]</pre>
<p>@@ -498,6 +506,7 @@</p>
<pre>self.image.vp_dir = None
self.image.zbuffer = None
self.image.camera_data = None</pre>
<p>+        self.image.image_used = None</p>
<pre>        free(self.image)

</pre>
<p>diff -r 672764585671c7d379c13c3537eebe2dde7dfcbe -r 040184c871c896fd1d2889c1fe193f79396620af yt/utilities/lib/mesh_traversal.pyx --- a/yt/utilities/lib/mesh_traversal.pyx +++ b/yt/utilities/lib/mesh_traversal.pyx @@ -25,7 +25,9 @@</p>
<pre>    ImageContainer
from cython.parallel import prange, parallel, threadid
from yt.visualization.image_writer import apply_colormap</pre>
<p>-from yt.utilities.lib.bounding_volume_hierarchy cimport BVH, Ray +from yt.utilities.lib.bounding_volume_hierarchy cimport BVH, Ray + +cdef np.float64_t INF = np.inf</p>
<pre>rtc.rtcInit(NULL)
rtc.rtcSetErrorFunction(error_printer)</pre>
<p>@@ -43,12 +45,9 @@</p>
<pre>    def __dealloc__(self):
        rtcs.rtcDeleteScene(self.scene_i)
</pre>
<p>+</p>
<pre>cdef class MeshSampler(ImageSampler):
</pre>
<ul><li><p>cdef public object image_used</p></li>
<li><p>cdef public object mesh_lines</p></li>
<li><p>cdef public object zbuffer</p></li></ul>
<p>–</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>@@ -71,15 +70,10 @@</p>
<pre>         cdef np.float64_t width[3]
         for i in range(3):
width[i] = self.width[i]</pre>
<ul><li><p>cdef np.ndarray[np.float64_t, ndim=1] data cdef np.ndarray[np.int64_t, ndim=1] used nx = im.nv[0] ny = im.nv[1] size = nx * ny</p></li>
<li><p>used = np.empty(size, dtype="int64")</p></li>
<li><p>mesh = np.empty(size, dtype="int64")</p></li>
<li><p>data = np.empty(size, dtype="float64")</p></li>
<li><p>zbuffer = np.empty(size, dtype="float64") cdef rtcr.RTCRay ray v_pos = <np.float64_t *> malloc(3 * sizeof(np.float64_t)) v_dir = <np.float64_t *> malloc(3 * sizeof(np.float64_t))</p></li></ul>
<p>@@ -100,24 +94,16 @@</p>
<pre>ray.time = 0
ray.Ng[0] = 1e37  # we use this to track the hit distance
rtcs.rtcIntersect(scene.scene_i, ray)</pre>
<ul><li><p>data[j] = ray.time</p></li>
<li><p>used[j] = ray.primID</p></li>
<li><p>mesh[j] = ray.instID</p></li>
<li><p>zbuffer[j] = ray.tfar</p></li>
<li><p>self.aimage = data</p></li>
<li><p>self.image_used = used</p></li>
<li><p>self.mesh_lines = mesh</p></li>
<li><p>self.zbuffer = zbuffer</p></li></ul>
<p>+            im.image[vi, vj, 0] = ray.time +            im.image_used[vi, vj] = ray.primID +            im.mesh_lines[vi, vj] = ray.instID +            im.zbuffer[vi, vj] = ray.tfar</p>
<pre>        free(v_pos)
        free(v_dir)


cdef class BVHMeshSampler(ImageSampler):
</pre>
<ul><li><p>cdef public object image_used</p></li>
<li><p>cdef public object mesh_lines</p></li>
<li><p>cdef public object zbuffer</p></li></ul>
<p>–</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>@@ -144,10 +130,6 @@</p>
<pre>nx = im.nv[0]
ny = im.nv[1]
size = nx * ny</pre>
<ul><li><p>used = np.empty(size, dtype="int64")</p></li>
<li><p>mesh = np.empty(size, dtype="int64")</p></li>
<li><p>data = np.empty(size, dtype="float64")</p></li>
<li><p>zbuffer = np.empty(size, dtype="float64") cdef Ray* ray with nogil, parallel(num_threads = num_threads):</p>
<pre>ray = <Ray *> malloc(sizeof(Ray))</pre></li></ul>
<p>@@ -162,19 +144,15 @@</p>
<pre>ray.origin[i] = v_pos[i]
ray.direction[i] = v_dir[i]
ray.inv_dir[i] = 1.0 / v_dir[i]</pre>
<ul><li><p>ray.t_far = np.inf</p></li></ul>
<p>+                ray.t_far = INF</p>
<pre>ray.t_near = 0.0
ray.data_val = 0
ray.elem_id = -1
bvh.intersect(ray)</pre>
<ul><li><p>data[j] = ray.data_val</p></li>
<li><p>used[j] = ray.elem_id</p></li>
<li><p>mesh[j] = ray.near_boundary</p></li>
<li><p>zbuffer[j] = ray.t_far</p></li>
<li><p>self.aimage = data</p></li>
<li><p>self.image_used = used</p></li>
<li><p>self.mesh_lines = mesh</p></li>
<li><p>self.zbuffer = zbuffer</p></li>
<li><p>free(v_pos)</p></li>
<li><p>free(v_dir)</p></li>
<li><p>free(ray)</p></li></ul>
<p>+                im.image[vi, vj, 0] = ray.data_val +                im.image_used[vi, vj] = ray.elem_id +                im.mesh_lines[vi, vj] = ray.near_boundary +                im.zbuffer[vi, vj] = ray.t_far +            free(v_pos) +            free(v_dir) +            free(ray)</p>
<p>diff -r 672764585671c7d379c13c3537eebe2dde7dfcbe -r 040184c871c896fd1d2889c1fe193f79396620af yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -502,11 +502,10 @@</p>
<pre>        mylog.debug("Done casting rays")

        self.finalize_image(camera)</pre>
<ul><li><p>self.data = self.sampler.aimage self.current_image = self.apply_colormap()</p>
<p>zbuffer += ZBuffer(self.current_image.astype('float64'),</p></li>
<li><p>self.sampler.zbuffer)</p></li></ul>
<p>+                           self.sampler.azbuffer)</p>
<pre>zbuffer.rgba = ImageArray(zbuffer.rgba)
self.zbuffer = zbuffer
self.current_image = self.zbuffer.rgba</pre>
<p>@@ -523,16 +522,13 @@</p>
<pre># reshape data
Nx = camera.resolution[0]
Ny = camera.resolution[1]</pre>
<ul><li><p>sam.aimage = sam.aimage.reshape(Nx, Ny)</p></li>
<li><p>sam.image_used = sam.image_used.reshape(Nx, Ny)</p></li>
<li><p>sam.mesh_lines = sam.mesh_lines.reshape(Nx, Ny)</p></li>
<li><p>sam.zbuffer = sam.zbuffer.reshape(Nx, Ny)</p></li></ul>
<p>+        self.data = sam.aimage[:,:,0].reshape(Nx, Ny)</p>
<pre># rotate</pre>
<ul><li><p>sam.aimage = np.rot90(sam.aimage, k=2)</p></li>
<li><p>sam.image_used = np.rot90(sam.image_used, k=2)</p></li>
<li><p>sam.mesh_lines = np.rot90(sam.mesh_lines, k=2)</p></li>
<li><p>sam.zbuffer = np.rot90(sam.zbuffer, k=2)</p></li></ul>
<p>+        self.data = np.rot90(self.data, k=2) +        sam.aimage_used = np.rot90(sam.aimage_used, k=2) +        sam.amesh_lines = np.rot90(sam.amesh_lines, k=2) +        sam.azbuffer = np.rot90(sam.azbuffer, k=2)</p>
<pre>def annotate_mesh_lines(self, color=None, alpha=1.0):
    r"""</pre>
<p>@@ -558,7 +554,7 @@</p>
<pre>        if color is None:
            color = np.array([0, 0, 0, alpha])
</pre>
<ul><li><p>locs = [self.sampler.mesh_lines == 1]</p></li></ul>
<p>+        locs = [self.sampler.amesh_lines == 1]</p>
<pre>self.current_image[:, :, 0][locs] = color[0]
self.current_image[:, :, 1][locs] = color[1]</pre>
<p>@@ -592,7 +588,7 @@</p>
<pre>color_bounds=self._color_bounds,
cmap_name=self._cmap)/255.
         alpha = image[:, :, 3]</pre>
<ul><li><p>alpha[self.sampler.image_used == -1] = 0.0</p></li></ul>
<p>+        alpha[self.sampler.aimage_used == -1] = 0.0</p>
<pre>        image[:, :, 3] = alpha
        return image
</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/c502208b18d1/">https://bitbucket.org/yt_analysis/yt/commits/c502208b18d1/</a> Changeset:   c502208b18d1 Branch:      yt User:        atmyers Date:        2016-04-03 23:09:52+00:00 Summary:     a couple of renamings to support switching between ray-tracing engines. Affected #:  3 files</p>
<p>diff -r 040184c871c896fd1d2889c1fe193f79396620af -r c502208b18d16b28d384f6c5ccd8ed68abc827ff yt/utilities/lib/mesh_traversal.pyx --- a/yt/utilities/lib/mesh_traversal.pyx +++ b/yt/utilities/lib/mesh_traversal.pyx @@ -1,6 +1,6 @@</p>
<pre>"""</pre>
<p>-This file contains the MeshSampler class, which handles casting rays at a -MeshSource using pyembree. +This file contains the MeshSampler classes, which handles casting rays at a +mesh source using either pyembree or the cython ray caster.</p>
<pre>"""</pre>
<p>@@ -46,7 +46,7 @@</p>
<pre>        rtcs.rtcDeleteScene(self.scene_i)

</pre>
<p>-cdef class MeshSampler(ImageSampler): +cdef class EmbreeMeshSampler(ImageSampler):</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>diff -r 040184c871c896fd1d2889c1fe193f79396620af -r c502208b18d16b28d384f6c5ccd8ed68abc827ff yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -369,7 +369,7 @@</p>
<pre>        assert(self.field is not None)
        assert(self.data_source is not None)
</pre>
<ul><li><p>self.scene = mesh_traversal.YTEmbreeScene()</p></li></ul>
<p>+        self.volume = mesh_traversal.YTEmbreeScene()</p>
<pre>        self.build_mesh()

    def cmap():</pre>
<p>@@ -438,7 +438,7 @@</p>
<pre># low-order geometry. Right now, high-order geometry is only
# implemented for 20-point hexes.
if indices.shape[1] == 20:</pre>
<ul><li><p>self.mesh = mesh_construction.QuadraticElementMesh(self.scene,</p></li></ul>
<p>+            self.mesh = mesh_construction.QuadraticElementMesh(self.volume,</p>
<pre>vertices,
indices,
field_data)</pre>
<p>@@ -458,7 +458,7 @@</p>
<pre>                field_data = field_data[:, 0:4]
                indices = indices[:, 0:4]
</pre>
<ul><li><p>self.mesh = mesh_construction.LinearElementMesh(self.scene,</p></li></ul>
<p>+            self.mesh = mesh_construction.LinearElementMesh(self.volume,</p>
<pre>vertices,
indices,
field_data)</pre>
<p>@@ -498,7 +498,7 @@</p>
<pre>        self.sampler = new_mesh_sampler(camera, self)

        mylog.debug("Casting rays")</pre>
<ul><li><p>self.sampler(self.scene)</p></li></ul>
<p>+        self.sampler(self.volume)</p>
<pre>        mylog.debug("Done casting rays")

        self.finalize_image(camera)</pre>
<p>diff -r 040184c871c896fd1d2889c1fe193f79396620af -r c502208b18d16b28d384f6c5ccd8ed68abc827ff yt/visualization/volume_rendering/utils.py --- a/yt/visualization/volume_rendering/utils.py +++ b/yt/visualization/volume_rendering/utils.py @@ -27,7 +27,7 @@</p>
<pre>    params['width'],
)
kwargs = {'lens_type': params['lens_type']}</pre>
<ul><li><p>sampler = mesh_traversal.MeshSampler(*args, **kwargs)</p></li></ul>
<p>+    sampler = mesh_traversal.EmbreeMeshSampler(*args, **kwargs)</p>
<pre>    return sampler

</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/1a8309856c3e/">https://bitbucket.org/yt_analysis/yt/commits/1a8309856c3e/</a> Changeset:   1a8309856c3e Branch:      yt User:        atmyers Date:        2016-04-03 23:42:20+00:00 Summary:     enable MeshSources to optionally use the cython ray-tracer. Affected #:  2 files</p>
<p>diff -r c502208b18d16b28d384f6c5ccd8ed68abc827ff -r 1a8309856c3ec60aa3bed1cf4c07c000cafeb62a yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -24,6 +24,7 @@</p>
<pre>from .utils import new_volume_render_sampler, data_source_or_all, \
    get_corners, new_projection_sampler, new_mesh_sampler, \
    new_interpolated_projection_sampler</pre>
<p>+from yt.utilities.lib.bounding_volume_hierarchy import BVH</p>
<pre>from yt.visualization.image_writer import apply_colormap
from yt.data_objects.image_array import ImageArray
from .zbuffer_array import ZBuffer</pre>
<p>@@ -353,8 +354,9 @@</p>
<pre>self.data_source = data_source_or_all(data_source)
field = self.data_source._determine_fields(field)[0]
self.field = field</pre>
<ul><li><p>self.mesh = None</p></li></ul>
<p>+        self.volume = None</p>
<pre>self.current_image = None</pre>
<p>+        self.engine = ‘engine’</p>
<pre># default color map
self._cmap = ytcfg.get("yt", "default_colormap")</pre>
<p>@@ -369,8 +371,12 @@</p>
<pre>        assert(self.field is not None)
        assert(self.data_source is not None)
</pre>
<ul><li><p>self.volume = mesh_traversal.YTEmbreeScene()</p></li>
<li><p>self.build_mesh()</p></li></ul>
<p>+        if self.engine == ‘embree’: +            self.volume = mesh_traversal.YTEmbreeScene() +            self.build_volume_embree() + +        elif self.engine == ‘bvh’: +            self.build_volume_bvh()</p>
<pre>def cmap():
    '''</pre>
<p>@@ -410,15 +416,15 @@</p>
<pre>def _validate(self):
    """Make sure that all dependencies have been met"""
    if self.data_source is None:</pre>
<ul><li><p>raise RuntimeError("Data source not initialized")</p></li></ul>
<p>+            raise RuntimeError("Data source not initialized.")</p>
<ul><li><p>if self.mesh is None:</p></li>
<li><p>raise RuntimeError("Mesh not initialized")</p></li></ul>
<p>+        if self.volume is None: +            raise RuntimeError("Volume not initialized.")</p>
<ul><li><p>def build_mesh(self):</p></li></ul>
<p>+    def build_volume_embree(self):</p>
<pre>        """
</pre>
<ul><li><p>This constructs the mesh that will be ray-traced.</p></li></ul>
<p>+        This constructs the mesh that will be ray-traced by pyembree.</p>
<pre>"""
ftype, fname = self.field</pre>
<p>@@ -463,6 +469,49 @@</p>
<pre>                                                            indices,
                                                            field_data)
</pre>
<p>+    def build_volume_bvh(self): +        """ + +        This constructs the mesh that will be ray-traced. + +        """ +        ftype, fname = self.field +        mesh_id = int(ftype[-1]) – 1 +        index = self.data_source.ds.index +        offset = index.meshes[mesh_id]._index_offset +        field_data = self.data_source[self.field].d  # strip units + +        vertices = index.meshes[mesh_id].connectivity_coords +        indices = index.meshes[mesh_id].connectivity_indices – offset + +        if len(field_data.shape) == 1: +            raise NotImplementedError("Element-centered fields are " +                                      “only supported by Embree. “) + +        # Here, we decide whether to render based on high-order or +        # low-order geometry. Right now, high-order geometry is only +        # supported by Embree. +        if indices.shape[1] == 20: +            # hexahedral +            mylog.warning("20-node hexes not yet supported, " + +                          “dropping to 1st order.”) +            field_data = field_data[:, 0:8] +            indices = indices[:, 0:8] +        elif indices.shape[1] == 27: +            # hexahedral +            mylog.warning("27-node hexes not yet supported, " + +                          "dropping to 1st order.”) +            field_data = field_data[:, 0:8] +            indices = indices[:, 0:8] +        elif indices.shape[1] == 10: +            # tetrahedral +            mylog.warning("10-node tetrahedral elements not yet supported, " + +                          "dropping to 1st order.”) +            field_data = field_data[:, 0:4] +            indices = indices[:, 0:4] + +        self.volume = BVH(vertices, indices, field_data) +</p>
<pre>    def render(self, camera, zbuffer=None):
        """Renders an image using the provided camera
</pre>
<p>@@ -495,7 +544,7 @@</p>
<pre>                              zbuffer.z.reshape(shape[:2]))
        self.zbuffer = zbuffer
</pre>
<ul><li><p>self.sampler = new_mesh_sampler(camera, self)</p></li></ul>
<p>+        self.sampler = new_mesh_sampler(camera, self, engine=self.engine)</p>
<pre>mylog.debug("Casting rays")
self.sampler(self.volume)</pre>
<p>diff -r c502208b18d16b28d384f6c5ccd8ed68abc827ff -r 1a8309856c3ec60aa3bed1cf4c07c000cafeb62a yt/visualization/volume_rendering/utils.py --- a/yt/visualization/volume_rendering/utils.py +++ b/yt/visualization/volume_rendering/utils.py @@ -14,7 +14,7 @@</p>
<pre>    return data_source

</pre>
<p>-def new_mesh_sampler(camera, render_source): +def new_mesh_sampler(camera, render_source, engine):</p>
<pre>params = ensure_code_unit_params(camera._get_sampler_params(render_source))
args = (
    np.atleast_3d(params['vp_pos']),</pre>
<p>@@ -27,7 +27,10 @@</p>
<pre>    params['width'],
)
kwargs = {'lens_type': params['lens_type']}</pre>
<ul><li><p>sampler = mesh_traversal.EmbreeMeshSampler(*args, **kwargs)</p></li></ul>
<p>+    if engine == ‘embree’: +        sampler = mesh_traversal.EmbreeMeshSampler(*args, **kwargs) +    elif engine == ‘bvh’: +        sampler = mesh_traversal.BVHMeshSampler(*args, **kwargs)</p>
<pre>    return sampler

</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/788526b95863/">https://bitbucket.org/yt_analysis/yt/commits/788526b95863/</a> Changeset:   788526b95863 Branch:      yt User:        atmyers Date:        2016-04-03 23:53:57+00:00 Summary:     typo fix Affected #:  1 file</p>
<p>diff -r 1a8309856c3ec60aa3bed1cf4c07c000cafeb62a -r 788526b95863868c9372f1964209c09001cc008e yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -356,7 +356,7 @@</p>
<pre>self.field = field
self.volume = None
self.current_image = None</pre>
<ul><li><p>self.engine = ‘engine’</p></li></ul>
<p>+        self.engine = ‘embree’</p>
<pre># default color map
self._cmap = ytcfg.get("yt", "default_colormap")</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/52262cbdce67/">https://bitbucket.org/yt_analysis/yt/commits/52262cbdce67/</a> Changeset:   52262cbdce67 Branch:      yt User:        atmyers Date:        2016-04-04 07:11:56+00:00 Summary:     make sure we free allocated memory in pixelization routines. Affected #:  1 file</p>
<p>diff -r 788526b95863868c9372f1964209c09001cc008e -r 52262cbdce67159a84284c2bf8a820b3167cea94 yt/utilities/lib/pixelization_routines.pyx --- a/yt/utilities/lib/pixelization_routines.pyx +++ b/yt/utilities/lib/pixelization_routines.pyx @@ -20,6 +20,7 @@</p>
<pre>from yt.utilities.lib.fp_utils cimport fmin, fmax, i64min, i64max, imin, imax, fabs
from yt.utilities.exceptions import YTPixelizeError, \
    YTElementTypeNotRecognized</pre>
<p>+from libc.stdlib cimport malloc, free</p>
<pre>from yt.utilities.lib.element_mappings cimport \
    ElementSampler, \
    P1Sampler3D, \</pre>
<p>@@ -29,9 +30,6 @@</p>
<pre>    Q1Sampler2D, \
    W1Sampler3D
</pre>
<p>-cdef extern from “stdlib.h”:</p>
<ul><li><p># NOTE that size_t might not be int</p></li>
<li><p>void *alloca(int)</p></li></ul>
<pre>cdef extern from "pixelization_constants.h":
    enum:</pre>
<p>@@ -578,8 +576,7 @@</p>
<pre>cdef int nvertices = conn.shape[1]
cdef int ndim = coords.shape[1]
cdef int num_field_vals = field.shape[1]</pre>
<ul><li><p>cdef double* mapped_coord</p></li>
<li><p>cdef int num_mapped_coords</p></li></ul>
<p>+    cdef double[4] mapped_coord</p>
<pre>    cdef ElementSampler sampler

    # Pick the right sampler and allocate storage for the mapped coordinate</pre>
<p>@@ -622,10 +619,8 @@</p>
<pre>        raise RuntimeError

    # allocate temporary storage</pre>
<ul><li><p>num_mapped_coords = sampler.num_mapped_coords</p></li>
<li><p>mapped_coord = <double*> alloca(sizeof(double) * num_mapped_coords)</p></li>
<li><p>vertices = <np.float64_t *> alloca(ndim * sizeof(np.float64_t) * nvertices)</p></li>
<li><p>field_vals = <np.float64_t *> alloca(sizeof(np.float64_t) * num_field_vals)</p></li></ul>
<p>+    vertices = <np.float64_t *> malloc(ndim * sizeof(np.float64_t) * nvertices) +    field_vals = <np.float64_t *> malloc(sizeof(np.float64_t) * num_field_vals)</p>
<pre># fill the image bounds and pixel size informaton here
for i in range(ndim):</pre>
<p>@@ -696,4 +691,7 @@</p>
<pre>    img[pi, pj, pk] = 1.0
elif sampler.check_near_edge(mapped_coord, thresh, yax):
    img[pi, pj, pk] = 1.0</pre>
<p>+ +    free(vertices) +    free(field_vals)</p>
<pre>return img</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/99d790ed1760/">https://bitbucket.org/yt_analysis/yt/commits/99d790ed1760/</a> Changeset:   99d790ed1760 Branch:      yt User:        atmyers Date:        2016-04-04 07:12:26+00:00 Summary:     refactoring so that we can annotate mesh lines using both engines. Affected #:  5 files</p>
<p>diff -r 52262cbdce67159a84284c2bf8a820b3167cea94 -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -246,11 +246,13 @@</p>
<pre>cdef np.float64_t* field_ptr
vertex_ptr = self.vertices + ray.elem_id*self.num_verts_per_elem*3
field_ptr = self.field_data + ray.elem_id*self.num_verts_per_elem</pre>
<ul><li><p>ray.data_val = self.sampler.sample_at_real_point(vertex_ptr,</p></li>
<li><p>field_ptr,</p></li>
<li><p>position)</p></li>
<li><p>ray.near_boundary = -1</p></li></ul>
<p>+        cdef np.float64_t[4] mapped_coord +        self.sampler.map_real_to_unit(mapped_coord, vertex_ptr, position) +        ray.data_val = self.sampler.sample_at_unit_point(mapped_coord, +                                                         field_ptr) + +        ray.near_boundary = self.sampler.check_mesh_lines(mapped_coord)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>diff -r 52262cbdce67159a84284c2bf8a820b3167cea94 -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 yt/utilities/lib/element_mappings.pxd --- a/yt/utilities/lib/element_mappings.pxd +++ b/yt/utilities/lib/element_mappings.pxd @@ -35,6 +35,8 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil +</p>
<pre>cdef class P1Sampler2D(ElementSampler):
</pre>
<p>@@ -75,6 +77,8 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil +</p>
<pre># This typedef defines a function pointer that defines the system
# of equations that will be solved by the NonlinearSolveSamplers.</pre>
<p>@@ -170,6 +174,8 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil +</p>
<pre>cdef class W1Sampler3D(NonlinearSolveSampler3D):
</pre>
<p>@@ -190,6 +196,9 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil + +</p>
<pre>cdef class S2Sampler3D(NonlinearSolveSampler3D):
</pre>
<p>@@ -210,6 +219,9 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil + +</p>
<pre>cdef class NonlinearSolveSampler2D(ElementSampler):
</pre>
<p>diff -r 52262cbdce67159a84284c2bf8a820b3167cea94 -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 yt/utilities/lib/element_mappings.pyx --- a/yt/utilities/lib/element_mappings.pyx +++ b/yt/utilities/lib/element_mappings.pyx @@ -93,6 +93,12 @@</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        pass + +    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True)</p>
<pre>     cdef double sample_at_real_point(self,
double* vertices,
double* field_values,</pre>
<p>@@ -263,6 +269,11 @@</p>
<pre>            return 1
        return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        pass</p>
<pre>cdef class NonlinearSolveSampler3D(ElementSampler):
</pre>
<p>@@ -371,7 +382,6 @@</p>
<pre>            return 0
        return 1
</pre>
<p>–</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>@@ -384,6 +394,23 @@</p>
<pre>        else:
            return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +            fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        else: +            return -1 + +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -526,6 +553,22 @@</p>
<pre>        else:
            return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +            fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        else: +            return -1 +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -707,7 +750,6 @@</p>
<pre>            return 0
        return 1
</pre>
<p>–</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>@@ -724,6 +766,32 @@</p>
<pre>            return 1
        return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        cdef double r, s, t +        cdef double thresh = 5.0e-2 +        r = mapped_coord[0] +        s = mapped_coord[1] +        t = mapped_coord[2] + +        cdef int near_edge_r, near_edge_s, near_edge_t +        near_edge_r = (r < thresh) or (fabs(r + s – 1.0) < thresh) +        near_edge_s = (s < thresh) +        near_edge_t = fabs(fabs(mapped_coord[2]) – 1.0) < thresh + +        # we use ray.instID to pass back whether the ray is near the +        # element boundary or not (used to annotate mesh lines) +        if (near_edge_r and near_edge_s): +            return 1 +        elif (near_edge_r and near_edge_t): +            return 1 +        elif (near_edge_s and near_edge_t): +            return 1 +        else: +            return -1 +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>diff -r 52262cbdce67159a84284c2bf8a820b3167cea94 -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 yt/utilities/lib/mesh_samplers.pyx --- a/yt/utilities/lib/mesh_samplers.pyx +++ b/yt/utilities/lib/mesh_samplers.pyx @@ -112,17 +112,8 @@</p>
<pre># we use ray.instID to pass back whether the ray is near the
# element boundary or not (used to annotate mesh lines)</pre>
<ul><li><p>if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>+    ray.instID = Q1Sampler.check_mesh_lines(mapped_coord) +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -165,28 +156,7 @@</p>
<pre>    val = W1Sampler.sample_at_unit_point(mapped_coord, field_data)
    ray.time = val
</pre>
<ul><li><p>cdef double r, s, t</p></li>
<li><p>cdef double thresh = 5.0e-2</p></li>
<li><p>r = mapped_coord[0]</p></li>
<li><p>s = mapped_coord[1]</p></li>
<li><p>t = mapped_coord[2]</p></li></ul>
<p>–</p>
<ul><li><p>cdef int near_edge_r, near_edge_s, near_edge_t</p></li>
<li><p>near_edge_r = (r < thresh) or (fabs(r + s – 1.0) < thresh)</p></li>
<li><p>near_edge_s = (s < thresh)</p></li>
<li><p>near_edge_t = fabs(fabs(mapped_coord[2]) – 1.0) < thresh</p></li></ul>
<p>–</p>
<ul><li><p># we use ray.instID to pass back whether the ray is near the</p></li>
<li><p># element boundary or not (used to annotate mesh lines)</p></li>
<li><p>if (near_edge_r and near_edge_s):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (near_edge_r and near_edge_t):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (near_edge_s and near_edge_t):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>– +    ray.instID = W1Sampler.check_mesh_lines(mapped_coord)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -223,20 +193,8 @@</p>
<pre>    val = S2Sampler.sample_at_unit_point(mapped_coord, patch.field_data)
    ray.time = val
</pre>
<ul><li><p># we use ray.instID to pass back whether the ray is near the</p></li>
<li><p># element boundary or not (used to annotate mesh lines)</p></li>
<li><p>if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>– +    ray.instID = S2Sampler.check_mesh_lines(mapped_coord) +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>diff -r 52262cbdce67159a84284c2bf8a820b3167cea94 -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 yt/utilities/lib/mesh_traversal.pyx --- a/yt/utilities/lib/mesh_traversal.pyx +++ b/yt/utilities/lib/mesh_traversal.pyx @@ -131,7 +131,7 @@</p>
<pre>ny = im.nv[1]
size = nx * ny
cdef Ray* ray</pre>
<ul><li><p>with nogil, parallel(num_threads = num_threads):</p></li></ul>
<p>+        with nogil, parallel():</p>
<pre>ray = <Ray *> malloc(sizeof(Ray))
v_pos = <np.float64_t *> malloc(3 * sizeof(np.float64_t))
v_dir = <np.float64_t *> malloc(3 * sizeof(np.float64_t))</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/b168bb218f14/">https://bitbucket.org/yt_analysis/yt/commits/b168bb218f14/</a> Changeset:   b168bb218f14 Branch:      yt User:        atmyers Date:        2016-04-04 17:33:50+00:00 Summary:     more refactoring. Affected #:  2 files</p>
<p>diff -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 -r b168bb218f14615792c2d8e1a453963d1d7fc488 yt/utilities/lib/element_mappings.pyx --- a/yt/utilities/lib/element_mappings.pyx +++ b/yt/utilities/lib/element_mappings.pyx @@ -273,7 +273,33 @@</p>
<pre>@cython.wraparound(False)
@cython.cdivision(True)
cdef int check_mesh_lines(self, double* mapped_coord) nogil:</pre>
<ul><li><p>pass</p></li></ul>
<p>+        cdef double u, v, w +        cdef double thresh = 2.0e-2 +        if mapped_coord[0] == 0: +            u = mapped_coord[1] +            v = mapped_coord[2] +            w = mapped_coord[3] +        elif mapped_coord[1] == 0: +            u = mapped_coord[2] +            v = mapped_coord[3] +            w = mapped_coord[0] +        elif mapped_coord[2] == 0: +            u = mapped_coord[1] +            v = mapped_coord[3] +            w = mapped_coord[0] +        else: +            u = mapped_coord[1] +            v = mapped_coord[2] +            w = mapped_coord[0] +        if ((u < thresh) or +            (v < thresh) or +            (w < thresh) or +            (fabs(u – 1) < thresh) or +            (fabs(v – 1) < thresh) or +            (fabs(w – 1) < thresh)): +            return 1 +        return -1 +</p>
<pre>cdef class NonlinearSolveSampler3D(ElementSampler):
</pre>
<p>diff -r 99d790ed1760c0529a7e26d4c66918f5849c4a16 -r b168bb218f14615792c2d8e1a453963d1d7fc488 yt/utilities/lib/mesh_samplers.pyx --- a/yt/utilities/lib/mesh_samplers.pyx +++ b/yt/utilities/lib/mesh_samplers.pyx @@ -235,23 +235,8 @@</p>
<pre>P1Sampler.map_real_to_unit(mapped_coord, vertices, position)
val = P1Sampler.sample_at_unit_point(mapped_coord, field_data)
ray.time = val</pre>
<p>–</p>
<ul><li><p>cdef double u, v, w</p></li>
<li><p>cdef double thresh = 2.0e-2</p></li>
<li><p>u = ray.u</p></li>
<li><p>v = ray.v</p></li>
<li><p>w = 1.0 – u – v</p></li>
<li><p># we use ray.instID to pass back whether the ray is near the</p></li>
<li><p># element boundary or not (used to annotate mesh lines)</p></li>
<li><p>if ((u < thresh) or</p></li>
<li><p>(v < thresh) or</p></li>
<li><p>(w < thresh) or</p></li>
<li><p>(fabs(u – 1) < thresh) or</p></li>
<li><p>(fabs(v – 1) < thresh) or</p></li>
<li><p>(fabs(w – 1) < thresh)):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>+ +    ray.instID = P1Sampler.check_mesh_lines(mapped_coord)</p>
<pre>@cython.boundscheck(False)</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/d3f8e67fd6a5/">https://bitbucket.org/yt_analysis/yt/commits/d3f8e67fd6a5/</a> Changeset:   d3f8e67fd6a5 Branch:      yt User:        atmyers Date:        2016-04-04 17:35:33+00:00 Summary:     raise Exception if invalid ray-tracing engine is selected. Affected #:  1 file</p>
<p>diff -r b168bb218f14615792c2d8e1a453963d1d7fc488 -r d3f8e67fd6a53f938e93332c72e1df4cd21efef2 yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -374,9 +374,11 @@</p>
<pre>         if self.engine == 'embree':
self.volume = mesh_traversal.YTEmbreeScene()
self.build_volume_embree()</pre>
<p>–</p>
<pre>         elif self.engine == 'bvh':
self.build_volume_bvh()</pre>
<p>+        else: +            raise NotImplementedError("Invalid ray-tracing engine selected. " +                                      “Choices are ‘embree’ and 'bvh'.”)</p>
<pre>def cmap():
    '''</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/30fedffbd142/">https://bitbucket.org/yt_analysis/yt/commits/30fedffbd142/</a> Changeset:   30fedffbd142 Branch:      yt User:        atmyers Date:        2016-04-04 18:32:15+00:00 Summary:     enable element-centered fields to work with BVH. Affected #:  3 files</p>
<p>diff -r d3f8e67fd6a53f938e93332c72e1df4cd21efef2 -r 30fedffbd142e6384222af1d224f059512a443e8 yt/utilities/lib/bounding_volume_hierarchy.pxd --- a/yt/utilities/lib/bounding_volume_hierarchy.pxd +++ b/yt/utilities/lib/bounding_volume_hierarchy.pxd @@ -45,6 +45,7 @@</p>
<pre>cdef np.int64_t num_tri
cdef np.int64_t num_elem
cdef np.int64_t num_verts_per_elem</pre>
<p>+    cdef np.int64_t num_field_per_elem</p>
<pre>     cdef ElementSampler sampler
     cdef np.int64_t _partition(self, np.int64_t begin, np.int64_t end,
np.int64_t ax, np.float64_t split) nogil</pre>
<p>diff -r d3f8e67fd6a53f938e93332c72e1df4cd21efef2 -r 30fedffbd142e6384222af1d224f059512a443e8 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -124,6 +124,7 @@</p>
<pre>self.num_elem = indices.shape[0]
self.num_verts_per_elem = indices.shape[1]</pre>
<p>+        self.num_field_per_elem = field_data.shape[1]</p>
<pre># We need to figure out what kind of elements we've been handed.
cdef int[MAX_NUM_TRI][3] tri_array</pre>
<p>@@ -142,20 +143,22 @@</p>
<pre>        self.num_tri = self.num_tri_per_elem*self.num_elem

        # allocate storage</pre>
<ul><li><p>cdef np.int64_t size = self.num_verts_per_elem * self.num_elem</p></li>
<li><p>self.vertices = <np.float64_t*> malloc(size * 3 * sizeof(np.float64_t))</p></li>
<li><p>self.field_data = <np.float64_t*> malloc(size * sizeof(np.float64_t))</p></li></ul>
<p>+        cdef np.int64_t v_size = self.num_verts_per_elem * self.num_elem * 3 +        self.vertices = <np.float64_t*> malloc(v_size * sizeof(np.float64_t)) +        cdef np.int64_t f_size = self.num_field_per_elem * self.num_elem +        self.field_data = <np.float64_t*> malloc(f_size * sizeof(np.float64_t))</p>
<pre># create data buffers
cdef np.int64_t i, j, k
cdef np.int64_t field_offset, vertex_offset
for i in range(self.num_elem):</pre>
<ul><li><p>field_offset = i*self.num_verts_per_elem for j in range(self.num_verts_per_elem):</p>
<pre>vertex_offset = i*self.num_verts_per_elem*3 + j*3</pre></li>
<li><p>self.field_data[field_offset + j] = field_data[i][j] for k in range(3):</p>
<pre>self.vertices[vertex_offset + k] = vertices[indices[i,j]][k]</pre></li></ul>
<p>+            field_offset = i*self.num_field_per_elem +            for j in range(self.num_field_per_elem): +                self.field_data[field_offset + j] = field_data[i][j]</p>
<pre># fill our array of triangles
cdef np.int64_t offset, tri_index</pre>
<p>@@ -245,13 +248,15 @@</p>
<pre>cdef np.float64_t* vertex_ptr
cdef np.float64_t* field_ptr
vertex_ptr = self.vertices + ray.elem_id*self.num_verts_per_elem*3</pre>
<ul><li><p>field_ptr = self.field_data + ray.elem_id*self.num_verts_per_elem</p></li></ul>
<p>+        field_ptr = self.field_data + ray.elem_id*self.num_field_per_elem</p>
<pre>cdef np.float64_t[4] mapped_coord
self.sampler.map_real_to_unit(mapped_coord, vertex_ptr, position)</pre>
<ul><li><p>ray.data_val = self.sampler.sample_at_unit_point(mapped_coord,</p></li>
<li><p>field_ptr)</p></li></ul>
<p>– +        if self.num_field_per_elem == 1: +            ray.data_val = field_ptr[0] +        else: +            ray.data_val = self.sampler.sample_at_unit_point(mapped_coord, +                                                             field_ptr)</p>
<pre>        ray.near_boundary = self.sampler.check_mesh_lines(mapped_coord)

    @cython.boundscheck(False)</pre>
<p>diff -r d3f8e67fd6a53f938e93332c72e1df4cd21efef2 -r 30fedffbd142e6384222af1d224f059512a443e8 yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -486,9 +486,9 @@</p>
<pre>        vertices = index.meshes[mesh_id].connectivity_coords
        indices = index.meshes[mesh_id].connectivity_indices - offset
</pre>
<p>+        # if this is an element field, promote to 2D here</p>
<pre>if len(field_data.shape) == 1:</pre>
<ul><li><p>raise NotImplementedError("Element-centered fields are "</p></li>
<li><p>"only supported by Embree. ")</p></li></ul>
<p>+            field_data = np.expand_dims(field_data, 1)</p>
<pre># Here, we decide whether to render based on high-order or
# low-order geometry. Right now, high-order geometry is only</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/628471eb2d03/">https://bitbucket.org/yt_analysis/yt/commits/628471eb2d03/</a> Changeset:   628471eb2d03 Branch:      yt User:        atmyers Date:        2016-04-04 20:05:48+00:00 Summary:     use the same initial ‘far away’ distance for both BVH and Embree. Affected #:  1 file</p>
<p>diff -r 30fedffbd142e6384222af1d224f059512a443e8 -r 628471eb2d03f68de22e1ba8fae1ff5a992035e0 yt/utilities/lib/mesh_traversal.pyx --- a/yt/utilities/lib/mesh_traversal.pyx +++ b/yt/utilities/lib/mesh_traversal.pyx @@ -27,8 +27,6 @@</p>
<pre>from yt.visualization.image_writer import apply_colormap
from yt.utilities.lib.bounding_volume_hierarchy cimport BVH, Ray
</pre>
<p>-cdef np.float64_t INF = np.inf –</p>
<pre>rtc.rtcInit(NULL)
rtc.rtcSetErrorFunction(error_printer)
</pre>
<p>@@ -144,7 +142,7 @@</p>
<pre>ray.origin[i] = v_pos[i]
ray.direction[i] = v_dir[i]
ray.inv_dir[i] = 1.0 / v_dir[i]</pre>
<ul><li><p>ray.t_far = INF</p></li></ul>
<p>+                ray.t_far = 1e37</p>
<pre>ray.t_near = 0.0
ray.data_val = 0
ray.elem_id = -1</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/71eeada8e267/">https://bitbucket.org/yt_analysis/yt/commits/71eeada8e267/</a> Changeset:   71eeada8e267 Branch:      yt User:        atmyers Date:        2016-04-04 22:52:21+00:00 Summary:     Allow mesh line annotation to work with element-centered fields in Embree mode. Affected #:  4 files</p>
<p>diff -r 628471eb2d03f68de22e1ba8fae1ff5a992035e0 -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 yt/utilities/lib/mesh_construction.pxd --- a/yt/utilities/lib/mesh_construction.pxd +++ b/yt/utilities/lib/mesh_construction.pxd @@ -11,6 +11,7 @@</p>
<pre>int* element_indices   # which vertices belong to which *element*
int tpe                # the number of triangles per element
int vpe                # the number of vertices per element</pre>
<p>+    int fpe                # the number of field values per element</p>
<pre>ctypedef struct Patch:
    float[8][3] v</pre>
<p>diff -r 628471eb2d03f68de22e1ba8fae1ff5a992035e0 -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 yt/utilities/lib/mesh_construction.pyx --- a/yt/utilities/lib/mesh_construction.pyx +++ b/yt/utilities/lib/mesh_construction.pyx @@ -25,7 +25,6 @@</p>
<pre>from mesh_samplers cimport \
    sample_hex, \
    sample_tetra, \</pre>
<ul><li><p>sample_element, \ sample_wedge</p></li></ul>
<pre>from pyembree.rtcore cimport \
    Vertex, \</pre>
<p>@@ -186,19 +185,18 @@</p>
<pre>datac.element_indices = self.element_indices
datac.tpe = self.tpe
datac.vpe = self.vpe</pre>
<p>+        datac.fpe = self.fpe</p>
<pre>        self.datac = datac
        
        rtcg.rtcSetUserData(scene.scene_i, self.mesh, &self.datac)

    cdef void _set_sampler_type(self, YTEmbreeScene scene):
</pre>
<ul><li><p>if self.fpe == 1:</p></li>
<li><p>self.filter_func = <rtcg.RTCFilterFunc> sample_element</p></li>
<li><p>elif self.fpe == 4:</p></li></ul>
<p>+        if self.vpe == 4:</p>
<pre>self.filter_func = <rtcg.RTCFilterFunc> sample_tetra</pre>
<ul><li><p>elif self.fpe == 6:</p></li></ul>
<p>+        elif self.vpe == 6:</p>
<pre>self.filter_func = <rtcg.RTCFilterFunc> sample_wedge</pre>
<ul><li><p>elif self.fpe == 8:</p></li></ul>
<p>+        elif self.vpe == 8:</p>
<pre>self.filter_func = <rtcg.RTCFilterFunc> sample_hex
         else:
raise NotImplementedError("Sampler type not implemented.")</pre>
<p>diff -r 628471eb2d03f68de22e1ba8fae1ff5a992035e0 -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 yt/utilities/lib/mesh_samplers.pxd --- a/yt/utilities/lib/mesh_samplers.pxd +++ b/yt/utilities/lib/mesh_samplers.pxd @@ -13,6 +13,3 @@</p>
<pre>cdef void sample_hex20(void* userPtr,
                       rtcr.RTCRay& ray) nogil</pre>
<p>– -cdef void sample_element(void* userPtr,</p>
<ul><li><p>rtcr.RTCRay& ray) nogil</p></li></ul>
<p>diff -r 628471eb2d03f68de22e1ba8fae1ff5a992035e0 -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 yt/utilities/lib/mesh_samplers.pyx --- a/yt/utilities/lib/mesh_samplers.pyx +++ b/yt/utilities/lib/mesh_samplers.pyx @@ -97,7 +97,9 @@</p>
<pre>for i in range(8):
    element_indices[i] = data.element_indices[elem_id*8+i]</pre>
<ul><li><p>field_data[i]      = data.field_data[elem_id*8+i]</p></li></ul>
<p>+ +    for i in range(data.fpe): +        field_data[i] = data.field_data[elem_id*data.fpe+i]</p>
<pre>for i in range(8):
    vertices[i*3]     = data.vertices[element_indices[i]].x</pre>
<p>@@ -107,7 +109,10 @@</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[3]
Q1Sampler.map_real_to_unit(mapped_coord, vertices, position)</pre>
<ul><li><p>val = Q1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    if data.fpe == 1: +        val = field_data[0] +    else: +        val = Q1Sampler.sample_at_unit_point(mapped_coord, field_data)</p>
<pre>    ray.time = val

    # we use ray.instID to pass back whether the ray is near the</pre>
<p>@@ -143,7 +148,9 @@</p>
<pre>for i in range(6):
    element_indices[i] = data.element_indices[elem_id*6+i]</pre>
<ul><li><p>field_data[i]      = data.field_data[elem_id*6+i]</p></li></ul>
<p>+ +    for i in range(data.fpe): +        field_data[i] = data.field_data[elem_id*data.fpe+i]</p>
<pre>for i in range(6):
    vertices[i*3]     = data.vertices[element_indices[i]].x</pre>
<p>@@ -153,9 +160,11 @@</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[3]
W1Sampler.map_real_to_unit(mapped_coord, vertices, position)</pre>
<ul><li><p>val = W1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    if data.fpe == 1: +        val = field_data[0] +    else: +        val = W1Sampler.sample_at_unit_point(mapped_coord, field_data)</p>
<pre>ray.time = val</pre>
<p>–</p>
<pre>    ray.instID = W1Sampler.check_mesh_lines(mapped_coord)

@cython.boundscheck(False)</pre>
<p>@@ -192,7 +201,6 @@</p>
<pre>S2Sampler.map_real_to_unit(mapped_coord, patch.vertices, position)
val = S2Sampler.sample_at_unit_point(mapped_coord, patch.field_data)
ray.time = val</pre>
<p>–</p>
<pre>    ray.instID = S2Sampler.check_mesh_lines(mapped_coord)
    
</pre>
<p>@@ -225,39 +233,19 @@</p>
<pre>for i in range(4):
    element_indices[i] = data.element_indices[elem_id*4+i]</pre>
<ul><li><p>field_data[i] = data.field_data[elem_id*4+i] vertices[i*3] = data.vertices[element_indices[i]].x vertices[i*3 + 1] = data.vertices[element_indices[i]].y vertices[i*3 + 2] = data.vertices[element_indices[i]].z</p></li></ul>
<p>+    for i in range(data.fpe): +        field_data[i] = data.field_data[elem_id*data.fpe+i] +</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[4]
P1Sampler.map_real_to_unit(mapped_coord, vertices, position)</pre>
<ul><li><p>val = P1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    if data.fpe == 1: +        val = field_data[0] +    else: +        val = P1Sampler.sample_at_unit_point(mapped_coord, field_data)</p>
<pre>ray.time = val</pre>
<p>–</p>
<pre>ray.instID = P1Sampler.check_mesh_lines(mapped_coord)</pre>
<p>– – -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.cdivision(True) -cdef void sample_element(void* userPtr,</p>
<ul><li><p>rtcr.RTCRay& ray) nogil:</p></li>
<li><p>cdef int ray_id, elem_id</p></li>
<li><p>cdef double val</p></li>
<li><p>cdef MeshDataContainer* data</p></li></ul>
<p>–</p>
<ul><li><p>data = <MeshDataContainer*> userPtr</p></li>
<li><p>ray_id = ray.primID</p></li>
<li><p>if ray_id == -1:</p></li>
<li><p>return</p></li></ul>
<p>–</p>
<ul><li><p># ray_id records the id number of the hit according to</p></li>
<li><p># embree, in which the primitives are triangles. Here,</p></li>
<li><p># we convert this to the element id by dividing by the</p></li>
<li><p># number of triangles per element.</p></li>
<li><p>elem_id = ray_id / data.tpe</p></li></ul>
<p>–</p>
<ul><li><p>val = data.field_data[elem_id]</p></li>
<li><p>ray.time = val</p></li></ul>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/5ada8f62d1d6/">https://bitbucket.org/yt_analysis/yt/commits/5ada8f62d1d6/</a> Changeset:   5ada8f62d1d6 Branch:      yt User:        atmyers Date:        2016-04-07 01:44:07+00:00 Summary:     merging with tip Affected #:  25 files</p>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 doc/source/analyzing/analysis_modules/absorption_spectrum.rst --- a/doc/source/analyzing/analysis_modules/absorption_spectrum.rst +++ b/doc/source/analyzing/analysis_modules/absorption_spectrum.rst @@ -1,48 +1,91 @@</p>
<pre>.. _absorption_spectrum:
</pre>
<p>-Absorption Spectrum -=================== +Creating Absorption Spectra +===========================</p>
<pre>.. sectionauthor:: Britton Smith <brittonsmith@gmail.com>
</pre>
<p>-Absorption line spectra, such as shown below, can be made with data created -by the (:ref:`light-ray-generator`).  For each element of the ray, column -densities are calculated multiplying the number density within a grid cell -with the path length of the ray through the cell.  Line profiles are -generated using a voigt profile based on the temperature field.  The lines -are then shifted according to the redshift recorded by the light ray tool -and (optionally) the peculiar velocity of gas along the ray.  Inclusion of the -peculiar velocity requires setting ``use_peculiar_velocity`` to True in the call to -:meth:`~yt.analysis_modules.cosmological_observation.light_ray.light_ray.LightRay.make_light_ray`. +Absorption line spectra are spectra generated using bright background sources +to illuminate tenuous foreground material and are primarily used in studies +of the circumgalactic medium and intergalactic medium.  These spectra can +be created using the +:class:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum` +and +:class:`~yt.analysis_modules.cosmological_observation.light_ray.light_ray.LightRay` +analysis modules.</p>
<p>-The spectrum generator will output a file containing the wavelength and -normalized flux.  It will also output a text file listing all important lines. +The +:class:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum` class +and its workhorse method +:meth:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum.make_spectrum` +return two arrays, one with wavelengths, the other with the normalized +flux values at each of the wavelength values.  It can also output a text file +listing all important lines. + +For example, here is an absorption spectrum for the wavelength range from 900 +to 1800 Angstroms made with a light ray extending from z = 0 to z = 0.4:</p>
<pre>.. image:: _images/spectrum_full.png
   :width: 500
</pre>
<p>-An absorption spectrum for the wavelength range from 900 to 1800 Angstroms -made with a light ray extending from z = 0 to z = 0.4. +And a zoom-in on the 1425-1450 Angstrom window:</p>
<pre>.. image:: _images/spectrum_zoom.png
   :width: 500
</pre>
<p>-A zoom-in of the above spectrum. +Method for Creating Absorption Spectra +--------------------------------------</p>
<p>-Creating an Absorption Spectrum -------------------------------- +Once a +:class:`~yt.analysis_modules.cosmological_observation.light_ray.light_ray.LightRay` +has been created traversing a dataset using the :ref:`light-ray-generator`, +a series of arrays store the various fields of the gas parcels (represented +as cells) intersected along the ray. +:class:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum` +steps through each element of the +:class:`~yt.analysis_modules.cosmological_observation.light_ray.light_ray.LightRay`'s +arrays and calculates the column density for desired ion by multiplying its +number density with the path length through the cell.  Using these column +densities along with temperatures to calculate thermal broadening, voigt +profiles are deposited on to a featureless background spectrum.  By default, +the peculiar velocity of the gas is included as a doppler redshift in addition +to any cosmological redshift of the data dump itself.</p>
<p>-To instantiate an AbsorptionSpectrum object, the arguments required are the -minimum and maximum wavelengths, and the number of wavelength bins. +Subgrid Deposition +^^^^^^^^^^^^^^^^^^ + +For features not resolved (i.e. possessing narrower width than the spectral +resolution), +:class:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum` +performs subgrid deposition.  The subgrid deposition algorithm creates a number +of smaller virtual bins, by default the width of the virtual bins is 1/10th +the width of the spectral feature.  The Voigt profile is then deposited +into these virtual bins where it is resolved, and then these virtual bins +are numerically integrated back to the resolution of the original spectral bin +size, yielding accurate equivalent widths values. +:class:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum` +informs the user how many spectral features are deposited in this fashion. + +Tutorial on Creating an Absorption Spectrum +------------------------------------------- + +Initializing `AbsorptionSpectrum` Class +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To instantiate an +:class:`~yt.analysis_modules.absorption_spectrum.absorption_spectrum.AbsorptionSpectrum` +object, the arguments required are the +minimum and maximum wavelengths (assumed to be in Angstroms), and the number +of wavelength bins to span this range (including the endpoints)</p>
<pre>.. code-block:: python

  from yt.analysis_modules.absorption_spectrum.api import AbsorptionSpectrum
</pre>
<ul><li><p>sp = AbsorptionSpectrum(900.0, 1800.0, 10000)</p></li></ul>
<p>+  sp = AbsorptionSpectrum(900.0, 1800.0, 10001)</p>
<pre>Adding Features to the Spectrum</pre>
<p>-------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</p>
<pre>Absorption lines and continuum features can then be added to the spectrum.
To add a line, you must know some properties of the line: the rest wavelength,</pre>
<p>@@ -67,8 +110,8 @@</p>
<pre>field from the ray data to use to calculate the column density.  The
``label_threshold`` keyword tells the spectrum generator to add all lines
above a column density of 10 :superscript:`10` cm :superscript:`-2` to the</pre>
<p>-text line list.  If None is provided, as is the default, no lines of this -type will be added to the text list. +text line list output at the end.  If None is provided, as is the default, +no lines of this type will be added to the text list.</p>
<pre>Continuum features with optical depths that follow a power law can also be
added.  Like adding lines, you must specify details like the wavelength</pre>
<p>@@ -86,7 +129,7 @@</p>
<pre>  sp.add_continuum(my_label, field, wavelength, normalization, index)

Making the Spectrum</pre>
<p>-------------------- +^^^^^^^^^^^^^^^^^^^</p>
<pre>Once all the lines and continuum are added, it is time to make a spectrum out
of some light ray data.</pre>
<p>@@ -95,12 +138,12 @@</p>
<pre>wavelength, flux = sp.make_spectrum('lightray.h5',
                                    output_file='spectrum.fits',</pre>
<ul><li><p>line_list_file='lines.txt',</p></li>
<li><p>use_peculiar_velocity=True)</p></li></ul>
<p>+                                      line_list_file='lines.txt')</p>
<pre>A spectrum will be made using the specified ray data and the wavelength and</pre>
<p>-flux arrays will also be returned.  If ``use_peculiar_velocity`` is set to -False, the lines will only be shifted according to the redshift. +flux arrays will also be returned.  If you set the optional +``use_peculiar_velocity`` keyword to False, the lines will not incorporate +doppler redshifts to shift the deposition of the line features.</p>
<pre>Three output file formats are supported for writing out the spectrum: fits,
hdf5, and ascii.  The file format used is based on the extension provided</pre>
<p>@@ -112,15 +155,16 @@</p>
<pre>Generating Spectra in Parallel
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</pre>
<p>-The spectrum generator can be run in parallel simply by following the procedures -laid out in :ref:`parallel-computation` for running yt scripts in parallel. -Spectrum generation is parallelized using a multi-level strategy where each -absorption line is deposited by a different processor.  If the number of available -processors is greater than the number of lines, then the deposition of -individual lines will be divided over multiple processors. +The `AbsorptionSpectrum` analysis module can be run in parallel simply by +following the procedures laid out in :ref:`parallel-computation` for running +yt scripts in parallel.  Spectrum generation is parallelized using a multi-level +strategy where each absorption line is deposited by a different processor. +If the number of available processors is greater than the number of lines, +then the deposition of individual lines will be divided over multiple +processors.</p>
<p>-Fitting an Absorption Spectrum ------------------------------- +Fitting Absorption Spectra +==========================</p>
<pre>.. sectionauthor:: Hilary Egan <hilary.egan@colorado.edu>
</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 doc/source/developing/testing.rst --- a/doc/source/developing/testing.rst +++ b/doc/source/developing/testing.rst @@ -485,12 +485,12 @@</p>
<pre>autodiscovered by `nose <http://nose.readthedocs.org/en/latest/>`_ itself,
answer tests require definition of which set of tests constitute to a given
answer. Configuration for the integration server is stored in</pre>
<p>-*tests/tests_2.7.yaml* in the main yt repository: +*tests/tests.yaml* in the main yt repository:</p>
<pre>.. code-block:: yaml

   answer_tests:</pre>
<ul><li><p>local_artio_270:</p></li></ul>
<p>+      local_artio_000:</p>
<pre>- yt/frontends/artio/tests/test_outputs.py
    # ...
    other_tests:</pre>
<p>@@ -498,7 +498,7 @@</p>
<pre>         - '-v'
         - '-s'
</pre>
<p>-Each element under <strong>answer_tests</strong> defines answer name (*local_artio_270* in above +Each element under <strong>answer_tests</strong> defines answer name (*local_artio_000* in above</p>
<pre>snippet) and specifies a list of files/classes/methods that will be validated
(*yt/frontends/artio/tests/test_outputs.py* in above snippet). On the testing
server it is translated to:</pre>
<p>@@ -506,7 +506,7 @@</p>
<pre>.. code-block:: bash

   $ nosetests --with-answer-testing --local --local-dir ... --answer-big-data \</pre>
<ul><li><p>--answer-name=local_artio_270 \</p></li></ul>
<p>+      --answer-name=local_artio_000 \</p>
<pre>      yt/frontends/artio/tests/test_outputs.py

If the answer doesn't exist on the server yet, ``nosetests`` is run twice and</pre>
<p>@@ -516,21 +516,21 @@</p>
<pre>~~~~~~~~~~~~~~~~

In order to regenerate answers for a particular set of tests it is sufficient to</pre>
<p>-change the answer name in <strong>tests/tests_2.7.yaml</strong> e.g.: +change the answer name in <strong>tests/tests.yaml</strong> e.g.:</p>
<pre>.. code-block:: diff
</pre>
<ul><li><p>--- a/tests/tests_2.7.yaml</p></li>
<li><p>+++ b/tests/tests_2.7.yaml</p></li></ul>
<p>+   --- a/tests/tests.yaml +   +++ b/tests/tests.yaml</p>
<pre>   @@ -25,7 +25,7 @@
        - yt/analysis_modules/halo_finding/tests/test_rockstar.py
        - yt/frontends/owls_subfind/tests/test_outputs.py
</pre>
<ul><li><ul><li><p>local_owls_270:</p></li></ul></li>
<li><p>+  local_owls_271:</p></li></ul>
<p>+   –  local_owls_000: +   +  local_owls_001:</p>
<pre>        - yt/frontends/owls/tests/test_outputs.py
</pre>
<ul><li><p>local_pw_270:</p></li></ul>
<p>+      local_pw_000:</p>
<pre>would regenerate answers for OWLS frontend.
</pre>
<p>@@ -538,20 +538,35 @@</p>
<pre>~~~~~~~~~~~~~~~~~~~~~~~

In order to add a new set of answer tests, it is sufficient to extend the</pre>
<p>-*answer_tests* list in <strong>tests/tests_2.7.yaml</strong> e.g.: +*answer_tests* list in <strong>tests/tests.yaml</strong> e.g.:</p>
<pre>.. code-block:: diff
</pre>
<ul><li><p>--- a/tests/tests_2.7.yaml</p></li>
<li><p>+++ b/tests/tests_2.7.yaml</p></li></ul>
<p>+   --- a/tests/tests.yaml +   +++ b/tests/tests.yaml</p>
<pre>   @@ -60,6 +60,10 @@
        - yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_non_cosmo
        - yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_cosmo
</pre>
<ul><li><p>+  local_gdf_270:</p></li></ul>
<p>+   +  local_gdf_000:</p>
<pre>   +    - yt/frontends/gdf/tests/test_outputs.py
   +
   +
    other_tests:
      unittests:
</pre>
<p>+Restricting Python Versions for Answer Tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If for some reason a test can be run only for a specific version of python it is +possible to indicate this by adding a ``[py2]`` or ``[py3]`` tag. For example: + +.. code-block:: yaml + +   answer_tests: +      local_test_000: +         – yt/test_A.py  # [py2] +         – yt/test_B.py  # [py3] + +would result in ``test_A.py`` being run only for <strong>python2</strong> and ``test_B.py`` +being run only for <strong>python3</strong>.</p>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 doc/source/installing.rst --- a/doc/source/installing.rst +++ b/doc/source/installing.rst @@ -244,6 +244,26 @@</p>
<pre>Option 1:
</pre>
<p>+Ensure that you have all build dependencies installed in your current +conda environment: + +.. code-block:: bash + +  conda install cython mercurial sympy ipython h5py matplotlib + +.. note:: + +  If you are using a python3 environment, ``conda`` will not be able to install +  <strong>mercurial</strong>, which works only with python2. You can circumvent this issue by +  creating a dedicated python2 environment and symlinking <strong>hg</strong> in your current +  environment: + +  .. code-block:: bash + +     export CONDA_DIR=$(python -c ‘import sys; print(sys.executable.split("/bin/python")[0])’) +     conda create -y -n py27 python=2.7 mercurial +     ln -s ${CONDA_DIR}/envs/py27/bin/hg ${CONDA_DIR}/bin +</p>
<pre>Clone the yt repository with:

.. code-block:: bash</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 doc/source/visualizing/colormaps/index.rst --- a/doc/source/visualizing/colormaps/index.rst +++ b/doc/source/visualizing/colormaps/index.rst @@ -3,33 +3,33 @@</p>
<pre>Colormaps
=========
</pre>
<p>-There are several colormaps available for yt.  yt includes all of the -matplotlib colormaps as well for nearly all functions.  Individual -visualization functions usually allow you to specify a colormap with the +There are several colormaps available for yt.  yt includes all of the +matplotlib colormaps as well for nearly all functions.  Individual +visualization functions usually allow you to specify a colormap with the</p>
<pre>``cmap`` flag.

.. _install-palettable:
</pre>
<p>-Palettable and ColorBrewer2 +Palettable and ColorBrewer2</p>
<pre>~~~~~~~~~~~~~~~~~~~~~~~~~~~

While colormaps that employ a variety of colors often look attractive,
they are not always the best choice to convey information to one's audience.</pre>
<p>-There are numerous `articles <<a href="https://eagereyes.org/basics/rainbow-color-map">https://eagereyes.org/basics/rainbow-color-map</a>>`_ -and -`presentations <<a href="http://pong.tamu.edu/~kthyng/presentations/visualization.pdf">http://pong.tamu.edu/~kthyng/presentations/visualization.pdf</a>>`_ -that discuss how rainbow-based colormaps fail with regard to black-and-white +There are numerous `articles <<a href="https://eagereyes.org/basics/rainbow-color-map">https://eagereyes.org/basics/rainbow-color-map</a>>`_ +and +`presentations <<a href="http://pong.tamu.edu/~kthyng/presentations/visualization.pdf">http://pong.tamu.edu/~kthyng/presentations/visualization.pdf</a>>`_ +that discuss how rainbow-based colormaps fail with regard to black-and-white</p>
<pre>reproductions, colorblind audience members, and confusing in color ordering.
Depending on the application, the consensus seems to be that gradients between
one or two colors are the best way for the audience to extract information
from one's figures.  Many such colormaps are found in palettable.
</pre>
<p>-If you have installed `palettable <<a href="http://jiffyclub.github.io/palettable/">http://jiffyclub.github.io/palettable/</a>>`_ -(formerly brewer2mpl), you can also access the discrete colormaps available +If you have installed `palettable <<a href="http://jiffyclub.github.io/palettable/">http://jiffyclub.github.io/palettable/</a>>`_ +(formerly brewer2mpl), you can also access the discrete colormaps available</p>
<pre>to that package including those from `colorbrewer <http://colorbrewer2.org>`_.</pre>
<p>-Install `palettable <<a href="http://jiffyclub.github.io/palettable/">http://jiffyclub.github.io/palettable/</a>>`_ with -``pip install palettable``.  To access these maps in yt, instead of supplying -the colormap name, specify a tuple of the form (name, type, number), for +Install `palettable <<a href="http://jiffyclub.github.io/palettable/">http://jiffyclub.github.io/palettable/</a>>`_ with +``pip install palettable``.  To access these maps in yt, instead of supplying +the colormap name, specify a tuple of the form (name, type, number), for</p>
<pre>example ``('RdBu', 'Diverging', 9)``.  These discrete colormaps will
not be interpolated, and can be useful for creating
colorblind/printer/grayscale-friendly plots. For more information, visit</pre>
<p>@@ -40,22 +40,22 @@</p>
<pre>Making and Viewing Custom Colormaps
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</pre>
<p>-yt can also accommodate custom colormaps using the -:func:`~yt.visualization.color_maps.make_colormap` function -These custom colormaps can be made to an arbitrary level of -complexity.  You can make these on the fly for each yt session, or you can -store them in your :ref:`plugin-file` for access to them in every future yt +yt can also accommodate custom colormaps using the +:func:`~yt.visualization.color_maps.make_colormap` function +These custom colormaps can be made to an arbitrary level of +complexity.  You can make these on the fly for each yt session, or you can +store them in your :ref:`plugin-file` for access to them in every future yt</p>
<pre>session.  The example below creates two custom colormaps, one that has</pre>
<p>-three equally spaced bars of blue, white and red, and the other that -interpolates in increasing lengthen intervals from black to red, to green, -to blue.  These will be accessible for the rest of the yt session as -'french_flag' and ‘weird’.  See -:func:`~yt.visualization.color_maps.make_colormap` and +three equally spaced bars of blue, white and red, and the other that +interpolates in increasing lengthed intervals from black to red, to green, +to blue.  These will be accessible for the rest of the yt session as +'french_flag' and ‘weird’.  See +:func:`~yt.visualization.color_maps.make_colormap` and</p>
<pre>:func:`~yt.visualization.color_maps.show_colormaps` for more details.

.. code-block:: python
</pre>
<ul><li><p>yt.make_colormap([('blue', 20), ('white', 20), ('red', 20)],</p></li></ul>
<p>+    yt.make_colormap([('blue', 20), ('white', 20), ('red', 20)],</p>
<pre>name='french_flag', interpolate=False)
     yt.make_colormap([('black', 5), ('red', 10), ('green', 20), ('blue', 0)],
name='weird', interpolate=True)</pre>
<p>@@ -66,7 +66,7 @@</p>
<pre>This is a chart of all of the yt and matplotlib colormaps available.  In
addition to each colormap displayed here, you can access its "reverse" by simply</pre>
<p>-appending a ``"_r"`` to the end of the colormap name. +appending a ``"_r"`` to the end of the colormap name.</p>
<pre>.. image:: ../_images/all_colormaps.png
   :width: 512</pre>
<p>@@ -80,7 +80,7 @@</p>
<pre>Displaying Colormaps Locally
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</pre>
<p>-To display the most up to date colormaps locally, you can use the +To display the most up to date colormaps locally, you can use the</p>
<pre>:func:`~yt.visualization.color_maps.show_colormaps` function.  By default,
you'll see every colormap available to you, but you can specify subsets
of colormaps to display, either as just the ``yt_native`` colormaps, or</pre>
<p>@@ -98,7 +98,7 @@</p>
<pre>import yt
yt.show_colormaps(subset=['algae', 'kamae', 'spectral',</pre>
<ul><li><p>‘arbre’, ‘dusk’, ‘octarine’, 'kelp'],</p></li></ul>
<p>+                              ‘arbre’, ‘dusk’, ‘octarine’, 'kelp'],</p>
<pre>                      filename="yt_native.png")

Applying a Colormap to your Rendering</pre>
<p>@@ -111,7 +111,7 @@</p>
<pre>    yt.write_image(im, "output.png", cmap_name = 'jet')
</pre>
<p>-If you're using the Plot Window interface (e.g. SlicePlot, ProjectionPlot, +If you're using the Plot Window interface (e.g. SlicePlot, ProjectionPlot,</p>
<pre>etc.), it's even easier than that.  Simply create your rendering, and you
can quickly swap the colormap on the fly after the fact with the ``set_cmap``
callback:</pre>
<p>@@ -127,16 +127,16 @@</p>
<pre>    p.set_cmap(field="density", cmap='hot')
    p.save('proj_with_hot_cmap.png')
</pre>
<p>-For more information about the callbacks available to Plot Window objects, +For more information about the callbacks available to Plot Window objects,</p>
<pre>see :ref:`callbacks`.

Examples of Each Colormap
~~~~~~~~~~~~~~~~~~~~~~~~~

To give the reader a better feel for how a colormap appears once it is applied</pre>
<p>-to a dataset, below we provide a library of identical projections of an -isolated galaxy where only the colormap has changed.  They use the sample -dataset “IsolatedGalaxy” available at +to a dataset, below we provide a library of identical projections of an +isolated galaxy where only the colormap has changed.  They use the sample +dataset “IsolatedGalaxy” available at</p>
<pre>`http://yt-project.org/data <http://yt-project.org/data>`_.

.. yt_colormaps:: cmap_images.py</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 setupext.py --- a/setupext.py +++ b/setupext.py @@ -138,6 +138,10 @@</p>
<pre>    import hglib
except ImportError:
    return None</pre>
<ul><li><p>with hglib.open(target_dir) as repo:</p></li>
<li><p>changeset = repo.identify(id=True, branch=True).strip().decode('utf8')</p></li></ul>
<p>+    try: +        with hglib.open(target_dir) as repo: +            changeset = repo.identify( +                id=True, branch=True).strip().decode('utf8') +    except hglib.error.ServerError: +        return None</p>
<pre>return changeset</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 tests/nose_runner.py --- a/tests/nose_runner.py +++ b/tests/nose_runner.py @@ -7,7 +7,6 @@</p>
<pre>from yt.config import ytcfg
from yt.utilities.answer_testing.framework import AnswerTesting
</pre>
<p>–</p>
<pre>class NoseWorker(multiprocessing.Process):

    def __init__(self, task_queue, result_queue):</pre>
<p>@@ -54,10 +53,19 @@</p>
<pre>def generate_tasks_input():</pre>
<p>+    pyver = “py{}{}".format(sys.version_info.major, sys.version_info.minor) +    if sys.version_info < (3, 0, 0): +        DROP_TAG = “py3” +    else: +        DROP_TAG = "py2” +</p>
<pre>test_dir = ytcfg.get("yt", "test_data_dir")
answers_dir = os.path.join(test_dir, "answers")</pre>
<ul><li><p>with open('tests/tests_%i.%i.yaml' % sys.version_info[:2], ‘r’) as obj:</p></li>
<li><p>tests = yaml.load(obj)</p></li></ul>
<p>+    with open('tests/tests.yaml', ‘r’) as obj: +        lines = obj.read() +    data = ‘\n'.join([line for line in lines.split('\n’) +                      if DROP_TAG not in line]) +    tests = yaml.load(data)</p>
<pre>     base_argv = ['--local-dir=%s' % answers_dir, '-v',
'--with-answer-testing', '--answer-big-data', '--local']</pre>
<p>@@ -66,9 +74,11 @@</p>
<pre>for test in list(tests["other_tests"].keys()):
    args.append([test] + tests["other_tests"][test])
for answer in list(tests["answer_tests"].keys()):</pre>
<ul><li><p>argv = [answer]</p></li></ul>
<p>+        if tests["answer_tests"][answer] is None: +            continue +        argv = ["{}_{}".format(pyver, answer)]</p>
<pre>argv += base_argv</pre>
<ul><li><p>argv.append('--answer-name=%s' % answer)</p></li></ul>
<p>+        argv.append('--answer-name=%s' % argv[0])</p>
<pre>        argv += tests["answer_tests"][answer]
        args.append(argv)
</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 tests/tests.yaml --- /dev/null +++ b/tests/tests.yaml @@ -0,0 +1,73 @@ +answer_tests: +  local_artio_000: +    – yt/frontends/artio/tests/test_outputs.py + +  local_athena_000: +    – yt/frontends/athena + +  local_chombo_000: +    – yt/frontends/chombo/tests/test_outputs.py + +  local_enzo_000: +    – yt/frontends/enzo + +  local_fits_000: +    – yt/frontends/fits/tests/test_outputs.py + +  local_flash_000: +    – yt/frontends/flash/tests/test_outputs.py + +  local_gadget_000: +    – yt/frontends/gadget/tests/test_outputs.py + +  local_gdf_000: +    – yt/frontends/gdf/tests/test_outputs.py + +  local_halos_000: +    – yt/analysis_modules/halo_analysis/tests/test_halo_finders.py  # [py2] +    – yt/analysis_modules/halo_finding/tests/test_rockstar.py  # [py2] +    – yt/frontends/owls_subfind/tests/test_outputs.py +    – yt/frontends/gadget_fof/tests/test_outputs.py:test_fields_g5 +    – yt/frontends/gadget_fof/tests/test_outputs.py:test_fields_g42 + +  local_owls_000: +    – yt/frontends/owls/tests/test_outputs.py + +  local_pw_000: +    – yt/visualization/tests/test_plotwindow.py:test_attributes +    – yt/visualization/tests/test_plotwindow.py:test_attributes_wt +    – yt/visualization/tests/test_profile_plots.py:test_phase_plot_attributes +    – yt/visualization/tests/test_particle_plot.py:test_particle_projection_answers +    – yt/visualization/tests/test_particle_plot.py:test_particle_projection_filter +    – yt/visualization/tests/test_particle_plot.py:test_particle_phase_answers + +  local_tipsy_000: +    – yt/frontends/tipsy/tests/test_outputs.py + +  local_varia_000: +    – yt/analysis_modules/radmc3d_export +    – yt/frontends/moab/tests/test_c5.py +    – yt/analysis_modules/photon_simulator/tests/test_spectra.py +    – yt/analysis_modules/photon_simulator/tests/test_sloshing.py +    – yt/visualization/volume_rendering/tests/test_vr_orientation.py +    – yt/visualization/volume_rendering/tests/test_mesh_render.py + +  local_orion_000: +    – yt/frontends/boxlib/tests/test_orion.py + +  local_ramses_000: +    – yt/frontends/ramses/tests/test_outputs.py + +  local_ytdata_000: +    – yt/frontends/ytdata + +  local_absorption_spectrum_000: +    – yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_non_cosmo +    – yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_cosmo + +other_tests: +  unittests: +     – ‘-v’ +  cookbook: +     – ‘-v’ +     – ‘doc/source/cookbook/tests/test_cookbook.py’</p>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 tests/tests_2.7.yaml --- a/tests/tests_2.7.yaml +++ /dev/null @@ -1,71 +0,0 @@ -answer_tests:</p>
<ul><li><p>local_artio_270:</p></li>
<li><ul><li><p>yt/frontends/artio/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_athena_270:</p></li>
<li><ul><li><p>yt/frontends/athena</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_chombo_271:</p></li>
<li><ul><li><p>yt/frontends/chombo/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_enzo_270:</p></li>
<li><ul><li><p>yt/frontends/enzo</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_fits_270:</p></li>
<li><ul><li><p>yt/frontends/fits/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_flash_270:</p></li>
<li><ul><li><p>yt/frontends/flash/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_gadget_270:</p></li>
<li><ul><li><p>yt/frontends/gadget/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_gdf_270:</p></li>
<li><ul><li><p>yt/frontends/gdf/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_halos_270:</p></li>
<li><ul><li><p>yt/analysis_modules/halo_analysis/tests/test_halo_finders.py</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/halo_finding/tests/test_rockstar.py</p></li></ul></li>
<li><ul><li><p>yt/frontends/owls_subfind/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_owls_270:</p></li>
<li><ul><li><p>yt/frontends/owls/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_pw_271:</p></li>
<li><ul><li><p>yt/visualization/tests/test_plotwindow.py:test_attributes</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_plotwindow.py:test_attributes_wt</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_profile_plots.py:test_phase_plot_attributes</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_particle_plot.py:test_particle_projection_answers</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_particle_plot.py:test_particle_projection_filter</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_particle_plot.py:test_particle_phase_answers</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_tipsy_270:</p></li>
<li><ul><li><p>yt/frontends/tipsy/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_varia_274:</p></li>
<li><ul><li><p>yt/analysis_modules/radmc3d_export</p></li></ul></li>
<li><ul><li><p>yt/frontends/moab/tests/test_c5.py</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/photon_simulator/tests/test_spectra.py</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/photon_simulator/tests/test_sloshing.py</p></li></ul></li>
<li><ul><li><p>yt/visualization/volume_rendering/tests/test_vr_orientation.py</p></li></ul></li>
<li><ul><li><p>yt/visualization/volume_rendering/tests/test_mesh_render.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_orion_270:</p></li>
<li><ul><li><p>yt/frontends/boxlib/tests/test_orion.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_ramses_270:</p></li>
<li><ul><li><p>yt/frontends/ramses/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_ytdata_270:</p></li>
<li><ul><li><p>yt/frontends/ytdata</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_absorption_spectrum_271:</p></li>
<li><ul><li><p>yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_non_cosmo</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_cosmo</p></li></ul></li></ul>
<p>– -other_tests:</p>
<ul><li><p>unittests:</p></li>
<li><ul><li><p>‘-v’</p></li></ul></li>
<li><p>cookbook:</p></li>
<li><ul><li><p>‘-v’</p></li></ul></li>
<li><ul><li><p>‘doc/source/cookbook/tests/test_cookbook.py’</p></li></ul></li></ul>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 tests/tests_3.5.yaml --- a/tests/tests_3.5.yaml +++ /dev/null @@ -1,71 +0,0 @@ -answer_tests:</p>
<ul><li><p>local_artio_350:</p></li>
<li><ul><li><p>yt/frontends/artio/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_athena_350:</p></li>
<li><ul><li><p>yt/frontends/athena</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_chombo_350:</p></li>
<li><ul><li><p>yt/frontends/chombo/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_enzo_350:</p></li>
<li><ul><li><p>yt/frontends/enzo</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_fits_350:</p></li>
<li><ul><li><p>yt/frontends/fits/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_flash_350:</p></li>
<li><ul><li><p>yt/frontends/flash/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_gadget_350:</p></li>
<li><ul><li><p>yt/frontends/gadget/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_gdf_350:</p></li>
<li><ul><li><p>yt/frontends/gdf/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_halos_350:</p></li>
<li><ul><li><p>yt/frontends/owls_subfind/tests/test_outputs.py</p></li></ul></li>
<li><ul><li><p>yt/frontends/gadget_fof/tests/test_outputs.py:test_fields_g5</p></li></ul></li>
<li><ul><li><p>yt/frontends/gadget_fof/tests/test_outputs.py:test_fields_g42</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_owls_350:</p></li>
<li><ul><li><p>yt/frontends/owls/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_pw_350:</p></li>
<li><ul><li><p>yt/visualization/tests/test_plotwindow.py:test_attributes</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_plotwindow.py:test_attributes_wt</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_profile_plots.py:test_phase_plot_attributes</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_particle_plot.py:test_particle_projection_answers</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_particle_plot.py:test_particle_projection_filter</p></li></ul></li>
<li><ul><li><p>yt/visualization/tests/test_particle_plot.py:test_particle_phase_answers</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_tipsy_350:</p></li>
<li><ul><li><p>yt/frontends/tipsy/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_varia_351:</p></li>
<li><ul><li><p>yt/analysis_modules/radmc3d_export</p></li></ul></li>
<li><ul><li><p>yt/frontends/moab/tests/test_c5.py</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/photon_simulator/tests/test_spectra.py</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/photon_simulator/tests/test_sloshing.py</p></li></ul></li>
<li><ul><li><p>yt/visualization/volume_rendering/tests/test_vr_orientation.py</p></li></ul></li>
<li><ul><li><p>yt/visualization/volume_rendering/tests/test_mesh_render.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_orion_350:</p></li>
<li><ul><li><p>yt/frontends/boxlib/tests/test_orion.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_ramses_350:</p></li>
<li><ul><li><p>yt/frontends/ramses/tests/test_outputs.py</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_ytdata_350:</p></li>
<li><ul><li><p>yt/frontends/ytdata</p></li></ul></li></ul>
<p>–</p>
<ul><li><p>local_absorption_spectrum_350:</p></li>
<li><ul><li><p>yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_non_cosmo</p></li></ul></li>
<li><ul><li><p>yt/analysis_modules/absorption_spectrum/tests/test_absorption_spectrum.py:test_absorption_spectrum_cosmo</p></li></ul></li></ul>
<p>– -other_tests:</p>
<ul><li><p>unittests:</p></li>
<li><ul><li><p>‘-v’</p></li></ul></li>
<li><p>cookbook:</p></li>
<li><ul><li><p>‘-v’</p></li></ul></li>
<li><ul><li><p>‘doc/source/cookbook/tests/test_cookbook.py’</p></li></ul></li></ul>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/data_objects/data_containers.py --- a/yt/data_objects/data_containers.py +++ b/yt/data_objects/data_containers.py @@ -1432,6 +1432,9 @@</p>
<pre>center = self.ds.arr(center, 'code_length')
         if iterable(width):
w, u = width</pre>
<p>+            if isinstance(w, tuple) and isinstance(u, tuple): +                height = u +                w, u = w</p>
<pre>width = self.ds.quan(w, input_units = u)
         elif not isinstance(width, YTArray):
width = self.ds.quan(width, 'code_length')</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/fields/field_info_container.py --- a/yt/fields/field_info_container.py +++ b/yt/fields/field_info_container.py @@ -38,6 +38,13 @@</p>
<pre>    add_volume_weighted_smoothed_field, \
    sph_whitelist_fields
</pre>
<p>+def tupleize(inp): +    if isinstance(inp, tuple): +        return inp +    # prepending with a ‘?’ ensures that the sort order is the same in py2 and +    # py3, since names of field types shouldn't begin with punctuation +    return ('?', inp, ) +</p>
<pre>class FieldInfoContainer(dict):
    """
    This is a generic field container.  It contains a list of potential derived</pre>
<p>@@ -271,7 +278,7 @@</p>
<pre>self.ds.field_dependencies.update(deps)
# Note we may have duplicated
dfl = set(self.ds.derived_field_list).union(deps.keys())</pre>
<ul><li><p>self.ds.derived_field_list = list(sorted(dfl))</p></li></ul>
<p>+        self.ds.derived_field_list = list(sorted(dfl, key=tupleize))</p>
<pre>        return loaded, unavailable

    def add_output_field(self, name, **kwargs):</pre>
<p>@@ -357,5 +364,5 @@</p>
<pre>deps[field] = fd
mylog.debug("Succeeded with %s (needs %s)", field, fd.requested)
         dfl = set(self.ds.derived_field_list).union(deps.keys())</pre>
<ul><li><p>self.ds.derived_field_list = list(sorted(dfl))</p></li></ul>
<p>+        self.ds.derived_field_list = list(sorted(dfl, key=tupleize))</p>
<pre>return deps, unavailable</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/fields/particle_fields.py --- a/yt/fields/particle_fields.py +++ b/yt/fields/particle_fields.py @@ -493,10 +493,10 @@</p>
<pre>bv = data.get_field_parameter("bulk_velocity")
pos = data.ds.arr([data[ptype, spos % ax] for ax in "xyz"])
vel = data.ds.arr([data[ptype, svel % ax] for ax in "xyz"])</pre>
<p>+        pos = pos – np.reshape(center, (3, 1)) +        vel = vel – np.reshape(bv, (3, 1))</p>
<pre>theta = get_sph_theta(pos, normal)
phi = get_sph_phi(pos, normal)</pre>
<ul><li><p>pos = pos – np.reshape(center, (3, 1))</p></li>
<li><p>vel = vel – np.reshape(bv, (3, 1)) sphr = get_sph_r_component(vel, theta, phi, normal) return sphr</p></li></ul>
<p>@@ -536,10 +536,10 @@</p>
<pre>bv = data.get_field_parameter("bulk_velocity")
pos = data.ds.arr([data[ptype, spos % ax] for ax in "xyz"])
vel = data.ds.arr([data[ptype, svel % ax] for ax in "xyz"])</pre>
<p>+        pos = pos – np.reshape(center, (3, 1)) +        vel = vel – np.reshape(bv, (3, 1))</p>
<pre>theta = get_sph_theta(pos, normal)
phi = get_sph_phi(pos, normal)</pre>
<ul><li><p>pos = pos – np.reshape(center, (3, 1))</p></li>
<li><p>vel = vel – np.reshape(bv, (3, 1)) spht = get_sph_theta_component(vel, theta, phi, normal) return spht</p></li></ul>
<p>@@ -664,9 +664,9 @@</p>
<pre>bv = data.get_field_parameter("bulk_velocity")
pos = data.ds.arr([data[ptype, spos % ax] for ax in "xyz"])
vel = data.ds.arr([data[ptype, svel % ax] for ax in "xyz"])</pre>
<ul><li><p>theta = get_cyl_theta(pos, normal) pos = pos – np.reshape(center, (3, 1)) vel = vel – np.reshape(bv, (3, 1))</p></li></ul>
<p>+        theta = get_cyl_theta(pos, normal)</p>
<pre>        cylr = get_cyl_r_component(vel, theta, normal)
        return cylr
</pre>
<p>@@ -688,9 +688,9 @@</p>
<pre>bv = data.get_field_parameter("bulk_velocity")
pos = data.ds.arr([data[ptype, spos % ax] for ax in "xyz"])
vel = data.ds.arr([data[ptype, svel % ax] for ax in "xyz"])</pre>
<ul><li><p>theta = get_cyl_theta(pos, normal) pos = pos – np.reshape(center, (3, 1)) vel = vel – np.reshape(bv, (3, 1))</p></li></ul>
<p>+        theta = get_cyl_theta(pos, normal)</p>
<pre>        cylt = get_cyl_theta_component(vel, theta, normal)
        return cylt
</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/fields/species_fields.py --- a/yt/fields/species_fields.py +++ b/yt/fields/species_fields.py @@ -114,6 +114,24 @@</p>
<pre>                       particle_type = particle_type,
                       units = unit_system["number_density"])
</pre>
<p>+def add_species_aliases(registry, ftype, alias_species, species): +    """ +    This takes a field registry, a fluid type, and two species names. +    The first species name is one you wish to alias to an existing species +    name.  For instance you might alias all “H_p0” fields to “H_” fields +    to indicate that “H_” fields are really just neutral hydrogen fields. +    This function registers field aliases for the density, number_density, +    mass, and fraction fields between the two species given in the arguments. +    """ +    registry.alias((ftype, “%s_density” % alias_species), +                   (ftype, “%s_density” % species)) +    registry.alias((ftype, “%s_fraction” % alias_species), +                   (ftype, “%s_fraction” % species)) +    registry.alias((ftype, “%s_number_density” % alias_species), +                   (ftype, “%s_number_density” % species)) +    registry.alias((ftype, “%s_mass” % alias_species), +                   (ftype, “%s_mass” % species)) +</p>
<pre>def add_nuclei_density_fields(registry, ftype,
                              particle_type = False):
    unit_system = registry.ds.unit_system</pre>
<p>@@ -181,4 +199,10 @@</p>
<pre># Skip it
continue
         func(registry, ftype, species, particle_type)</pre>
<p>+        # Adds aliases for all neutral species from their raw “MM_” +        # species to “MM_p0_” species to be explicit. +        # See YTEP-0003 for more details. +        if (ChemicalFormula(species).charge == 0): +            alias_species = “%s_p0” % species.split('_')[0] +            add_species_aliases(registry, “gas”, alias_species, species)</p>
<pre>add_nuclei_density_fields(registry, ftype, particle_type=particle_type)</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/fields/tests/test_fields.py --- a/yt/fields/tests/test_fields.py +++ b/yt/fields/tests/test_fields.py @@ -301,6 +301,19 @@</p>
<pre>    u2 = array_like_field(ad, 1., ("all", "particle_mass")).units
    assert u1 == u2
</pre>
<p>+def test_add_field_string(): +    ds = fake_random_ds(16) +    ad = ds.all_data() + +    def density_alias(field, data): +        return data['density'] + +    ds.add_field('density_alias', function=density_alias, units='g/cm**3') + +    ad['density_alias'] +    assert ds.derived_field_list[0] == ‘density_alias’ + +</p>
<pre>if __name__ == "__main__":
    setup()
    for t in test_all_fields():</pre>
<p>@@ -308,3 +321,4 @@</p>
<pre>test_add_deposited_particle_field()
test_add_field_unit_semantics()
test_array_like_field()</pre>
<p>+    test_add_field_string()</p>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/frontends/flash/fields.py --- a/yt/frontends/flash/fields.py +++ b/yt/frontends/flash/fields.py @@ -151,12 +151,14 @@</p>
<pre>Na_code = data.ds.quan(Na, '1/code_mass')
return data["flash","dens"]*data["flash","sumy"]*Na_code
         self.add_field(('flash','nion'), function=_nion, units="code_length**-3")</pre>
<ul><li><p>def _abar(field, data):</p></li>
<li><p>try:</p></li>
<li><p>return data["flash","abar"]</p></li>
<li><p>except:</p></li>
<li><p>return 1.0/data["flash","sumy"]</p></li>
<li><p>self.add_field(("flash","abar"), function=_abar, units="1")</p></li></ul>
<p>+ +        if ("flash", “abar”) in self.field_list: +            self.add_output_field(("flash", “abar"), units="1”) +        else: +            def _abar(field, data): +                return 1.0 / data["flash","sumy"] +            self.add_field(("flash","abar"), function=_abar, units="1") +</p>
<pre>         def _number_density(fields,data):
return (data["nele"]+data["nion"])
         self.add_field(("gas","number_density"), function=_number_density,</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/frontends/stream/data_structures.py --- a/yt/frontends/stream/data_structures.py +++ b/yt/frontends/stream/data_structures.py @@ -66,7 +66,7 @@</p>
<pre>from yt.data_objects.unstructured_mesh import \
    SemiStructuredMesh, \
    UnstructuredMesh</pre>
<p>-from yt.extern.six import string_types, iteritems +from yt.extern.six import string_types</p>
<pre>from .fields import \
    StreamFieldInfo
</pre>
<p>@@ -464,36 +464,46 @@</p>
<pre>        ds.stream_handler.particle_count[gi] = npart
                                        
def unitify_data(data):</pre>
<ul><li><p>if all([hasattr(val, ‘units’) for val in data.values()]):</p></li>
<li><p>new_data, field_units = {}, {}</p></li>
<li><p>for k, v in data.items():</p></li>
<li><p>field_units[k] = v.units</p></li>
<li><p>new_data[k] = v.copy().d</p></li>
<li><p>data = new_data</p></li>
<li><p>elif all([((not isinstance(val, np.ndarray)) and (len(val) == 2))</p></li>
<li><p>for val in data.values()]):</p></li>
<li><p>new_data, field_units = {}, {}</p></li>
<li><p>for field in data:</p></li></ul>
<p>+    new_data, field_units = {}, {} +    for field, val in data.items(): +        # val is a data array +        if isinstance(val, np.ndarray): +            # val is a YTArray +            if hasattr(val, "units"): +                field_units[field] = val.units +                new_data[field] = val.copy().d +            # val is a numpy array +            else: +                field_units[field] = "" +                new_data[field] = val.copy() + +        # val is a tuple of (data, units) +        elif isinstance(val, tuple) and len(val) == 2:</p>
<pre>try:
    assert isinstance(field, (string_types, tuple)), \
      "Field name is not a string!"</pre>
<ul><li><p>assert isinstance(data[field][0], np.ndarray), \</p></li></ul>
<p>+                assert isinstance(val[0], np.ndarray), \</p>
<pre>"Field data is not an ndarray!"</pre>
<ul><li><p>assert isinstance(data[field][1], string_types), \</p></li></ul>
<p>+                assert isinstance(val[1], string_types), \</p>
<pre>"Unit specification is not a string!"</pre>
<ul><li><p>field_units[field] = data[field][1]</p></li>
<li><p>new_data[field] = data[field][0]</p></li></ul>
<p>+                field_units[field] = val[1] +                new_data[field] = val[0]</p>
<pre>except AssertionError as e:</pre>
<ul><li><p>raise RuntimeError("The data dict appears to be invalid.\n" +</p></li>
<li><p>str(e))</p></li>
<li><p>data = new_data</p></li>
<li><p>elif all([iterable(val) for val in data.values()]):</p></li>
<li><p>field_units = {field:'' for field in data.keys()}</p></li>
<li><p>data = dict((field, np.asarray(val)) for field, val in iteritems(data))</p></li>
<li><p>else:</p></li>
<li><p>raise RuntimeError("The data dict appears to be invalid. "</p></li>
<li><p>"The data dictionary must map from field "</p></li>
<li><p>"names to (numpy array, unit spec) tuples. ")</p></li></ul>
<p>+                raise RuntimeError( +                    “The data dict appears to be invalid.\n” + str(e)) + +        # val is a list of data to be turned into an array +        elif iterable(val): +            field_units[field] = "" +            new_data[field] = np.asarray(val) + +        else: +            raise RuntimeError("The data dict appears to be invalid. " +                               "The data dictionary must map from field " +                               "names to (numpy array, unit spec) tuples. ") + +    data = new_data +</p>
<pre># At this point, we have arrays for all our fields
new_data = {}
for field in data:</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/chemical_formulas.py --- a/yt/utilities/chemical_formulas.py +++ b/yt/utilities/chemical_formulas.py @@ -29,6 +29,9 @@</p>
<pre>    charge = -int(ionization[1:])
else:
    raise NotImplementedError</pre>
<p>+        elif self.formula_string.startswith('El'): +            molecule = self.formula_string +            charge = -1</p>
<pre>         else:
molecule = self.formula_string
charge = 0</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/command_line.py --- a/yt/utilities/command_line.py +++ b/yt/utilities/command_line.py @@ -1075,25 +1075,33 @@</p>
<pre>print("File must be a PNG file!")
return 1
         image_data = base64.b64encode(open(filename, 'rb').read())</pre>
<ul><li><p>api_key = ‘f62d550859558f28c4c214136bc797c7’</p></li>
<li><p>parameters = {'key':api_key, ‘image':image_data, type:'base64’,</p></li>
<li><p>‘caption’: "",</p></li></ul>
<p>+        api_key = ‘e1977d9195fe39e’ +        headers = {'Authorization': ‘Client-ID %s’ % api_key} +        parameters = {'image': image_data, type: ‘base64’, +                      ‘name’: filename,</p>
<pre>'title': "%s uploaded by yt" % filename}
         data = urllib.parse.urlencode(parameters).encode('utf-8')</pre>
<ul><li><p>req = urllib.request.Request('<a href="http://api.imgur.com/2/upload.json">http://api.imgur.com/2/upload.json</a>', data)</p></li></ul>
<p>+        req = urllib.request.Request('<a href="https://api.imgur.com/3/upload">https://api.imgur.com/3/upload</a>', data=data, +                                     headers=headers)</p>
<pre>         try:
response = urllib.request.urlopen(req).read().decode()
         except urllib.error.HTTPError as e:
print("ERROR", e)
return {'uploaded':False}
         rv = json.loads(response)</pre>
<ul><li><p>if ‘upload’ in rv and ‘links’ in rv['upload']:</p></li></ul>
<p>+        if ‘data’ in rv and ‘link’ in rv['data']: +            delete_cmd = ( +                “curl -X DELETE -H 'Authorization: Client-ID {secret}'” +                " <a href="https://api.imgur.com/3/image/">https://api.imgur.com/3/image/</a>{delete_hash}" +            )</p>
<pre>print()
print("Image successfully uploaded!  You can find it at:")</pre>
<ul><li><p>print("    %s" % (rv['upload']['links']['original']))</p></li></ul>
<p>+            print("    %s" % (rv['data']['link']))</p>
<pre>print()</pre>
<ul><li><p>print("If you'd like to delete it, visit this page:")</p></li>
<li><p>print("    %s" % (rv['upload']['links']['delete_page']))</p></li></ul>
<p>+            print("If you'd like to delete it, use the following") +            print("    %s" % +                  delete_cmd.format(secret=api_key, +                                    delete_hash=rv['data']['deletehash']))</p>
<pre>print()
         else:
print()</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/lib/field_interpolation_tables.pxd --- a/yt/utilities/lib/field_interpolation_tables.pxd +++ b/yt/utilities/lib/field_interpolation_tables.pxd @@ -16,6 +16,7 @@</p>
<pre>cimport cython
cimport numpy as np
from yt.utilities.lib.fp_utils cimport imax, fmax, imin, fmin, iclip, fclip, fabs</pre>
<p>+from libc.stdlib cimport malloc</p>
<pre>DEF Nch = 4
</pre>
<p>@@ -26,6 +27,8 @@</p>
<pre>np.float64_t bounds[2]
np.float64_t dbin
np.float64_t idbin</pre>
<p>+    np.float64_t *d0 +    np.float64_t *dy</p>
<pre>int field_id
int weight_field_id
int weight_table_id</pre>
<p>@@ -41,12 +44,18 @@</p>
<pre>cdef inline void FIT_initialize_table(FieldInterpolationTable *fit, int nbins,
              np.float64_t *values, np.float64_t bounds1, np.float64_t bounds2,
              int field_id, int weight_field_id, int weight_table_id) nogil:</pre>
<p>+    cdef int i</p>
<pre>fit.bounds[0] = bounds1; fit.bounds[1] = bounds2
fit.nbins = nbins
fit.dbin = (fit.bounds[1] - fit.bounds[0])/(fit.nbins-1)
fit.idbin = 1.0/fit.dbin
# Better not pull this out from under us, yo
fit.values = values</pre>
<p>+    fit.d0 = <np.float64_t *> malloc(sizeof(np.float64_t) * nbins) +    fit.dy = <np.float64_t *> malloc(sizeof(np.float64_t) * nbins) +    for i in range(nbins-1): +        fit.d0[i] = fit.bounds[0] + i * fit.dbin +        fit.dy[i] = (fit.values[i + 1] – fit.values[i]) * fit.idbin</p>
<pre>fit.field_id = field_id
fit.weight_field_id = weight_field_id
fit.weight_table_id = weight_table_id</pre>
<p>@@ -56,18 +65,18 @@</p>
<pre>@cython.cdivision(True)
cdef inline np.float64_t FIT_get_value(FieldInterpolationTable *fit,
                                       np.float64_t dvs[6]) nogil:</pre>
<ul><li><p>cdef np.float64_t bv, dy, dd</p></li></ul>
<p>+    cdef np.float64_t dd, dout</p>
<pre>cdef int bin_id
if dvs[fit.field_id] >= fit.bounds[1] or dvs[fit.field_id] <= fit.bounds[0]: return 0.0
if not isnormal(dvs[fit.field_id]): return 0.0
bin_id = <int> ((dvs[fit.field_id] - fit.bounds[0]) * fit.idbin)
bin_id = iclip(bin_id, 0, fit.nbins-2)</pre>
<ul><li><p>dd = dvs[fit.field_id] – (fit.bounds[0] + bin_id * fit.dbin) # x – x0</p></li>
<li><p>bv = fit.values[bin_id]</p></li>
<li><p>dy = fit.values[bin_id + 1] – bv</p></li></ul>
<p>+ +    dd = dvs[fit.field_id] – fit.d0[bin_id] # x – x0 +    dout = fit.values[bin_id] + dd * fit.dy[bin_id]</p>
<pre>if fit.weight_field_id != -1:</pre>
<ul><li><p>return dvs[fit.weight_field_id] * (bv + dd*dy*fit.idbin)</p></li>
<li><p>return (bv + dd*dy*fit.idbin)</p></li></ul>
<p>+        dout *= dvs[fit.weight_field_id] +    return dout</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/lib/grid_traversal.pyx --- a/yt/utilities/lib/grid_traversal.pyx +++ b/yt/utilities/lib/grid_traversal.pyx @@ -853,9 +853,11 @@</p>
<pre>            self.sampler = volume_render_stars_sampler

    def __dealloc__(self):</pre>
<ul><li><p>return</p></li>
<li><p>#free(self.vra.fits)</p></li>
<li><p>#free(self.vra)</p></li></ul>
<p>+        for i in range(self.vra.n_fits): +            free(self.vra.fits[i].d0) +            free(self.vra.fits[i].dy) +        free(self.vra.fits) +        free(self.vra)</p>
<pre>cdef class LightSourceRenderSampler(ImageSampler):
    cdef VolumeRenderAccumulator *vra</pre>
<p>@@ -914,11 +916,13 @@</p>
<pre>        self.sampler = volume_render_gradient_sampler

    def __dealloc__(self):</pre>
<ul><li><p>return</p></li>
<li><p>#free(self.vra.fits)</p></li>
<li><p>#free(self.vra)</p></li>
<li><p>#free(self.light_dir)</p></li>
<li><p>#free(self.light_rgba)</p></li></ul>
<p>+        for i in range(self.vra.n_fits): +            free(self.vra.fits[i].d0) +            free(self.vra.fits[i].dy) +        free(self.vra.light_dir) +        free(self.vra.light_rgba) +        free(self.vra.fits) +        free(self.vra)</p>
<pre>@cython.boundscheck(False)</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/lib/mesh_intersection.pyx --- a/yt/utilities/lib/mesh_intersection.pyx +++ b/yt/utilities/lib/mesh_intersection.pyx @@ -21,6 +21,7 @@</p>
<pre>cimport cython
from libc.math cimport fabs, fmin, fmax, sqrt
from yt.utilities.lib.mesh_samplers cimport sample_hex20</pre>
<p>+from vec3_ops cimport dot, subtract, cross, distance</p>
<pre>@cython.boundscheck(False)</pre>
<p>@@ -80,30 +81,6 @@</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>-cdef float dot(const float* a,</p>
<ul><li><p>const float* b,</p></li>
<li><p>size_t N) nogil:</p></li>
<li><p>cdef int i</p></li>
<li><p>cdef float rv = 0.0</p></li>
<li><p>for i in range(N):</p></li>
<li><p>rv += a[i]*b[i]</p></li>
<li><p>return rv</p></li></ul>
<p>– – -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.cdivision(True) -cdef void cross(const float* a,</p>
<ul><li><p>const float* b,</p></li>
<li><p>float* c) nogil:</p></li>
<li><p>c[0] = a[1]*b[2] – a[2]*b[1]</p></li>
<li><p>c[1] = a[2]*b[0] – a[0]*b[2]</p></li>
<li><p>c[2] = a[0]*b[1] – a[1]*b[0]</p></li></ul>
<p>– – -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.cdivision(True)</p>
<pre>cdef void patchBoundsFunc(Patch* patches,
                          size_t item,
                          rtcg.RTCBounds* bounds_o) nogil:</pre>
<p>@@ -146,7 +123,7 @@</p>
<pre># first we compute the two planes that define the ray.
cdef float[3] n, N1, N2</pre>
<ul><li><p>cdef float A = dot(ray.dir, ray.dir, 3)</p></li></ul>
<p>+    cdef float A = dot(ray.dir, ray.dir)</p>
<pre>    for i in range(3):
        n[i] = ray.dir[i] / A
</pre>
<p>@@ -160,16 +137,16 @@</p>
<pre>        N1[2] =-n[1]
    cross(N1, n, N2)
</pre>
<ul><li><p>cdef float d1 = -dot(N1, ray.org, 3)</p></li>
<li><p>cdef float d2 = -dot(N2, ray.org, 3)</p></li></ul>
<p>+    cdef float d1 = -dot(N1, ray.org) +    cdef float d2 = -dot(N2, ray.org)</p>
<pre># the initial guess is set to zero
cdef float u = 0.0
cdef float v = 0.0
cdef float[3] S
patchSurfaceFunc(patch, u, v, S)</pre>
<ul><li><p>cdef float fu = dot(N1, S, 3) + d1</p></li>
<li><p>cdef float fv = dot(N2, S, 3) + d2</p></li></ul>
<p>+    cdef float fu = dot(N1, S) + d1 +    cdef float fv = dot(N2, S) + d2</p>
<pre>cdef float err = fmax(fabs(fu), fabs(fv))

# begin Newton interation</pre>
<p>@@ -183,10 +160,10 @@</p>
<pre># compute the Jacobian
patchSurfaceDerivU(patch, u, v, Su)
patchSurfaceDerivV(patch, u, v, Sv)</pre>
<ul><li><p>J11 = dot(N1, Su, 3)</p></li>
<li><p>J12 = dot(N1, Sv, 3)</p></li>
<li><p>J21 = dot(N2, Su, 3)</p></li>
<li><p>J22 = dot(N2, Sv, 3)</p></li></ul>
<p>+        J11 = dot(N1, Su) +        J12 = dot(N1, Sv) +        J21 = dot(N2, Su) +        J22 = dot(N2, Sv)</p>
<pre>det = (J11*J22 - J12*J21)

# update the u, v values</pre>
<p>@@ -194,17 +171,14 @@</p>
<pre>v -= (-J21*fu + J11*fv) / det

patchSurfaceFunc(patch, u, v, S)</pre>
<ul><li><p>fu = dot(N1, S, 3) + d1</p></li>
<li><p>fv = dot(N2, S, 3) + d2</p></li></ul>
<p>+        fu = dot(N1, S) + d1 +        fv = dot(N2, S) + d2</p>
<pre>        err = fmax(fabs(fu), fabs(fv))
        iterations += 1

    # t is the distance along the ray to this hit</pre>
<ul><li><p>cdef float t = 0.0</p></li>
<li><p>for i in range(3):</p></li>
<li><p>t += (S[i] – ray.org[i])**2</p></li>
<li><p>t = sqrt(t)</p></li></ul>
<p>+    cdef float t = distance(S, ray.org)</p>
<pre># only count this is it's the closest hit
if (t < ray.tnear or t > ray.Ng[0]):</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/lib/pixelization_routines.pyx --- a/yt/utilities/lib/pixelization_routines.pyx +++ b/yt/utilities/lib/pixelization_routines.pyx @@ -21,6 +21,7 @@</p>
<pre>from yt.utilities.exceptions import YTPixelizeError, \
    YTElementTypeNotRecognized
from libc.stdlib cimport malloc, free</pre>
<p>+from vec3_ops cimport dot, cross, subtract</p>
<pre>from yt.utilities.lib.element_mappings cimport \
    ElementSampler, \
    P1Sampler3D, \</pre>
<p>@@ -518,17 +519,11 @@</p>
<pre>vi2a = faces[n][1][0]
vi2b = faces[n][1][1]
# Shared vertex is vi1a and vi2a</pre>
<ul><li><p>for i in range(3):</p></li>
<li><p>vec1[i] = vertices[vi1b][i] – vertices[vi1a][i]</p></li>
<li><p>vec2[i] = vertices[vi2b][i] – vertices[vi2a][i]</p></li>
<li><p>npoint[i] = point[i] – vertices[vi1b][i]</p></li>
<li><p># Now the cross product of vec1 x vec2</p></li>
<li><p>cp_vec[0] = vec1[1] * vec2[2] – vec1[2] * vec2[1]</p></li>
<li><p>cp_vec[1] = vec1[2] * vec2[0] – vec1[0] * vec2[2]</p></li>
<li><p>cp_vec[2] = vec1[0] * vec2[1] – vec1[1] * vec2[0]</p></li>
<li><p>dp = 0.0</p></li>
<li><p>for j in range(3):</p></li>
<li><p>dp += cp_vec[j] * npoint[j]</p></li></ul>
<p>+        subtract(vertices[vi1b], vertices[vi1a], vec1) +        subtract(vertices[vi2b], vertices[vi2a], vec2) +        subtract(point, vertices[vi1b], npoint) +        cross(vec1, vec2, cp_vec) +        dp = dot(cp_vec, npoint)</p>
<pre>         if match == 0:
if dp < 0:
    signs[n] = -1</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/lib/vec3_ops.pxd --- a/yt/utilities/lib/vec3_ops.pxd +++ b/yt/utilities/lib/vec3_ops.pxd @@ -1,22 +1,22 @@</p>
<pre>cimport cython</pre>
<p>-import numpy as np -cimport numpy as np +cimport cython.floating</p>
<pre>from libc.math cimport sqrt
</pre>
<p>+</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>-cdef inline np.float64_t dot(const np.float64_t a[3],</p>
<ul><li><p>const np.float64_t b[3]) nogil:</p></li></ul>
<p>+cdef inline cython.floating dot(const cython.floating[3] a, +                                const cython.floating[3] b) nogil:</p>
<pre>    return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]


@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>-cdef inline void cross(const np.float64_t a[3],</p>
<ul><li><p>const np.float64_t b[3],</p></li>
<li><p>np.float64_t c[3]) nogil:</p></li></ul>
<p>+cdef inline void cross(const cython.floating[3] a, +                       const cython.floating[3] b, +                       cython.floating c[3]) nogil:</p>
<pre>c[0] = a[1]*b[2] - a[2]*b[1]
c[1] = a[2]*b[0] - a[0]*b[2]
c[2] = a[0]*b[1] - a[1]*b[0]</pre>
<p>@@ -25,26 +25,36 @@</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>-cdef inline void subtract(const np.float64_t a[3],</p>
<ul><li><p>const np.float64_t b[3],</p></li>
<li><p>np.float64_t c[3]) nogil:</p></li></ul>
<p>+cdef inline void subtract(const cython.floating[3] a, +                          const cython.floating[3] b, +                          cython.floating c[3]) nogil:</p>
<pre>    c[0] = a[0] - b[0]
    c[1] = a[1] - b[1]
    c[2] = a[2] - b[2]
</pre>
<p>+</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>-cdef inline void fma(const np.float64_t f,</p>
<ul><li><p>const np.float64_t a[3],</p></li>
<li><p>const np.float64_t b[3],</p></li>
<li><p>np.float64_t c[3]) nogil:</p></li></ul>
<p>+cdef inline cython.floating distance(const cython.floating[3] a, +                                     const cython.floating[3] b) nogil: +    return sqrt((a[0] – b[0])**2 + (a[1] – b[1])**2 +(a[2] – b[2])**2) + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +cdef inline void fma(const cython.floating f, +                     const cython.floating[3] a, +                     const cython.floating[3] b, +                     cython.floating[3] c) nogil:</p>
<pre>    c[0] = f * a[0] + b[0]
    c[1] = f * a[1] + b[1]
    c[2] = f * a[2] + b[2]
</pre>
<p>+</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>-cdef inline np.float64_t L2_norm(const np.float64_t a[3]) nogil: +cdef inline cython.floating L2_norm(const cython.floating[3] a) nogil:</p>
<pre>return sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2])</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/utilities/logger.py --- a/yt/utilities/logger.py +++ b/yt/utilities/logger.py @@ -54,36 +54,43 @@</p>
<pre>ytLogger = logging.getLogger("yt")
</pre>
<p>-yt_sh = logging.StreamHandler(stream=stream) -# create formatter and add it to the handlers -formatter = logging.Formatter(ufstring) -yt_sh.setFormatter(formatter) -# add the handler to the logger -ytLogger.addHandler(yt_sh) -ytLogger.setLevel(level) -ytLogger.propagate = False –</p>
<pre>def disable_stream_logging():</pre>
<ul><li><p>ytLogger.removeHandler(ytLogger.handlers[0])</p></li></ul>
<p>+    if len(ytLogger.handlers) > 0: +        ytLogger.removeHandler(ytLogger.handlers[0])</p>
<pre>    h = logging.NullHandler()
    ytLogger.addHandler(h)
</pre>
<p>-original_emitter = yt_sh.emit –</p>
<pre>def colorize_logging():
    f = logging.Formatter(cfstring)
    ytLogger.handlers[0].setFormatter(f)
    yt_sh.emit = add_coloring_to_emit_ansi(yt_sh.emit)

def uncolorize_logging():</pre>
<ul><li><p>f = logging.Formatter(ufstring)</p></li>
<li><p>ytLogger.handlers[0].setFormatter(f)</p></li>
<li><p>yt_sh.emit = original_emitter</p></li></ul>
<p>– -if ytcfg.getboolean("yt", "coloredlogs"):</p>
<ul><li><p>colorize_logging()</p></li></ul>
<p>+    try: +        f = logging.Formatter(ufstring) +        ytLogger.handlers[0].setFormatter(f) +        yt_sh.emit = original_emitter +    except NameError: +        # yt_sh and original_emitter are not defined because +        # suppressStreamLogging is True, so we continue since there is nothing +        # to uncolorize +        pass</p>
<pre>if ytcfg.getboolean("yt", "suppressStreamLogging"):
    disable_stream_logging()</pre>
<p>+else: +    yt_sh = logging.StreamHandler(stream=stream) +    # create formatter and add it to the handlers +    formatter = logging.Formatter(ufstring) +    yt_sh.setFormatter(formatter) +    # add the handler to the logger +    ytLogger.addHandler(yt_sh) +    ytLogger.setLevel(level) +    ytLogger.propagate = False + +    original_emitter = yt_sh.emit + +    if ytcfg.getboolean("yt", "coloredlogs"): +        colorize_logging()</p>
<pre>ytLogger.debug("Set log level to %s", level)</pre>
<p>diff -r 71eeada8e2678c1c55fdf7aa11868c2e99272637 -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 yt/visualization/volume_rendering/camera.py --- a/yt/visualization/volume_rendering/camera.py +++ b/yt/visualization/volume_rendering/camera.py @@ -165,7 +165,7 @@</p>
<pre>         position : number, YTQuantity, iterable, or 3 element YTArray
If a scalar, assumes that the position is the same in all three</pre>
<ul><li><p>coordinates. If an interable, must contain only scalars or</p></li></ul>
<p>+            coordinates. If an iterable, must contain only scalars or</p>
<pre>            (length, unit) tuples.
        '''
</pre>
<p>@@ -195,7 +195,7 @@</p>
<pre>         width : number, YTQuantity, iterable, or 3 element YTArray
The width of the volume rendering in the horizontal, vertical, and
depth directions. If a scalar, assumes that the width is the same in</pre>
<ul><li><p>all three directions. If an interable, must contain only scalars or</p></li></ul>
<p>+            all three directions. If an iterable, must contain only scalars or</p>
<pre>            (length, unit) tuples.
        '''
</pre>
<p>@@ -223,7 +223,7 @@</p>
<pre>         focus : number, YTQuantity, iterable, or 3 element YTArray
The width of the volume rendering in the horizontal, vertical, and
depth directions. If a scalar, assumes that the width is the same in</pre>
<ul><li><p>all three directions. If an interable, must contain only scalars or</p></li></ul>
<p>+            all three directions. If an iterable, must contain only scalars or</p>
<pre>            (length, unit) tuples.
        '''
</pre>
<p>@@ -360,7 +360,7 @@</p>
<pre>         width : number, YTQuantity, iterable, or 3 element YTArray
The width of the volume rendering in the horizontal, vertical, and
depth directions. If a scalar, assumes that the width is the same in</pre>
<ul><li><p>all three directions. If an interable, must contain only scalars or</p></li></ul>
<p>+            all three directions. If an iterable, must contain only scalars or</p>
<pre>(length, unit) tuples.
         """
         self.width = width</pre>
<p>@@ -378,7 +378,7 @@</p>
<pre>         width : number, YTQuantity, iterable, or 3 element YTArray
If a scalar, assumes that the position is the same in all three</pre>
<ul><li><p>coordinates. If an interable, must contain only scalars or</p></li></ul>
<p>+            coordinates. If an iterable, must contain only scalars or</p>
<pre>            (length, unit) tuples.

        north_vector : array_like, optional</pre>
<p>@@ -402,7 +402,7 @@</p>
<pre>         focus : number, YTQuantity, iterable, or 3 element YTArray
If a scalar, assumes that the focus is the same is all three</pre>
<ul><li><p>coordinates. If an interable, must contain only scalars or</p></li></ul>
<p>+            coordinates. If an iterable, must contain only scalars or</p>
<pre>            (length, unit) tuples.

        """</pre>
<p>@@ -470,7 +470,7 @@</p>
<pre>occur.  Defaults to None, which sets rotation around
`north_vector`
         rot_center  : array_like, optional</pre>
<ul><li><p>Specifiy the center around which rotation will occur. Defaults</p></li></ul>
<p>+            Specify the center around which rotation will occur. Defaults</p>
<pre>            to None, which sets rotation around the original camera position
            (i.e. the camera position does not change)
</pre>
<p>@@ -526,7 +526,7 @@</p>
<pre>         theta : float, in radians
Angle (in radians) by which to pitch the view.
         rot_center  : array_like, optional</pre>
<ul><li><p>Specifiy the center around which rotation will occur.</p></li></ul>
<p>+            Specify the center around which rotation will occur.</p>
<pre>Examples
--------</pre>
<p>@@ -554,7 +554,7 @@</p>
<pre>         theta : float, in radians
Angle (in radians) by which to yaw the view.
         rot_center  : array_like, optional</pre>
<ul><li><p>Specifiy the center around which rotation will occur.</p></li></ul>
<p>+            Specify the center around which rotation will occur.</p>
<pre>Examples
--------</pre>
<p>@@ -582,7 +582,7 @@</p>
<pre>         theta : float, in radians
Angle (in radians) by which to roll the view.
         rot_center  : array_like, optional</pre>
<ul><li><p>Specifiy the center around which rotation will occur.</p></li></ul>
<p>+            Specify the center around which rotation will occur.</p>
<pre>Examples
--------</pre>
<p>@@ -617,7 +617,7 @@</p>
<pre>occur.  Defaults to None, which sets rotation around the
original `north_vector`
         rot_center  : array_like, optional</pre>
<ul><li><p>Specifiy the center around which rotation will occur. Defaults</p></li></ul>
<p>+            Specify the center around which rotation will occur. Defaults</p>
<pre>            to None, which sets rotation around the original camera position
            (i.e. the camera position does not change)
</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/2350683ee8c9/">https://bitbucket.org/yt_analysis/yt/commits/2350683ee8c9/</a> Changeset:   2350683ee8c9 Branch:      yt User:        atmyers Date:        2016-04-13 16:42:50+00:00 Summary:     remove duplicate import Affected #:  1 file</p>
<p>diff -r 5ada8f62d1d6bfe88aa77d2be553c8364360f332 -r 2350683ee8c925c7ac8db99436e16291a05e2836 yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -9,7 +9,6 @@</p>
<pre>ElementSampler, \
Q1Sampler3D, \
P1Sampler3D, \</pre>
<ul><li><p>Q1Sampler3D, \ W1Sampler3D</p></li></ul>
<pre>cdef ElementSampler Q1Sampler = Q1Sampler3D()</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/248ccc5ef8b4/">https://bitbucket.org/yt_analysis/yt/commits/248ccc5ef8b4/</a> Changeset:   248ccc5ef8b4 Branch:      yt User:        ngoldbaum Date:        2016-04-20 18:22:12+00:00 Summary:     Merged in atmyers/yt (pull request #2107)</p>
<p>Allow MeshSources to optionally use the Cython ray-tracer instead of Embree. Affected #:  14 files</p>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/bounding_volume_hierarchy.pxd --- a/yt/utilities/lib/bounding_volume_hierarchy.pxd +++ b/yt/utilities/lib/bounding_volume_hierarchy.pxd @@ -1,6 +1,7 @@</p>
<pre>cimport cython
import numpy as np
cimport numpy as np</pre>
<p>+from yt.utilities.lib.element_mappings cimport ElementSampler</p>
<pre># ray data structure
cdef struct Ray:</pre>
<p>@@ -11,6 +12,7 @@</p>
<pre>np.float64_t t_near
np.float64_t t_far
np.int64_t elem_id</pre>
<p>+    np.int64_t near_boundary</p>
<pre># axis-aligned bounding box
cdef struct BBox:</pre>
<p>@@ -30,7 +32,6 @@</p>
<pre>np.float64_t p0[3]
np.float64_t p1[3]
np.float64_t p2[3]</pre>
<ul><li><p>np.float64_t d0, d1, d2 np.int64_t elem_id np.float64_t centroid[3] BBox bbox</p></li></ul>
<p>@@ -38,6 +39,14 @@</p>
<pre>cdef class BVH:
    cdef BVHNode* root
    cdef Triangle* triangles</pre>
<p>+    cdef np.float64_t* vertices +    cdef np.float64_t* field_data +    cdef np.int64_t num_tri_per_elem +    cdef np.int64_t num_tri +    cdef np.int64_t num_elem +    cdef np.int64_t num_verts_per_elem +    cdef np.int64_t num_field_per_elem +    cdef ElementSampler sampler</p>
<pre>     cdef np.int64_t _partition(self, np.int64_t begin, np.int64_t end,
np.int64_t ax, np.float64_t split) nogil
     cdef void intersect(self, Ray* ray) nogil</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/bounding_volume_hierarchy.pyx --- a/yt/utilities/lib/bounding_volume_hierarchy.pyx +++ b/yt/utilities/lib/bounding_volume_hierarchy.pyx @@ -1,10 +1,19 @@ -cimport cython +cimport cython</p>
<pre>import numpy as np
cimport numpy as np
from libc.math cimport fabs
from libc.stdlib cimport malloc, free
from cython.parallel import parallel, prange
from vec3_ops cimport dot, subtract, cross</pre>
<p>+from yt.utilities.lib.element_mappings cimport \ +    ElementSampler, \ +    Q1Sampler3D, \ +    P1Sampler3D, \ +    W1Sampler3D + +cdef ElementSampler Q1Sampler = Q1Sampler3D() +cdef ElementSampler P1Sampler = P1Sampler3D() +cdef ElementSampler W1Sampler = W1Sampler3D()</p>
<pre>cdef extern from "platform_dep.h" nogil:
    double fmax(double x, double y)</pre>
<p>@@ -13,7 +22,16 @@</p>
<pre>cdef extern from "mesh_construction.h":
    enum:
        MAX_NUM_TRI</pre>
<p>+ +    int HEX_NV +    int HEX_NT +    int TETRA_NV +    int TETRA_NT +    int WEDGE_NV +    int WEDGE_NT</p>
<pre>int triangulate_hex[MAX_NUM_TRI][3]</pre>
<p>+    int triangulate_tetra[MAX_NUM_TRI][3] +    int triangulate_wedge[MAX_NUM_TRI][3]</p>
<pre># define some constants
cdef np.float64_t DETERMINANT_EPS = 1.0e-10</pre>
<p>@@ -60,7 +78,6 @@</p>
<pre>if(t > DETERMINANT_EPS and t < ray.t_far):
    ray.t_far = t</pre>
<ul><li><p>ray.data_val = (1.0 – u – v)*tri.d0 + u*tri.d1 + v*tri.d2 ray.elem_id = tri.elem_id return True</p></li></ul>
<p>@@ -104,31 +121,62 @@</p>
<pre>@cython.wraparound(False)
@cython.cdivision(True)
def __cinit__(self,</pre>
<ul><li><p>np.float64_t[:, ::1] vertices,</p></li>
<li><p>np.int64_t[:, ::1] indices,</p></li>
<li><p>np.float64_t[:, ::1] field_data):</p></li></ul>
<p>+                  np.float64_t[:, :] vertices, +                  np.int64_t[:, :] indices, +                  np.float64_t[:, :] field_data):</p>
<ul><li><p>cdef np.int64_t num_elem = indices.shape[0]</p></li>
<li><p>cdef np.int64_t num_tri = 12*num_elem</p></li></ul>
<p>+        self.num_elem = indices.shape[0] +        self.num_verts_per_elem = indices.shape[1] +        self.num_field_per_elem = field_data.shape[1] + +        # We need to figure out what kind of elements we've been handed. +        cdef int[MAX_NUM_TRI][3] tri_array +        if self.num_verts_per_elem == 8: +            self.num_tri_per_elem = HEX_NT +            tri_array = triangulate_hex +            self.sampler = Q1Sampler +        elif self.num_verts_per_elem == 6: +            self.num_tri_per_elem = WEDGE_NT +            tri_array = triangulate_wedge +            self.sampler = W1Sampler +        elif self.num_verts_per_elem == 4: +            self.num_tri_per_elem = TETRA_NT +            tri_array = triangulate_tetra +            self.sampler = P1Sampler +        self.num_tri = self.num_tri_per_elem*self.num_elem + +        # allocate storage +        cdef np.int64_t v_size = self.num_verts_per_elem * self.num_elem * 3 +        self.vertices = <np.float64_t*> malloc(v_size * sizeof(np.float64_t)) +        cdef np.int64_t f_size = self.num_field_per_elem * self.num_elem +        self.field_data = <np.float64_t*> malloc(f_size * sizeof(np.float64_t)) + +        # create data buffers +        cdef np.int64_t i, j, k +        cdef np.int64_t field_offset, vertex_offset +        for i in range(self.num_elem): +            for j in range(self.num_verts_per_elem): +                vertex_offset = i*self.num_verts_per_elem*3 + j*3 +                for k in range(3): +                    self.vertices[vertex_offset + k] = vertices[indices[i,j]][k] +            field_offset = i*self.num_field_per_elem +            for j in range(self.num_field_per_elem): +                self.field_data[field_offset + j] = field_data[i][j]</p>
<pre># fill our array of triangles</pre>
<ul><li><p>cdef np.int64_t i, j, k cdef np.int64_t offset, tri_index cdef np.int64_t v0, v1, v2 cdef Triangle* tri</p></li>
<li><p>self.triangles = <Triangle*> malloc(num_tri * sizeof(Triangle))</p></li>
<li><p>for i in range(num_elem):</p></li>
<li><p>offset = 12*i</p></li>
<li><p>for j in range(12):</p></li></ul>
<p>+        self.triangles = <Triangle*> malloc(self.num_tri * sizeof(Triangle)) +        for i in range(self.num_elem): +            offset = self.num_tri_per_elem*i +            for j in range(self.num_tri_per_elem):</p>
<pre>tri_index = offset + j
tri = &(self.triangles[tri_index])
tri.elem_id = i</pre>
<ul><li><p>v0 = indices[i][triangulate_hex[j][0]]</p></li>
<li><p>v1 = indices[i][triangulate_hex[j][1]]</p></li>
<li><p>v2 = indices[i][triangulate_hex[j][2]]</p></li>
<li><p>tri.d0 = field_data[i][triangulate_hex[j][0]]</p></li>
<li><p>tri.d1 = field_data[i][triangulate_hex[j][1]]</p></li>
<li><p>tri.d2 = field_data[i][triangulate_hex[j][2]]</p></li></ul>
<p>+                v0 = indices[i][tri_array[j][0]] +                v1 = indices[i][tri_array[j][1]] +                v2 = indices[i][tri_array[j][2]]</p>
<pre>for k in range(3):
    tri.p0[k] = vertices[v0][k]
    tri.p1[k] = vertices[v1][k]</pre>
<p>@@ -137,7 +185,7 @@</p>
<pre>                    tri.bbox.left_edge[k]  = fmin(fmin(tri.p0[k], tri.p1[k]), tri.p2[k])
                    tri.bbox.right_edge[k] = fmax(fmax(tri.p0[k], tri.p1[k]), tri.p2[k])
</pre>
<ul><li><p>self.root = self._recursive_build(0, num_tri)</p></li></ul>
<p>+        self.root = self._recursive_build(0, self.num_tri)</p>
<pre>cdef void _recursive_free(self, BVHNode* node) nogil:
    if node.end - node.begin > LEAF_SIZE:</pre>
<p>@@ -148,6 +196,8 @@</p>
<pre>def __dealloc__(self):
    self._recursive_free(self.root)
    free(self.triangles)</pre>
<p>+        free(self.field_data) +        free(self.vertices)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -189,6 +239,28 @@</p>
<pre>@cython.cdivision(True)
cdef void intersect(self, Ray* ray) nogil:
    self._recursive_intersect(ray, self.root)</pre>
<p>+ +        if ray.elem_id < 0: +            return + +        cdef np.float64_t[3] position +        cdef np.int64_t i +        for i in range(3): +            position[i] = ray.origin[i] + ray.t_far*ray.direction[i] + +        cdef np.float64_t* vertex_ptr +        cdef np.float64_t* field_ptr +        vertex_ptr = self.vertices + ray.elem_id*self.num_verts_per_elem*3 +        field_ptr = self.field_data + ray.elem_id*self.num_field_per_elem + +        cdef np.float64_t[4] mapped_coord +        self.sampler.map_real_to_unit(mapped_coord, vertex_ptr, position) +        if self.num_field_per_elem == 1: +            ray.data_val = field_ptr[0] +        else: +            ray.data_val = self.sampler.sample_at_unit_point(mapped_coord, +                                                             field_ptr) +        ray.near_boundary = self.sampler.check_mesh_lines(mapped_coord)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -281,6 +353,7 @@</p>
<pre>ray.t_far = INF
ray.t_near = 0.0
ray.data_val = 0</pre>
<p>+            ray.elem_id = -1</p>
<pre>            bvh.intersect(ray)
            image[i] = ray.data_val
</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/element_mappings.pxd --- a/yt/utilities/lib/element_mappings.pxd +++ b/yt/utilities/lib/element_mappings.pxd @@ -35,6 +35,8 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil +</p>
<pre>cdef class P1Sampler2D(ElementSampler):
</pre>
<p>@@ -75,6 +77,8 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil +</p>
<pre># This typedef defines a function pointer that defines the system
# of equations that will be solved by the NonlinearSolveSamplers.</pre>
<p>@@ -170,6 +174,8 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil +</p>
<pre>cdef class W1Sampler3D(NonlinearSolveSampler3D):
</pre>
<p>@@ -190,6 +196,9 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil + +</p>
<pre>cdef class S2Sampler3D(NonlinearSolveSampler3D):
</pre>
<p>@@ -210,6 +219,9 @@</p>
<pre>                             double tolerance,
                             int direction) nogil
</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil + +</p>
<pre>cdef class NonlinearSolveSampler2D(ElementSampler):
</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/element_mappings.pyx --- a/yt/utilities/lib/element_mappings.pyx +++ b/yt/utilities/lib/element_mappings.pyx @@ -95,6 +95,12 @@</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>+    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        pass + +    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True)</p>
<pre>     cdef double sample_at_real_point(self,
double* vertices,
double* field_values,</pre>
<p>@@ -265,6 +271,37 @@</p>
<pre>            return 1
        return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        cdef double u, v, w +        cdef double thresh = 2.0e-2 +        if mapped_coord[0] == 0: +            u = mapped_coord[1] +            v = mapped_coord[2] +            w = mapped_coord[3] +        elif mapped_coord[1] == 0: +            u = mapped_coord[2] +            v = mapped_coord[3] +            w = mapped_coord[0] +        elif mapped_coord[2] == 0: +            u = mapped_coord[1] +            v = mapped_coord[3] +            w = mapped_coord[0] +        else: +            u = mapped_coord[1] +            v = mapped_coord[2] +            w = mapped_coord[0] +        if ((u < thresh) or +            (v < thresh) or +            (w < thresh) or +            (fabs(u – 1) < thresh) or +            (fabs(v – 1) < thresh) or +            (fabs(w – 1) < thresh)): +            return 1 +        return -1 +</p>
<pre>cdef class NonlinearSolveSampler3D(ElementSampler):
</pre>
<p>@@ -373,7 +410,6 @@</p>
<pre>            return 0
        return 1
</pre>
<p>–</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>@@ -386,6 +422,23 @@</p>
<pre>        else:
            return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +            fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        else: +            return -1 + +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -528,6 +581,22 @@</p>
<pre>        else:
            return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +            fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and +              fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1): +            return 1 +        else: +            return -1 +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -709,7 +778,6 @@</p>
<pre>            return 0
        return 1
</pre>
<p>–</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)</pre>
<p>@@ -726,6 +794,32 @@</p>
<pre>            return 1
        return 0
</pre>
<p>+    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    cdef int check_mesh_lines(self, double* mapped_coord) nogil: +        cdef double r, s, t +        cdef double thresh = 5.0e-2 +        r = mapped_coord[0] +        s = mapped_coord[1] +        t = mapped_coord[2] + +        cdef int near_edge_r, near_edge_s, near_edge_t +        near_edge_r = (r < thresh) or (fabs(r + s – 1.0) < thresh) +        near_edge_s = (s < thresh) +        near_edge_t = fabs(fabs(mapped_coord[2]) – 1.0) < thresh + +        # we use ray.instID to pass back whether the ray is near the +        # element boundary or not (used to annotate mesh lines) +        if (near_edge_r and near_edge_s): +            return 1 +        elif (near_edge_r and near_edge_t): +            return 1 +        elif (near_edge_s and near_edge_t): +            return 1 +        else: +            return -1 +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/grid_traversal.pxd --- a/yt/utilities/lib/grid_traversal.pxd +++ b/yt/utilities/lib/grid_traversal.pxd @@ -25,6 +25,8 @@</p>
<pre>np.float64_t *center
np.float64_t[:,:,:] image
np.float64_t[:,:] zbuffer</pre>
<p>+    np.int64_t[:,:] image_used +    np.int64_t[:,:] mesh_lines</p>
<pre>np.float64_t pdx, pdy
np.float64_t bounds[4]
np.float64_t[:,:] camera_data   # position, width, unit_vec[0,2]</pre>
<p>@@ -59,6 +61,8 @@</p>
<pre>cdef sampler_function *sampler
cdef public object acenter, aimage, ax_vec, ay_vec
cdef public object azbuffer</pre>
<p>+    cdef public object aimage_used +    cdef public object amesh_lines</p>
<pre>cdef void *supp_data
cdef np.float64_t width[3]
cdef public object lens_type</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/grid_traversal.pyx --- a/yt/utilities/lib/grid_traversal.pyx +++ b/yt/utilities/lib/grid_traversal.pyx @@ -383,6 +383,8 @@</p>
<pre>*args, **kwargs):
         self.image = <ImageContainer *> calloc(sizeof(ImageContainer), 1)
         cdef np.float64_t[:,:] zbuffer</pre>
<p>+        cdef np.int64_t[:,:] image_used +        cdef np.int64_t[:,:] mesh_lines</p>
<pre>        cdef np.float64_t[:,:] camera_data
        cdef int i
</pre>
<p>@@ -393,6 +395,10 @@</p>
<pre>         zbuffer = kwargs.pop("zbuffer", None)
         if zbuffer is None:
zbuffer = np.ones((image.shape[0], image.shape[1]), "float64")</pre>
<p>+ +        image_used = np.zeros((image.shape[0], image.shape[1]), “int64”) +        mesh_lines = np.zeros((image.shape[0], image.shape[1]), “int64”) +</p>
<pre>         self.lens_type = kwargs.pop("lens_type", None)
         if self.lens_type == "plane-parallel":
self.extent_function = calculate_extent_plane_parallel</pre>
<p>@@ -400,7 +406,7 @@</p>
<pre>         else:
if not (vp_pos.shape[0] == vp_dir.shape[0] == image.shape[0]) or \
   not (vp_pos.shape[1] == vp_dir.shape[1] == image.shape[1]):</pre>
<ul><li><p>msg = “Bad lense shape / direction for %s\n” % (self.lens_type)</p></li></ul>
<p>+                msg = “Bad lens shape / direction for %s\n” % (self.lens_type)</p>
<pre>msg += "Shapes: (%s - %s - %s) and (%s - %s - %s)" % (
    vp_pos.shape[0], vp_dir.shape[0], image.shape[0],
    vp_pos.shape[1], vp_dir.shape[1], image.shape[1])</pre>
<p>@@ -426,7 +432,9 @@</p>
<pre>self.image.x_vec = <np.float64_t *> x_vec.data
self.ay_vec = y_vec
self.image.y_vec = <np.float64_t *> y_vec.data</pre>
<ul><li><p>self.image.zbuffer = zbuffer</p></li></ul>
<p>+        self.image.zbuffer = self.azbuffer = zbuffer +        self.image.image_used = self.aimage_used = image_used +        self.image.mesh_lines = self.amesh_lines = mesh_lines</p>
<pre>self.image.nv[0] = image.shape[0]
self.image.nv[1] = image.shape[1]
for i in range(4): self.image.bounds[i] = bounds[i]</pre>
<p>@@ -501,6 +509,7 @@</p>
<pre>self.image.vp_dir = None
self.image.zbuffer = None
self.image.camera_data = None</pre>
<p>+        self.image.image_used = None</p>
<pre>        free(self.image)

</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/mesh_construction.pxd --- a/yt/utilities/lib/mesh_construction.pxd +++ b/yt/utilities/lib/mesh_construction.pxd @@ -11,6 +11,7 @@</p>
<pre>int* element_indices   # which vertices belong to which *element*
int tpe                # the number of triangles per element
int vpe                # the number of vertices per element</pre>
<p>+    int fpe                # the number of field values per element</p>
<pre>ctypedef struct Patch:
    float[8][3] v</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/mesh_construction.pyx --- a/yt/utilities/lib/mesh_construction.pyx +++ b/yt/utilities/lib/mesh_construction.pyx @@ -25,7 +25,6 @@</p>
<pre>from mesh_samplers cimport \
    sample_hex, \
    sample_tetra, \</pre>
<ul><li><p>sample_element, \ sample_wedge</p></li></ul>
<pre>from pyembree.rtcore cimport \
    Vertex, \</pre>
<p>@@ -104,7 +103,7 @@</p>
<pre>                 np.ndarray indices,
                 np.ndarray data):
</pre>
<ul><li><p># We need now to figure out what kind of elements we've been handed.</p></li></ul>
<p>+        # We need to figure out what kind of elements we've been handed.</p>
<pre>         if indices.shape[1] == 8:
self.vpe = HEX_NV
self.tpe = HEX_NT</pre>
<p>@@ -186,19 +185,18 @@</p>
<pre>datac.element_indices = self.element_indices
datac.tpe = self.tpe
datac.vpe = self.vpe</pre>
<p>+        datac.fpe = self.fpe</p>
<pre>        self.datac = datac
        
        rtcg.rtcSetUserData(scene.scene_i, self.mesh, &self.datac)

    cdef void _set_sampler_type(self, YTEmbreeScene scene):
</pre>
<ul><li><p>if self.fpe == 1:</p></li>
<li><p>self.filter_func = <rtcg.RTCFilterFunc> sample_element</p></li>
<li><p>elif self.fpe == 4:</p></li></ul>
<p>+        if self.vpe == 4:</p>
<pre>self.filter_func = <rtcg.RTCFilterFunc> sample_tetra</pre>
<ul><li><p>elif self.fpe == 6:</p></li></ul>
<p>+        elif self.vpe == 6:</p>
<pre>self.filter_func = <rtcg.RTCFilterFunc> sample_wedge</pre>
<ul><li><p>elif self.fpe == 8:</p></li></ul>
<p>+        elif self.vpe == 8:</p>
<pre>self.filter_func = <rtcg.RTCFilterFunc> sample_hex
         else:
raise NotImplementedError("Sampler type not implemented.")</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/mesh_samplers.pxd --- a/yt/utilities/lib/mesh_samplers.pxd +++ b/yt/utilities/lib/mesh_samplers.pxd @@ -13,6 +13,3 @@</p>
<pre>cdef void sample_hex20(void* userPtr,
                       rtcr.RTCRay& ray) nogil</pre>
<p>– -cdef void sample_element(void* userPtr,</p>
<ul><li><p>rtcr.RTCRay& ray) nogil</p></li></ul>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/mesh_samplers.pyx --- a/yt/utilities/lib/mesh_samplers.pyx +++ b/yt/utilities/lib/mesh_samplers.pyx @@ -97,7 +97,9 @@</p>
<pre>for i in range(8):
    element_indices[i] = data.element_indices[elem_id*8+i]</pre>
<ul><li><p>field_data[i]      = data.field_data[elem_id*8+i]</p></li></ul>
<p>+ +    for i in range(data.fpe): +        field_data[i] = data.field_data[elem_id*data.fpe+i]</p>
<pre>for i in range(8):
    vertices[i*3]     = data.vertices[element_indices[i]].x</pre>
<p>@@ -107,22 +109,16 @@</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[3]
Q1Sampler.map_real_to_unit(mapped_coord, vertices, position)</pre>
<ul><li><p>val = Q1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    if data.fpe == 1: +        val = field_data[0] +    else: +        val = Q1Sampler.sample_at_unit_point(mapped_coord, field_data)</p>
<pre>    ray.time = val

    # we use ray.instID to pass back whether the ray is near the
    # element boundary or not (used to annotate mesh lines)</pre>
<ul><li><p>if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>+    ray.instID = Q1Sampler.check_mesh_lines(mapped_coord) +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -152,7 +148,9 @@</p>
<pre>for i in range(6):
    element_indices[i] = data.element_indices[elem_id*6+i]</pre>
<ul><li><p>field_data[i]      = data.field_data[elem_id*6+i]</p></li></ul>
<p>+ +    for i in range(data.fpe): +        field_data[i] = data.field_data[elem_id*data.fpe+i]</p>
<pre>for i in range(6):
    vertices[i*3]     = data.vertices[element_indices[i]].x</pre>
<p>@@ -162,31 +160,12 @@</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[3]
W1Sampler.map_real_to_unit(mapped_coord, vertices, position)</pre>
<ul><li><p>val = W1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    if data.fpe == 1: +        val = field_data[0] +    else: +        val = W1Sampler.sample_at_unit_point(mapped_coord, field_data)</p>
<pre>ray.time = val</pre>
<p>–</p>
<ul><li><p>cdef double r, s, t</p></li>
<li><p>cdef double thresh = 5.0e-2</p></li>
<li><p>r = mapped_coord[0]</p></li>
<li><p>s = mapped_coord[1]</p></li>
<li><p>t = mapped_coord[2]</p></li></ul>
<p>–</p>
<ul><li><p>cdef int near_edge_r, near_edge_s, near_edge_t</p></li>
<li><p>near_edge_r = (r < thresh) or (fabs(r + s – 1.0) < thresh)</p></li>
<li><p>near_edge_s = (s < thresh)</p></li>
<li><p>near_edge_t = fabs(fabs(mapped_coord[2]) – 1.0) < thresh</p></li></ul>
<p>–</p>
<ul><li><p># we use ray.instID to pass back whether the ray is near the</p></li>
<li><p># element boundary or not (used to annotate mesh lines)</p></li>
<li><p>if (near_edge_r and near_edge_s):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (near_edge_r and near_edge_t):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (near_edge_s and near_edge_t):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>– +    ray.instID = W1Sampler.check_mesh_lines(mapped_coord)</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -222,21 +201,8 @@</p>
<pre>S2Sampler.map_real_to_unit(mapped_coord, patch.vertices, position)
val = S2Sampler.sample_at_unit_point(mapped_coord, patch.field_data)
ray.time = val</pre>
<p>–</p>
<ul><li><p># we use ray.instID to pass back whether the ray is near the</p></li>
<li><p># element boundary or not (used to annotate mesh lines)</p></li>
<li><p>if (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[0]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>elif (fabs(fabs(mapped_coord[1]) – 1.0) < 1e-1 and</p></li>
<li><p>fabs(fabs(mapped_coord[2]) – 1.0) < 1e-1):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>– +    ray.instID = S2Sampler.check_mesh_lines(mapped_coord) +</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -267,54 +233,19 @@</p>
<pre>for i in range(4):
    element_indices[i] = data.element_indices[elem_id*4+i]</pre>
<ul><li><p>field_data[i] = data.field_data[elem_id*4+i] vertices[i*3] = data.vertices[element_indices[i]].x vertices[i*3 + 1] = data.vertices[element_indices[i]].y vertices[i*3 + 2] = data.vertices[element_indices[i]].z</p></li></ul>
<p>+    for i in range(data.fpe): +        field_data[i] = data.field_data[elem_id*data.fpe+i] +</p>
<pre># we use ray.time to pass the value of the field
cdef double mapped_coord[4]
P1Sampler.map_real_to_unit(mapped_coord, vertices, position)</pre>
<ul><li><p>val = P1Sampler.sample_at_unit_point(mapped_coord, field_data)</p></li></ul>
<p>+    if data.fpe == 1: +        val = field_data[0] +    else: +        val = P1Sampler.sample_at_unit_point(mapped_coord, field_data)</p>
<pre>ray.time = val</pre>
<p>–</p>
<ul><li><p>cdef double u, v, w</p></li>
<li><p>cdef double thresh = 2.0e-2</p></li>
<li><p>u = ray.u</p></li>
<li><p>v = ray.v</p></li>
<li><p>w = 1.0 – u – v</p></li>
<li><p># we use ray.instID to pass back whether the ray is near the</p></li>
<li><p># element boundary or not (used to annotate mesh lines)</p></li>
<li><p>if ((u < thresh) or</p></li>
<li><p>(v < thresh) or</p></li>
<li><p>(w < thresh) or</p></li>
<li><p>(fabs(u – 1) < thresh) or</p></li>
<li><p>(fabs(v – 1) < thresh) or</p></li>
<li><p>(fabs(w – 1) < thresh)):</p></li>
<li><p>ray.instID = 1</p></li>
<li><p>else:</p></li>
<li><p>ray.instID = -1</p></li></ul>
<p>– – -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.cdivision(True) -cdef void sample_element(void* userPtr,</p>
<ul><li><p>rtcr.RTCRay& ray) nogil:</p></li>
<li><p>cdef int ray_id, elem_id</p></li>
<li><p>cdef double val</p></li>
<li><p>cdef MeshDataContainer* data</p></li></ul>
<p>–</p>
<ul><li><p>data = <MeshDataContainer*> userPtr</p></li>
<li><p>ray_id = ray.primID</p></li>
<li><p>if ray_id == -1:</p></li>
<li><p>return</p></li></ul>
<p>–</p>
<ul><li><p># ray_id records the id number of the hit according to</p></li>
<li><p># embree, in which the primitives are triangles. Here,</p></li>
<li><p># we convert this to the element id by dividing by the</p></li>
<li><p># number of triangles per element.</p></li>
<li><p>elem_id = ray_id / data.tpe</p></li></ul>
<p>–</p>
<ul><li><p>val = data.field_data[elem_id]</p></li>
<li><p>ray.time = val</p></li></ul>
<p>+    ray.instID = P1Sampler.check_mesh_lines(mapped_coord)</p>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/mesh_traversal.pyx --- a/yt/utilities/lib/mesh_traversal.pyx +++ b/yt/utilities/lib/mesh_traversal.pyx @@ -1,6 +1,6 @@</p>
<pre>"""</pre>
<p>-This file contains the MeshSampler class, which handles casting rays at a -MeshSource using pyembree. +This file contains the MeshSampler classes, which handles casting rays at a +mesh source using either pyembree or the cython ray caster.</p>
<pre>"""</pre>
<p>@@ -25,6 +25,7 @@</p>
<pre>    ImageContainer
from cython.parallel import prange, parallel, threadid
from yt.visualization.image_writer import apply_colormap</pre>
<p>+from yt.utilities.lib.bounding_volume_hierarchy cimport BVH, Ray</p>
<pre>rtc.rtcInit(NULL)
rtc.rtcSetErrorFunction(error_printer)</pre>
<p>@@ -42,11 +43,8 @@</p>
<pre>    def __dealloc__(self):
        rtcs.rtcDeleteScene(self.scene_i)
</pre>
<p>-cdef class MeshSampler(ImageSampler):</p>
<ul><li><p>cdef public object image_used</p></li>
<li><p>cdef public object mesh_lines</p></li>
<li><p>cdef public object zbuffer</p></li></ul>
<p>+cdef class EmbreeMeshSampler(ImageSampler):</p>
<pre>@cython.boundscheck(False)
@cython.wraparound(False)</pre>
<p>@@ -70,15 +68,10 @@</p>
<pre>         cdef np.float64_t width[3]
         for i in range(3):
width[i] = self.width[i]</pre>
<ul><li><p>cdef np.ndarray[np.float64_t, ndim=1] data cdef np.ndarray[np.int64_t, ndim=1] used nx = im.nv[0] ny = im.nv[1] size = nx * ny</p></li>
<li><p>used = np.empty(size, dtype="int64")</p></li>
<li><p>mesh = np.empty(size, dtype="int64")</p></li>
<li><p>data = np.empty(size, dtype="float64")</p></li>
<li><p>zbuffer = np.empty(size, dtype="float64") cdef rtcr.RTCRay ray v_pos = <np.float64_t *> malloc(3 * sizeof(np.float64_t)) v_dir = <np.float64_t *> malloc(3 * sizeof(np.float64_t))</p></li></ul>
<p>@@ -99,13 +92,65 @@</p>
<pre>ray.time = 0
ray.Ng[0] = 1e37  # we use this to track the hit distance
rtcs.rtcIntersect(scene.scene_i, ray)</pre>
<ul><li><p>data[j] = ray.time</p></li>
<li><p>used[j] = ray.primID</p></li>
<li><p>mesh[j] = ray.instID</p></li>
<li><p>zbuffer[j] = ray.tfar</p></li>
<li><p>self.aimage = data</p></li>
<li><p>self.image_used = used</p></li>
<li><p>self.mesh_lines = mesh</p></li>
<li><p>self.zbuffer = zbuffer</p></li></ul>
<p>+            im.image[vi, vj, 0] = ray.time +            im.image_used[vi, vj] = ray.primID +            im.mesh_lines[vi, vj] = ray.instID +            im.zbuffer[vi, vj] = ray.tfar</p>
<pre>free(v_pos)
free(v_dir)</pre>
<p>+ + +cdef class BVHMeshSampler(ImageSampler): + +    @cython.boundscheck(False) +    @cython.wraparound(False) +    @cython.cdivision(True) +    def __call__(self, +                 BVH bvh, +                 int num_threads = 0): +        ''' + +        This function is supposed to cast the rays and return the +        image. + +        ''' + +        cdef int vi, vj, i, j +        cdef ImageContainer <strong>im = self.image +        cdef np.float64_t *v_pos +        cdef np.float64_t *v_dir +        cdef np.int64_t nx, ny, size +        cdef np.float64_t width[3] +        for i in range(3): +            width[i] = self.width[i] +        cdef np.ndarray[np.float64_t, ndim=1] data +        cdef np.ndarray[np.int64_t, ndim=1] used +        nx = im.nv[0] +        ny = im.nv[1] +        size = nx * ny +        cdef Ray</strong> ray +        with nogil, parallel(): +            ray = <Ray *> malloc(sizeof(Ray)) +            v_pos = <np.float64_t *> malloc(3 * sizeof(np.float64_t)) +            v_dir = <np.float64_t *> malloc(3 * sizeof(np.float64_t)) +            for j in prange(size): +                vj = j % ny +                vi = (j – vj) / ny +                vj = vj +                self.vector_function(im, vi, vj, width, v_dir, v_pos) +                for i in range(3): +                    ray.origin[i] = v_pos[i] +                    ray.direction[i] = v_dir[i] +                    ray.inv_dir[i] = 1.0 / v_dir[i] +                ray.t_far = 1e37 +                ray.t_near = 0.0 +                ray.data_val = 0 +                ray.elem_id = -1 +                bvh.intersect(ray) +                im.image[vi, vj, 0] = ray.data_val +                im.image_used[vi, vj] = ray.elem_id +                im.mesh_lines[vi, vj] = ray.near_boundary +                im.zbuffer[vi, vj] = ray.t_far +            free(v_pos) +            free(v_dir) +            free(ray)</p>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/utilities/lib/pixelization_routines.pyx --- a/yt/utilities/lib/pixelization_routines.pyx +++ b/yt/utilities/lib/pixelization_routines.pyx @@ -20,6 +20,7 @@</p>
<pre>from yt.utilities.lib.fp_utils cimport fmin, fmax, i64min, i64max, imin, imax, fabs
from yt.utilities.exceptions import YTPixelizeError, \
    YTElementTypeNotRecognized</pre>
<p>+from libc.stdlib cimport malloc, free</p>
<pre>from vec3_ops cimport dot, cross, subtract
from yt.utilities.lib.element_mappings cimport \
    ElementSampler, \</pre>
<p>@@ -30,9 +31,6 @@</p>
<pre>    Q1Sampler2D, \
    W1Sampler3D
</pre>
<p>-cdef extern from “stdlib.h”:</p>
<ul><li><p># NOTE that size_t might not be int</p></li>
<li><p>void *alloca(int)</p></li></ul>
<pre>cdef extern from "pixelization_constants.h":
    enum:</pre>
<p>@@ -573,8 +571,7 @@</p>
<pre>cdef int nvertices = conn.shape[1]
cdef int ndim = coords.shape[1]
cdef int num_field_vals = field.shape[1]</pre>
<ul><li><p>cdef double* mapped_coord</p></li>
<li><p>cdef int num_mapped_coords</p></li></ul>
<p>+    cdef double[4] mapped_coord</p>
<pre>    cdef ElementSampler sampler

    # Pick the right sampler and allocate storage for the mapped coordinate</pre>
<p>@@ -617,10 +614,8 @@</p>
<pre>        raise RuntimeError

    # allocate temporary storage</pre>
<ul><li><p>num_mapped_coords = sampler.num_mapped_coords</p></li>
<li><p>mapped_coord = <double*> alloca(sizeof(double) * num_mapped_coords)</p></li>
<li><p>vertices = <np.float64_t *> alloca(ndim * sizeof(np.float64_t) * nvertices)</p></li>
<li><p>field_vals = <np.float64_t *> alloca(sizeof(np.float64_t) * num_field_vals)</p></li></ul>
<p>+    vertices = <np.float64_t *> malloc(ndim * sizeof(np.float64_t) * nvertices) +    field_vals = <np.float64_t *> malloc(sizeof(np.float64_t) * num_field_vals)</p>
<pre># fill the image bounds and pixel size informaton here
for i in range(ndim):</pre>
<p>@@ -691,4 +686,7 @@</p>
<pre>    img[pi, pj, pk] = 1.0
elif sampler.check_near_edge(mapped_coord, thresh, yax):
    img[pi, pj, pk] = 1.0</pre>
<p>+ +    free(vertices) +    free(field_vals)</p>
<pre>return img</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/visualization/volume_rendering/render_source.py --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -24,6 +24,7 @@</p>
<pre>from .utils import new_volume_render_sampler, data_source_or_all, \
    get_corners, new_projection_sampler, new_mesh_sampler, \
    new_interpolated_projection_sampler</pre>
<p>+from yt.utilities.lib.bounding_volume_hierarchy import BVH</p>
<pre>from yt.visualization.image_writer import apply_colormap
from yt.data_objects.image_array import ImageArray
from .zbuffer_array import ZBuffer</pre>
<p>@@ -353,8 +354,9 @@</p>
<pre>self.data_source = data_source_or_all(data_source)
field = self.data_source._determine_fields(field)[0]
self.field = field</pre>
<ul><li><p>self.mesh = None</p></li></ul>
<p>+        self.volume = None</p>
<pre>self.current_image = None</pre>
<p>+        self.engine = ‘embree’</p>
<pre># default color map
self._cmap = ytcfg.get("yt", "default_colormap")</pre>
<p>@@ -369,8 +371,14 @@</p>
<pre>        assert(self.field is not None)
        assert(self.data_source is not None)
</pre>
<ul><li><p>self.scene = mesh_traversal.YTEmbreeScene()</p></li>
<li><p>self.build_mesh()</p></li></ul>
<p>+        if self.engine == ‘embree’: +            self.volume = mesh_traversal.YTEmbreeScene() +            self.build_volume_embree() +        elif self.engine == ‘bvh’: +            self.build_volume_bvh() +        else: +            raise NotImplementedError("Invalid ray-tracing engine selected. " +                                      “Choices are ‘embree’ and 'bvh'.”)</p>
<pre>def cmap():
    '''</pre>
<p>@@ -410,12 +418,60 @@</p>
<pre>def _validate(self):
    """Make sure that all dependencies have been met"""
    if self.data_source is None:</pre>
<ul><li><p>raise RuntimeError("Data source not initialized")</p></li></ul>
<p>+            raise RuntimeError("Data source not initialized.")</p>
<ul><li><p>if self.mesh is None:</p></li>
<li><p>raise RuntimeError("Mesh not initialized")</p></li></ul>
<p>+        if self.volume is None: +            raise RuntimeError("Volume not initialized.")</p>
<ul><li><p>def build_mesh(self):</p></li></ul>
<p>+    def build_volume_embree(self): +        """ + +        This constructs the mesh that will be ray-traced by pyembree. + +        """ +        ftype, fname = self.field +        mesh_id = int(ftype[-1]) – 1 +        index = self.data_source.ds.index +        offset = index.meshes[mesh_id]._index_offset +        field_data = self.data_source[self.field].d  # strip units + +        vertices = index.meshes[mesh_id].connectivity_coords +        indices = index.meshes[mesh_id].connectivity_indices – offset + +        # if this is an element field, promote to 2D here +        if len(field_data.shape) == 1: +            field_data = np.expand_dims(field_data, 1) + +        # Here, we decide whether to render based on high-order or +        # low-order geometry. Right now, high-order geometry is only +        # implemented for 20-point hexes. +        if indices.shape[1] == 20: +            self.mesh = mesh_construction.QuadraticElementMesh(self.volume, +                                                               vertices, +                                                               indices, +                                                               field_data) +        else: +            # if this is another type of higher-order element, we demote +            # to 1st order here, for now. +            if indices.shape[1] == 27: +                # hexahedral +                mylog.warning("27-node hexes not yet supported, " + +                              “dropping to 1st order.”) +                field_data = field_data[:, 0:8] +                indices = indices[:, 0:8] +            elif indices.shape[1] == 10: +                # tetrahedral +                mylog.warning("10-node tetrahedral elements not yet supported, " + +                              “dropping to 1st order.”) +                field_data = field_data[:, 0:4] +                indices = indices[:, 0:4] + +            self.mesh = mesh_construction.LinearElementMesh(self.volume, +                                                            vertices, +                                                            indices, +                                                            field_data) + +    def build_volume_bvh(self):</p>
<pre>        """

        This constructs the mesh that will be ray-traced.</pre>
<p>@@ -436,32 +492,27 @@</p>
<pre># Here, we decide whether to render based on high-order or
# low-order geometry. Right now, high-order geometry is only</pre>
<ul><li><p># implemented for 20-point hexes.</p></li></ul>
<p>+        # supported by Embree.</p>
<pre>if indices.shape[1] == 20:</pre>
<ul><li><p>self.mesh = mesh_construction.QuadraticElementMesh(self.scene,</p></li>
<li><p>vertices,</p></li>
<li><p>indices,</p></li>
<li><p>field_data)</p></li>
<li><p>else:</p></li>
<li><p># if this is another type of higher-order element, we demote</p></li>
<li><p># to 1st order here, for now.</p></li>
<li><p>if indices.shape[1] == 27:</p></li>
<li><p># hexahedral</p></li>
<li><p>mylog.warning("27-node hexes not yet supported, " +</p></li>
<li><p>“dropping to 1st order.”)</p></li>
<li><p>field_data = field_data[:, 0:8]</p></li>
<li><p>indices = indices[:, 0:8]</p></li>
<li><p>elif indices.shape[1] == 10:</p></li>
<li><p># tetrahedral</p></li>
<li><p>mylog.warning("10-node tetrahedral elements not yet supported, " +</p></li>
<li><p>“dropping to 1st order.”)</p></li>
<li><p>field_data = field_data[:, 0:4]</p></li>
<li><p>indices = indices[:, 0:4]</p></li></ul>
<p>+            # hexahedral +            mylog.warning("20-node hexes not yet supported, " + +                          “dropping to 1st order.”) +            field_data = field_data[:, 0:8] +            indices = indices[:, 0:8] +        elif indices.shape[1] == 27: +            # hexahedral +            mylog.warning("27-node hexes not yet supported, " + +                          “dropping to 1st order.”) +            field_data = field_data[:, 0:8] +            indices = indices[:, 0:8] +        elif indices.shape[1] == 10: +            # tetrahedral +            mylog.warning("10-node tetrahedral elements not yet supported, " + +                          “dropping to 1st order.”) +            field_data = field_data[:, 0:4] +            indices = indices[:, 0:4]</p>
<ul><li><p>self.mesh = mesh_construction.LinearElementMesh(self.scene,</p></li>
<li><p>vertices,</p></li>
<li><p>indices,</p></li>
<li><p>field_data)</p></li></ul>
<p>+        self.volume = BVH(vertices, indices, field_data)</p>
<pre>def render(self, camera, zbuffer=None):
    """Renders an image using the provided camera</pre>
<p>@@ -495,18 +546,17 @@</p>
<pre>                              zbuffer.z.reshape(shape[:2]))
        self.zbuffer = zbuffer
</pre>
<ul><li><p>self.sampler = new_mesh_sampler(camera, self)</p></li></ul>
<p>+        self.sampler = new_mesh_sampler(camera, self, engine=self.engine)</p>
<pre>mylog.debug("Casting rays")</pre>
<ul><li><p>self.sampler(self.scene)</p></li></ul>
<p>+        self.sampler(self.volume)</p>
<pre>        mylog.debug("Done casting rays")

        self.finalize_image(camera)</pre>
<ul><li><p>self.data = self.sampler.aimage self.current_image = self.apply_colormap()</p>
<p>zbuffer += ZBuffer(self.current_image.astype('float64'),</p></li>
<li><p>self.sampler.zbuffer)</p></li></ul>
<p>+                           self.sampler.azbuffer)</p>
<pre>zbuffer.rgba = ImageArray(zbuffer.rgba)
self.zbuffer = zbuffer
self.current_image = self.zbuffer.rgba</pre>
<p>@@ -523,16 +573,13 @@</p>
<pre># reshape data
Nx = camera.resolution[0]
Ny = camera.resolution[1]</pre>
<ul><li><p>sam.aimage = sam.aimage.reshape(Nx, Ny)</p></li>
<li><p>sam.image_used = sam.image_used.reshape(Nx, Ny)</p></li>
<li><p>sam.mesh_lines = sam.mesh_lines.reshape(Nx, Ny)</p></li>
<li><p>sam.zbuffer = sam.zbuffer.reshape(Nx, Ny)</p></li></ul>
<p>+        self.data = sam.aimage[:,:,0].reshape(Nx, Ny)</p>
<pre># rotate</pre>
<ul><li><p>sam.aimage = np.rot90(sam.aimage, k=2)</p></li>
<li><p>sam.image_used = np.rot90(sam.image_used, k=2)</p></li>
<li><p>sam.mesh_lines = np.rot90(sam.mesh_lines, k=2)</p></li>
<li><p>sam.zbuffer = np.rot90(sam.zbuffer, k=2)</p></li></ul>
<p>+        self.data = np.rot90(self.data, k=2) +        sam.aimage_used = np.rot90(sam.aimage_used, k=2) +        sam.amesh_lines = np.rot90(sam.amesh_lines, k=2) +        sam.azbuffer = np.rot90(sam.azbuffer, k=2)</p>
<pre>def annotate_mesh_lines(self, color=None, alpha=1.0):
    r"""</pre>
<p>@@ -558,7 +605,7 @@</p>
<pre>        if color is None:
            color = np.array([0, 0, 0, alpha])
</pre>
<ul><li><p>locs = [self.sampler.mesh_lines == 1]</p></li></ul>
<p>+        locs = [self.sampler.amesh_lines == 1]</p>
<pre>self.current_image[:, :, 0][locs] = color[0]
self.current_image[:, :, 1][locs] = color[1]</pre>
<p>@@ -592,7 +639,7 @@</p>
<pre>color_bounds=self._color_bounds,
cmap_name=self._cmap)/255.
         alpha = image[:, :, 3]</pre>
<ul><li><p>alpha[self.sampler.image_used == -1] = 0.0</p></li></ul>
<p>+        alpha[self.sampler.aimage_used == -1] = 0.0</p>
<pre>        image[:, :, 3] = alpha
        return image
</pre>
<p>diff -r 5d118c06fa7eecc494eff5d231ebf3c47d9d4ab9 -r 248ccc5ef8b46d83682344d249c8de1c964759ab yt/visualization/volume_rendering/utils.py --- a/yt/visualization/volume_rendering/utils.py +++ b/yt/visualization/volume_rendering/utils.py @@ -14,7 +14,7 @@</p>
<pre>    return data_source

</pre>
<p>-def new_mesh_sampler(camera, render_source): +def new_mesh_sampler(camera, render_source, engine):</p>
<pre>params = ensure_code_unit_params(camera._get_sampler_params(render_source))
args = (
    np.atleast_3d(params['vp_pos']),</pre>
<p>@@ -27,7 +27,10 @@</p>
<pre>    params['width'],
)
kwargs = {'lens_type': params['lens_type']}</pre>
<ul><li><p>sampler = mesh_traversal.MeshSampler(*args, **kwargs)</p></li></ul>
<p>+    if engine == ‘embree’: +        sampler = mesh_traversal.EmbreeMeshSampler(*args, **kwargs) +    elif engine == ‘bvh’: +        sampler = mesh_traversal.BVHMeshSampler(*args, **kwargs)</p>
<pre>return sampler</pre>
<p>Repository URL: <a href="https://bitbucket.org/yt_analysis/yt/">https://bitbucket.org/yt_analysis/yt/</a></p>
<p>—</p>
<p>This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.</p>

<img src="http://link.bitbucket.org/wf/open?upn=ll4ctv0L-2ByeRZFC1LslHcg6aJmnQ70VruLbmeLQr27AjYAOtThjzbMF4GW9cGgz1yedEPXs3m-2FWlkc04gXWyuwRDY6l1LAoixt9-2FPEdgzSrOVCJqel8aCPiEYUQp8NdfC-2BWBp8XbAg-2BUxGMYIKEeIlMNsh-2FzfpV4SUQwYu0qxsiTTPvBKhaZ15PoYcv5jFtniZSRHMsqo0q7mt7Em-2B9TQD9vJi6hM1bMlW8BpFnlYIk-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;"/>
</body></html>