sandbox/acastillo/output_fields/spectra/spectra_sample.h
Sampling a plane onto a regular lattice
sample_scalar_plane() evaluates every field in
list on a regular m1 x m2 lattice in the plane z = h and assembles the result, across ranks,
into one contiguous array. 3D only.
This is the piece a horizontal FFT needs:
foreach_region() returns the cell containing each query
point, so on a tree grid the lattice is a uniform view of an adaptive
field. With xmin = X0, xmax = X0 + L0 and
m1 equal to the finest grid size, the query points are the
finest cells’ centres and they cover [X_0,
X_0+L_0) exactly once – one period, no repeated endpoint.
Follows output_field() in output.h: the array starts at
nodata and is combined with a min reduction, so a
point no rank owns stays nodata and one located on several
ranks resolves to the same value either way. Values are read as
s[] rather than interpolated, matching profiles_scalar.h; away from
the finest level that means the containing cell’s value, so a lattice
finer than the local grid low-passes the field.
h on a cell face is ambiguous for a z-dependent field – locate()
picks one side. Offset by half a cell to sample cell centres.
The caller allocates plane with m1*m2*len
doubles, laid out as plane[(i*m2 + j)*len + k] for field
k at lattice point (i,j). Returns the number
of unfilled points, 0 for a complete plane.
#if dimension != 3
#error sample_scalar_plane() is 3D only
#endif
int sample_scalar_plane (scalar * list, double * plane, double h,
double xmin, double xmax,
double ymin, double ymax,
int m1, int m2)
{
int len = list_len (list), n = m1*m2*len;
coord box[2] = {{xmin, ymin, h}, {xmax, ymax, h}};
coord nsamples = {m1, m2, 1};
for (int i = 0; i < n; i++)
plane[i] = nodata;
coord p;
foreach_region (p, box, nsamples, reduction(min:plane[:n])){
double * alias = plane; // so that qcc considers 'plane' a local variable
int i = (p.x - box[0].x)/(box[1].x - box[0].x)*nsamples.x;
int j = (p.y - box[0].y)/(box[1].y - box[0].y)*nsamples.y;
int k = 0;
for (scalar s in list)
alias[(i*m2 + j)*len + k++] = s[];
}
int holes = 0;
for (int i = 0; i < n; i++)
if (plane[i] == nodata)
holes++;
return holes;
}Snap a target height to the nearest cell centre.
foreach_region returns the cell containing the point, so a
height on a face resolves to one side arbitrarily – z = 0 is a face whenever the grid size is
even.
double snap_to_cell (double h, int m)
{
double del = L0/m;
return Z0 + (floor ((h - Z0)/del) + 0.5)*del;
}