`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:

- Generating mesh data from a
`CatalogSource`

(see Converting a CatalogSource to a Mesh) - Reading mesh data from disk (see Saving and Loading a Mesh)
- Generating mock fields directly on a mesh (see Gaussian Realizations)

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])
mean of configuration space field = (1+0j)
# perform the inverse FFT
In [10]: rfield2 = cfield.c2r()
# print the mean of the underlying array
In [11]: print(rfield2.value.mean())
1.0
```

For all `MeshSource`

objects, the input parameters and additional
meta-data are stored in the `attrs`

dictionary attribute.

For more information about specific mesh sources, please see the API section.