MeshSource
?¶Often in large-scale structure data analysis, we wish to manipulate
representations of continuous quantities on a discrete grid. The canonical
example is the analysis of the cosmological density field,
interpolated on to a 3D mesh from a discrete set of galaxies. To support
such calculations, nbodykit provides the
nbodykit.base.mesh.MeshSource
object.
Fundamentally, the MeshSource
object stores a (possibly weighted)
density field on a three-dimensional mesh, with the Nmesh
parameter
determining the number of grid cells per side (such that there are
\(\mathrm{Nmesh}^3\) mesh cells). nbodykit adds the functionality
to analyze these fields in both configuration space (often referred
to real space) and Fourier space through an interface to the
RealField
and ComplexField
objects
implemented by the pmesh
package. These objects are
paired classes, related through the operation of a 3D
fast Fourier transform
(FFT). The FFT operation implemented in pmesh
relies on
the pfft-python package, which
is a Python binding of PFFT, a massively parallel
FFT library.
The MeshSource
is an abstract base class – it cannot be directly
initialized. Instead, nbodykit includes several specialized subclasses of
MeshSource
in the nbodykit.source.mesh
module. In general,
these subclasses fall into three categories:
CatalogSource
(see Converting a CatalogSource to a Mesh)The MeshSource.paint()
function produces the values of the field
on the mesh, returning either a RealField
or
ComplexField
. This function treats the mesh equally in
either configuration space or Fourier space, internally
performing the appropriate FFTs. By specifying the mode
keyword to the
paint()
function, users can access either the field
data in configuration space or the complex modes of the field in Fourier space.
The “painting” nomenclature derives from the most common use case. The
process of interpolating a set of discrete objects on to the mesh evokes
the imagery of “painting” the mesh. More generally, the paint()
function is responsible for filling in the mesh with data, which could also
involve reading data from disk or generating mock fields directly on the mesh.
For further details and examples of painting a catalog of discrete objects to a mesh, see Painting Catalogs to a Mesh.
RealField
and ComplexField
¶The MeshSource
class provides an interface to the
pmesh.pm.RealField
and pmesh.pm.ComplexField
objects.
These classes behave like numpy arrays and include functions to
perform parallel forward and inverse FFTs. These
field objects are initialized from a pmesh.pm.ParticleMesh
, which
sets the number of mesh cells and stores FFT-related grid quantities.
In [1]: from pmesh.pm import ParticleMesh, RealField, ComplexField
# a 8^3 mesh
In [2]: pm = ParticleMesh(Nmesh=[8,8,8])
# initialize a RealField
In [3]: rfield = RealField(pm)
# shape
In [4]: print(rfield.shape)
(8, 8, 8)
# set entire mesh to unity
In [5]: rfield[...] = 1.0
# print the mean of the underlying array
In [6]: print(rfield.value.mean())
1.0
All MeshSource
objects implement either the
MeshSource.to_real_field()
function or the
MeshSource.to_complex_field()
function. These
functions are responsible for returning either a RealField
or a ComplexField
. The MeshSource.paint
function
calls these functions, providing the core functionality
of the MeshSource
class.
c2r()
and r2c()
functions¶Users can transform between RealField
and
ComplexField
objects using the r2c()
function for forward FFTs and the c2r()
function
for inverse FFTs. These operations take advantage of the fact that the field objects in
configuration space store real-valued quantities to perform real-to-complex
FFTs. This type of FFT uses the symmetry of real-valued quantities to store
only half of the complex modes along the z
axis.
# perform the forward FFT
In [7]: cfield = rfield.r2c()
# stores Nmesh/2+1 in z axis b/c of conjugate symmetry
In [8]: print(cfield.shape)
(8, 8, 5)
# k=0 mode is the mean value of configuration space field
In [9]: print("mean of configuration space field = ", cfield[0,0,0])