# Overview: Grid operations

Some common operations on grids.

# Smoothing

Smooth the grid by Fourier transforming and applying a filter. The filter can be sharpk ($H(1-kR)$, i.e. $0$ for $kR > 1$ and $1$ otherwise), tophat (the Fourier transform of $H(R-x)$ in 2D or 3D) or gaussian ($e^{-\frac{1}2{}(kR)^2}$) or add your own.

template<int N>
void smoothing_filter_fourier_space(
FFTWGrid<N> & fourier_grid,
double smoothing_scale,
std::string smoothing_method)


# Whitening

Transform a grid to Fourier space, normalize all modes such that $|f(k)| = 1$ and transform back (the method below does just the middle part).

template<int N>
void whitening_fourier_space(FFTWGrid<N> & fourier_grid);

// When starting in real-space
grid.fftw_r2c();
whitening_fourier_space(grid);
grid.fftw_c2r();


# Convolutions

Convolve the grid (in real space) with an arbitary (compact) kernel:

template<int N, int ORDER, class T>
void convolve_grid_with_kernel(
const FFTWGrid<N> & grid_in,
FFTWGrid<N> & grid_out,
std::function<FloatType(std::vector<double> &am; dx)> & convolution_kernel);


The argument to the kernel is how far away the point is from the cell in units of the cell-size so the NGP kernel would be $1$ if all $|dx_i| < 0.5$ and zero otherwisee. ORDER is how wide the kernel is (how many grid-cells; this is needed to limit the number of cells we visit).

We can also perform convolutions of two grids in real and fourier space (using Fourier transforms):

template <int N>
void convolution_fourier_space(const FFTWGrid<N> & fourier_grid_f,
const FFTWGrid<N> & fourier_grid_g,
FFTWGrid<N> & fourier_grid_result);

template <int N>
void convolution_real_space(const FFTWGrid<N> & real_grid_f,
const FFTWGrid<N> & real_grid_g,
FFTWGrid<N> & real_grid_result);


This is computing the grids $F(k) = \int d^N q f(q)g(k-q)$ and $F(x) = \int d^N y f(x)g(x-y)$ respectively. This requires three Fourier tranforms and one temporary grid (we don't touch the input grids).