Example #1
0
 def deposit(self,
             positions,
             fields=None,
             method=None,
             kernel_name="cubic"):
     # Here we perform our particle deposition.
     if fields is None:
         fields = []
     cls = getattr(particle_deposit, f"deposit_{method}", None)
     if cls is None:
         raise YTParticleDepositionNotImplemented(method)
     nz = self.nz
     nvals = (nz, nz, nz, self.ires.size)
     # We allocate number of zones, not number of octs
     op = cls(nvals, kernel_name)
     op.initialize()
     mylog.debug(
         "Depositing %s (%s^3) particles into %s Root Mesh",
         positions.shape[0],
         positions.shape[0]**0.3333333,
         nvals[-1],
     )
     pos = np.array(positions, dtype="float64")
     f64 = [np.array(f, dtype="float64") for f in fields]
     self.oct_handler.deposit(op, self.base_selector, pos, f64)
     vals = op.finalize()
     if vals is None:
         return
     return np.asfortranarray(vals)
Example #2
0
 def deposit(self,
             positions,
             fields=None,
             method=None,
             kernel_name="cubic"):
     # Here we perform our particle deposition.
     cls = getattr(particle_deposit, f"deposit_{method}", None)
     if cls is None:
         raise YTParticleDepositionNotImplemented(method)
     # We allocate number of zones, not number of octs. Everything
     # inside this is Fortran ordered because of the ordering in the
     # octree deposit routines, so we reverse it here to match the
     # convention there
     nvals = tuple(self.ActiveDimensions[::-1])
     # append a dummy dimension because we are only depositing onto
     # one grid
     op = cls(nvals + (1, ), kernel_name)
     op.initialize()
     op.process_grid(self, positions, fields)
     vals = op.finalize()
     if vals is None:
         return
     # Fortran-ordered, so transpose.
     vals = vals.transpose()
     # squeeze dummy dimension we appended above
     return np.squeeze(vals, axis=0)
Example #3
0
    def deposit(self,
                positions,
                fields=None,
                method=None,
                kernel_name='cubic'):
        r"""Operate on the mesh, in a particle-against-mesh fashion, with
        exclusively local input.

        This uses the octree indexing system to call a "deposition" operation
        (defined in yt/geometry/particle_deposit.pyx) that can take input from
        several particles (local to the mesh) and construct some value on the
        mesh.  The canonical example is to sum the total mass in a mesh cell
        and then divide by its volume.

        Parameters
        ----------
        positions : array_like (Nx3)
            The positions of all of the particles to be examined.  A new
            indexed octree will be constructed on these particles.
        fields : list of arrays
            All the necessary fields for computing the particle operation.  For
            instance, this might include mass, velocity, etc.
        method : string
            This is the "method name" which will be looked up in the
            `particle_deposit` namespace as `methodname_deposit`.  Current
            methods include `count`, `simple_smooth`, `sum`, `std`, `cic`,
            `weighted_mean`, `mesh_id`, and `nearest`.
        kernel_name : string, default 'cubic'
            This is the name of the smoothing kernel to use. Current supported
            kernel names include `cubic`, `quartic`, `quintic`, `wendland2`,
            `wendland4`, and `wendland6`.

        Returns
        -------
        List of fortran-ordered, mesh-like arrays.
        """
        # Here we perform our particle deposition.
        if fields is None: fields = []
        cls = getattr(particle_deposit, "deposit_%s" % method, None)
        if cls is None:
            raise YTParticleDepositionNotImplemented(method)
        nz = self.nz
        nvals = (nz, nz, nz, (self.domain_ind >= 0).sum())
        # We allocate number of zones, not number of octs
        op = cls(nvals, kernel_name)
        op.initialize()
        mylog.debug("Depositing %s (%s^3) particles into %s Octs",
                    positions.shape[0], positions.shape[0]**0.3333333,
                    nvals[-1])
        pos = np.asarray(positions.convert_to_units("code_length"),
                         dtype="float64")
        # We should not need the following if we know in advance all our fields
        # need no casting.
        fields = [np.ascontiguousarray(f, dtype="float64") for f in fields]
        op.process_octree(self.oct_handler, self.domain_ind, pos, fields,
                          self.domain_id, self._domain_offset)
        vals = op.finalize()
        if vals is None: return
        return np.asfortranarray(vals)
 def deposit(self, positions, fields = None, method = None):
     raise NotImplementedError
     # Here we perform our particle deposition.
     cls = getattr(particle_deposit, "deposit_%s" % method, None)
     if cls is None:
         raise YTParticleDepositionNotImplemented(method)
     op = cls(self.ActiveDimensions.prod()) # We allocate number of zones, not number of octs
     op.initialize()
     op.process_grid(self, positions, fields)
     vals = op.finalize()
     if vals is None: return
     return vals.reshape(self.ActiveDimensions, order="C")
Example #5
0
 def deposit(self, positions, fields = None, method = None,
             kernel_name = 'cubic'):
     # Here we perform our particle deposition.
     cls = getattr(particle_deposit, "deposit_%s" % method, None)
     if cls is None:
         raise YTParticleDepositionNotImplemented(method)
     # We allocate number of zones, not number of octs
     # Everything inside this is fortran ordered, so we reverse it here.
     op = cls(tuple(self.ActiveDimensions)[::-1], kernel_name)
     op.initialize()
     op.process_grid(self, positions, fields)
     vals = op.finalize()
     if vals is None: return
     return vals.transpose() # Fortran-ordered, so transpose.
Example #6
0
 def deposit(self, positions, fields = None, method = None,
             kernel_name = 'cubic'):
     # Here we perform our particle deposition.
     cls = getattr(particle_deposit, "deposit_%s" % method, None)
     if cls is None:
         raise YTParticleDepositionNotImplemented(method)
     # We allocate number of zones, not number of octs. Everything inside
     # this is Fortran ordered because of the ordering in the octree deposit
     # routines, so we reverse it here to match the convention there
     op = cls(tuple(self.ActiveDimensions[::-1]), kernel_name)
     op.initialize()
     op.process_grid(self, positions, fields)
     vals = op.finalize()
     if vals is None: return
     # Fortran-ordered, so transpose.
     return vals.transpose()
Example #7
0
    def particle_operation(self,
                           positions,
                           fields=None,
                           method=None,
                           nneighbors=64,
                           kernel_name='cubic'):
        r"""Operate on particles, in a particle-against-particle fashion.

        This uses the octree indexing system to call a "smoothing" operation
        (defined in yt/geometry/particle_smooth.pyx) that expects to be called
        in a particle-by-particle fashion.  For instance, the canonical example
        of this would be to compute the Nth nearest neighbor, or to compute the
        density for a given particle based on some kernel operation.

        Many of the arguments to this are identical to those used in the smooth
        and deposit functions.  Note that the `fields` argument must not be
        empty, as these fields will be modified in place.

        Parameters
        ----------
        positions : array_like (Nx3)
            The positions of all of the particles to be examined.  A new
            indexed octree will be constructed on these particles.
        fields : list of arrays
            All the necessary fields for computing the particle operation.  For
            instance, this might include mass, velocity, etc.  One of these
            will likely be modified in place.
        method : string
            This is the "method name" which will be looked up in the
            `particle_smooth` namespace as `methodname_smooth`.
        nneighbors : int, default 64
            The number of neighbors to examine during the process.
        kernel_name : string, default 'cubic'
            This is the name of the smoothing kernel to use. Current supported
            kernel names include `cubic`, `quartic`, `quintic`, `wendland2`,
            `wendland4`, and `wendland6`.

        Returns
        -------
        Nothing.

        """
        # Here we perform our particle deposition.
        positions.convert_to_units("code_length")
        morton = compute_morton(positions[:, 0], positions[:, 1],
                                positions[:, 2], self.ds.domain_left_edge,
                                self.ds.domain_right_edge)
        morton.sort()
        particle_octree = ParticleOctreeContainer([1, 1, 1],
                                                  self.ds.domain_left_edge,
                                                  self.ds.domain_right_edge,
                                                  over_refine=1)
        particle_octree.n_ref = nneighbors * 2
        particle_octree.add(morton)
        particle_octree.finalize()
        pdom_ind = particle_octree.domain_ind(self.selector)
        if fields is None: fields = []
        cls = getattr(particle_smooth, "%s_smooth" % method, None)
        if cls is None:
            raise YTParticleDepositionNotImplemented(method)
        nz = self.nz
        mdom_ind = self.domain_ind
        nvals = (nz, nz, nz, (mdom_ind >= 0).sum())
        op = cls(nvals, len(fields), nneighbors, kernel_name)
        op.initialize()
        mylog.debug("Smoothing %s particles into %s Octs", positions.shape[0],
                    nvals[-1])
        op.process_particles(particle_octree, pdom_ind, positions, fields,
                             self.domain_id, self._domain_offset,
                             self.ds.periodicity, self.ds.geometry)
        vals = op.finalize()
        if vals is None: return
        if isinstance(vals, list):
            vals = [np.asfortranarray(v) for v in vals]
        else:
            vals = np.asfortranarray(vals)
        return vals
Example #8
0
    def smooth(self,
               positions,
               fields=None,
               index_fields=None,
               method=None,
               create_octree=False,
               nneighbors=64,
               kernel_name='cubic'):
        r"""Operate on the mesh, in a particle-against-mesh fashion, with
        non-local input.

        This uses the octree indexing system to call a "smoothing" operation
        (defined in yt/geometry/particle_smooth.pyx) that can take input from
        several (non-local) particles and construct some value on the mesh.
        The canonical example is to conduct a smoothing kernel operation on the
        mesh.

        Parameters
        ----------
        positions : array_like (Nx3)
            The positions of all of the particles to be examined.  A new
            indexed octree will be constructed on these particles.
        fields : list of arrays
            All the necessary fields for computing the particle operation.  For
            instance, this might include mass, velocity, etc.
        index_fields : list of arrays
            All of the fields defined on the mesh that may be used as input to
            the operation.
        method : string
            This is the "method name" which will be looked up in the
            `particle_smooth` namespace as `methodname_smooth`.  Current
            methods include `volume_weighted`, `nearest`, `idw`,
            `nth_neighbor`, and `density`.
        create_octree : bool
            Should we construct a new octree for indexing the particles?  In
            cases where we are applying an operation on a subset of the
            particles used to construct the mesh octree, this will ensure that
            we are able to find and identify all relevant particles.
        nneighbors : int, default 64
            The number of neighbors to examine during the process.
        kernel_name : string, default 'cubic'
            This is the name of the smoothing kernel to use. Current supported
            kernel names include `cubic`, `quartic`, `quintic`, `wendland2`,
            `wendland4`, and `wendland6`.

        Returns
        -------
        List of fortran-ordered, mesh-like arrays.
        """
        # Here we perform our particle deposition.
        positions.convert_to_units("code_length")
        if create_octree:
            morton = compute_morton(positions[:, 0], positions[:, 1],
                                    positions[:, 2], self.ds.domain_left_edge,
                                    self.ds.domain_right_edge)
            morton.sort()
            particle_octree = ParticleOctreeContainer(
                [1, 1, 1],
                self.ds.domain_left_edge,
                self.ds.domain_right_edge,
                over_refine=self._oref)
            # This should ensure we get everything within one neighbor of home.
            particle_octree.n_ref = nneighbors * 2
            particle_octree.add(morton)
            particle_octree.finalize()
            pdom_ind = particle_octree.domain_ind(self.selector)
        else:
            particle_octree = self.oct_handler
            pdom_ind = self.domain_ind
        if fields is None: fields = []
        if index_fields is None: index_fields = []
        cls = getattr(particle_smooth, "%s_smooth" % method, None)
        if cls is None:
            raise YTParticleDepositionNotImplemented(method)
        nz = self.nz
        mdom_ind = self.domain_ind
        nvals = (nz, nz, nz, (mdom_ind >= 0).sum())
        op = cls(nvals, len(fields), nneighbors, kernel_name)
        op.initialize()
        mylog.debug("Smoothing %s particles into %s Octs", positions.shape[0],
                    nvals[-1])
        # Pointer operations within 'process_octree' require arrays to be
        # contiguous cf. https://bitbucket.org/yt_analysis/yt/issues/1079
        fields = [np.ascontiguousarray(f, dtype="float64") for f in fields]
        op.process_octree(self.oct_handler, mdom_ind, positions, self.fcoords,
                          fields, self.domain_id, self._domain_offset,
                          self.ds.periodicity, index_fields, particle_octree,
                          pdom_ind, self.ds.geometry)
        # If there are 0s in the smoothing field this will not throw an error,
        # but silently return nans for vals where dividing by 0
        # Same as what is currently occurring, but suppressing the div by zero
        # error.
        with np.errstate(invalid='ignore'):
            vals = op.finalize()
        if vals is None: return
        if isinstance(vals, list):
            vals = [np.asfortranarray(v) for v in vals]
        else:
            vals = np.asfortranarray(vals)
        return vals