sandbox/acastillo/output_fields/tests_spectra/test_spectra_modes.c
Transform and shell binning on single modes
Modes the lattice represents exactly, so the tolerances are machine
tolerances. oblique and diagonal pin the
binning: |k| = 5 off-axis, and |k| = sqrt(2), which reaches bin 1 only
if the rounding in shell_average() is right.
subsampled breaks the rule in spectra.h: halving the lattice puts
every query point on a cell face, where locate() picks a
side inconsistently. That jitter is not a rigid shift, so energy leaves
the bin.
#include "utils.h"
#include "acastillo/output_fields/spectra/spectra.h"
#define ML 5
FILE * fp_out = NULL;
static void check (const char * tag, const char * kind, scalar s, int m,
int bexp, double Eexp, double leakexp)
{
int nk = nshells (m, m);
double * plane = malloc ((size_t) m*m*sizeof(double));
int holes = sample_scalar_plane ({s}, plane, snap_to_cell (0., 1 << ML),
X0, X0 + L0, Y0, Y0 + L0, m, m);
double ms = 0.;
for (int i = 0; i < m*m; i++)
ms += sq (plane[i]);
ms /= (double) m*m;
double * data = malloc (2*(size_t) m*m*sizeof(double));
for (int i = 0; i < m*m; i++)
data[2*i] = plane[i], data[2*i + 1] = 0.;
fft2D_forward (data, m, m);
double * E = malloc ((size_t) nk*sizeof(double));
shell_average (data, m, m, E, nk);
double sum = 0., peak = -1.;
int bpeak = -1;
for (int b = 0; b < nk; b++) {
sum += E[b];
if (E[b] > peak)
peak = E[b], bpeak = b;
}
if (pid() == 0)
fprintf (fp_out, "%s %s %d %d %d %d %.17g %.17g %.17g %.17g %.17g\n",
tag, kind, m, holes, bpeak, bexp, E[bexp], Eexp,
fabs (sum - E[bexp] - leakexp), fabs (sum - ms), sum);
free (plane), free (data), free (E);
}
int main()
{
L0 = 2.*pi;
X0 = Y0 = Z0 = -L0/2.;
int m = 1 << ML;
init_grid (m);
scalar a[], b[], d[], e[], g[];
foreach() {
a[] = 3.; // bin 0, E = 9
b[] = cos (5.*x); // kx = 5, bin 5, E = 1/2
d[] = cos (3.*x + 4.*y); // |k| = 5, bin 5, E = 1/2
e[] = cos (5.*x) + 2.*sin (3.*y); // bin 3 at 2, bin 5 at 1/2
g[] = cos (x + y); // |k| = sqrt(2), bin 1, E = 1/2
}
if (pid() == 0) {
fp_out = fopen ("spectra_modes.asc", "w");
fprintf (fp_out, "# tag kind m holes bpeak bexp E Eexp leak parseval sum\n");
}
check ("constant", "exact", a, m, 0, 9.0, 0.);
check ("axial", "exact", b, m, 5, 0.5, 0.);
check ("oblique", "exact", d, m, 5, 0.5, 0.);
check ("twomode", "exact", e, m, 3, 2.0, 0.5);
check ("diagonal", "exact", g, m, 1, 0.5, 0.);
// half the lattice: every query point on a face, so the bin bleeds
check ("subsampled", "leaky", g, m/2, 1, 0.5, 0.);
if (pid() == 0) {
fclose (fp_out);
system ("python3 ../test_spectra.py modes spectra_modes.asc 1>&2");
}
}