Source code for nbodykit.algorithms.kdtree

import os
import numpy
import logging

from nbodykit.utils import split_size_3d
from pmesh.domain import GridND
from scipy.spatial.ckdtree import cKDTree as KDTree

[docs]class KDDensity(object): """ Estimate a proxy density based on the distance to the nearest neighbor. The result is proportional to the density but the scale is unspecified. Results are computed when the object is inititalized. See the documenation of :func:`~KDDensity.run` for the attributes storing the results. Parameters ---------- source : CatalogSource the input source of particles to compute the proxy density on; must specify the 'Position' column margin: float, optional Padding region per parallel domain; relative to the mean seperation """ logger = logging.getLogger('KDDensity') def __init__(self, source, margin=1.0): if 'Position' not in source: raise ValueError("please specify the 'Position' column in the input source") self.comm = source.comm self._source = source if 'BoxSize' not in self._source.attrs: raise ValueError("please specify 'BoxSize' in the input source 'attrs'") BoxSize = numpy.array(self._source.attrs['BoxSize'], dtype='f8') if BoxSize.ndim == 0 or len(BoxSize) == 1: # catch some common problems about BoxSize. BoxSize = numpy.array([BoxSize, BoxSize, BoxSize]) # store some meta-data self.attrs = {} self.attrs['BoxSize'] = BoxSize self.attrs['meansep'] = (self._source.csize / BoxSize.prod()) ** (1.0 / len(BoxSize)) self.attrs['margin'] = margin # run the algorithm self.run()
[docs] def run(self): """ Compute the density proxy. This attaches the following attribute: - :attr:`density` Attributes ---------- density : array_like, length: :attr:`size` a unit-less, proxy density value for each object on the local rank. This is computed as the inverse cube of the distance to the closest, nearest neighbor """ # do the domain decomposition Np = split_size_3d(self.comm.size) edges = [numpy.linspace(0, self.attrs['BoxSize'][d], Np[d] + 1, endpoint=True) for d in range(3)] domain = GridND(comm=self.comm, periodic=True, edges=edges) # read all position and exchange pos = self._source.compute(self._source['Position']) layout = domain.decompose(pos, smoothing=self.attrs['margin'] * self.attrs['meansep']) xpos = layout.exchange(pos) # wait for scipy 0.19.1 assert all(self.attrs['BoxSize'] == self.attrs['BoxSize'][0]) xpos[...] /= self.attrs['BoxSize'] xpos %= 1 # KDTree tree = KDTree(xpos, boxsize=1.0) d, i = tree.query(xpos, k=[8]) d = d[:, 0] # gather back to original root, taking the minimum distance d = layout.gather(d, mode=numpy.fmin) self.density = 1 / (d ** 3 * self.attrs['BoxSize'].prod())