PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Macros | Functions
statistics_target.c File Reference

Spatial target resolution for the field-statistics pipeline. More...

#include "statistics_target.h"
#include "logging.h"
Include dependency graph for statistics_target.c:

Go to the source code of this file.

Macros

#define __FUNCT__   "SpatialTargetPlanCreate"
 
#define __FUNCT__   "SpatialTargetPlanGlobalPointCount"
 

Functions

PetscErrorCode PicurvLayoutDimensionIsNodeLike (FieldLayout layout, PetscInt dim, PetscBool *node_like)
 Implementation of PicurvLayoutDimensionIsNodeLike().
 
static void ResolveLayoutSpan (PetscBool node_like, PetscBool periodic, PetscInt size, PetscInt *lo, PetscInt *hi_exclusive)
 Internal helper: resolves the layout-valid index span for one dimension.
 
PetscErrorCode SpatialTargetPlanCreate (UserCtx *user, FieldId field_id, PicurvStatisticsMask mask, SpatialTargetPlan *plan)
 Implementation of SpatialTargetPlanCreate().
 
PetscErrorCode SpatialTargetPlanLocalPointCount (const SpatialTargetPlan *plan, PetscInt *count)
 Implementation of SpatialTargetPlanLocalPointCount().
 
PetscErrorCode SpatialTargetPlanGlobalPointCount (const SpatialTargetPlan *plan, MPI_Comm comm, PetscInt *count)
 Implementation of SpatialTargetPlanGlobalPointCount().
 
PetscBool SpatialTargetPlanMaskAllows (const SpatialTargetPlan *plan, PetscReal nvert_value)
 Implementation of SpatialTargetPlanMaskAllows().
 
static PetscInt SpatialAverageSlot (const PetscBool average_direction[3], const PetscInt retained_extent[3], PetscInt i, PetscInt j, PetscInt k)
 Flattens the retained global indices of one point into a reduction slot.
 
PetscErrorCode PicurvSpatialRatioAverage (UserCtx *user, const SpatialTargetPlan *plan, Vec numerator, Vec denominator, Vec inclusion, const PetscBool average_direction[3], MPI_Comm comm, Vec ratio, PetscReal *scalar)
 Implementation of PicurvSpatialRatioAverage().
 

Detailed Description

Spatial target resolution for the field-statistics pipeline.

Full API contract is documented with the declarations in include/statistics_target.h.

Definition in file statistics_target.c.

Macro Definition Documentation

◆ __FUNCT__ [1/2]

#define __FUNCT__   "SpatialTargetPlanCreate"

Definition at line 74 of file statistics_target.c.

◆ __FUNCT__ [2/2]

#define __FUNCT__   "SpatialTargetPlanGlobalPointCount"

Definition at line 74 of file statistics_target.c.

Function Documentation

◆ PicurvLayoutDimensionIsNodeLike()

PetscErrorCode PicurvLayoutDimensionIsNodeLike ( FieldLayout  layout,
PetscInt  dim,
PetscBool *  node_like 
)

Implementation of PicurvLayoutDimensionIsNodeLike().

Reports whether a layout is node-like in one dimension.

See also
PicurvLayoutDimensionIsNodeLike()

Definition at line 16 of file statistics_target.c.

17{
18 PetscFunctionBeginUser;
19 PetscCheck(node_like != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
20 "Classification output is required.");
21 PetscCheck(dim >= 0 && dim < 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
22 "Dimension must be 0, 1, or 2; got %" PetscInt_FMT ".", dim);
23
24 switch (layout) {
26 *node_like = PETSC_TRUE;
27 break;
29 *node_like = PETSC_FALSE;
30 break;
32 *node_like = (PetscBool)(dim == 0);
33 break;
35 *node_like = (PetscBool)(dim == 1);
36 break;
38 *node_like = (PetscBool)(dim == 2);
39 break;
41 /* x, y, and z live on I-, J-, and K-faces respectively, so no single
42 * classification describes the packed vector. */
43 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
44 "Component-staggered layout has no single per-dimension classification.");
45 default:
46 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
47 "Unknown field layout %d.", (int)layout);
48 }
49 PetscFunctionReturn(0);
50}
@ FIELD_LAYOUT_K_FACE
@ FIELD_LAYOUT_I_FACE
@ FIELD_LAYOUT_CELL_CENTERED
@ FIELD_LAYOUT_COMPONENT_STAGGERED
@ FIELD_LAYOUT_NODE_CENTERED
@ FIELD_LAYOUT_J_FACE
Here is the caller graph for this function:

◆ ResolveLayoutSpan()

static void ResolveLayoutSpan ( PetscBool  node_like,
PetscBool  periodic,
PetscInt  size,
PetscInt *  lo,
PetscInt *  hi_exclusive 
)
static

Internal helper: resolves the layout-valid index span for one dimension.

Local to this translation unit.

The DMDA carries one extra high-side slot beyond the physical grid, and the solver's shifted convention places boundary/dummy values at index zero. Under periodicity the repair algorithms in Boundaries.c write index 0 and index size-1 from the opposite side, so both are dependent duplicates and the independent span starts at one in every layout.

Definition at line 62 of file statistics_target.c.

64{
65 /* Node-like and non-periodic is the only case whose first physical entry
66 * sits at index zero; everywhere else index zero is a boundary, dummy, or
67 * periodic duplicate. */
68 *lo = (node_like && !periodic) ? 0 : 1;
69 /* The final slot is the DMDA's extra non-physical entry under every layout. */
70 *hi_exclusive = size - 1;
71}
Here is the caller graph for this function:

◆ SpatialTargetPlanCreate()

PetscErrorCode SpatialTargetPlanCreate ( UserCtx *  user,
FieldId  field_id,
PicurvStatisticsMask  mask,
SpatialTargetPlan *  plan 
)

Implementation of SpatialTargetPlanCreate().

Resolves the iteration domain for one field on one block.

See also
SpatialTargetPlanCreate()

Definition at line 79 of file statistics_target.c.

81{
82 const FieldDescriptor *descriptor = NULL;
83 const DMDALocalInfo *info = NULL;
84 SimCtx *simCtx = NULL;
85 PetscInt owned_start[3];
86 PetscInt owned_end[3];
87 PetscInt global_size[3];
88 PetscBool periodic[3];
89
90 PetscFunctionBeginUser;
92 PetscCheck(user != NULL && plan != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
93 "Block context and plan output are required.");
94 PetscCheck(mask == PICURV_STATISTICS_MASK_FLUID, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
95 "Only the fluid mask is implemented.");
96 simCtx = user->simCtx;
97 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
98 "Block context must carry a simulation context.");
99
100 PetscCall(FieldGetDescriptor(field_id, &descriptor));
101 PetscCheck(descriptor->layout != FIELD_LAYOUT_COMPONENT_STAGGERED,
102 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
103 "Field '%s' is component-staggered; its components live on different face "
104 "families and cannot share one pointwise target domain.",
105 descriptor->canonical_name);
106
107 info = &user->info;
108 owned_start[0] = info->xs; owned_end[0] = info->xs + info->xm; global_size[0] = info->mx;
109 owned_start[1] = info->ys; owned_end[1] = info->ys + info->ym; global_size[1] = info->my;
110 owned_start[2] = info->zs; owned_end[2] = info->zs + info->zm; global_size[2] = info->mz;
111 /* The simCtx flags are authoritative here because they are what selects
112 * DM_BOUNDARY_PERIODIC when the DMDA is built, and therefore what decides
113 * whether the end planes are wrapped duplicates. */
114 periodic[0] = (PetscBool)(simCtx->i_periodic != 0);
115 periodic[1] = (PetscBool)(simCtx->j_periodic != 0);
116 periodic[2] = (PetscBool)(simCtx->k_periodic != 0);
117
119 plan->mask = mask;
120 plan->descriptor = descriptor;
121
122 for (PetscInt dim = 0; dim < 3; ++dim) {
123 PetscBool node_like = PETSC_FALSE;
124 PetscInt layout_lo = 0;
125 PetscInt layout_hi = 0;
126
127 PetscCall(PicurvLayoutDimensionIsNodeLike(descriptor->layout, dim, &node_like));
128 ResolveLayoutSpan(node_like, periodic[dim], global_size[dim], &layout_lo, &layout_hi);
129
130 /* Intersect the layout-valid span with this rank's owned range: the
131 * first exclusion removes solver-layout indices, the second removes
132 * PETSc halo storage. */
133 plan->start[dim] = PetscMax(owned_start[dim], layout_lo);
134 plan->end[dim] = PetscMin(owned_end[dim], layout_hi);
135 if (plan->end[dim] < plan->start[dim]) plan->end[dim] = plan->start[dim];
136 }
138 PetscFunctionReturn(0);
139}
FieldLayout layout
const char * canonical_name
PetscErrorCode FieldGetDescriptor(FieldId field_id, const FieldDescriptor **descriptor)
Return immutable metadata for a valid field identifier.
Immutable metadata for one field identity.
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:894
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:885
static void ResolveLayoutSpan(PetscBool node_like, PetscBool periodic, PetscInt size, PetscInt *lo, PetscInt *hi_exclusive)
Internal helper: resolves the layout-valid index span for one dimension.
PetscErrorCode PicurvLayoutDimensionIsNodeLike(FieldLayout layout, PetscInt dim, PetscBool *node_like)
Implementation of PicurvLayoutDimensionIsNodeLike().
PicurvTargetKind kind
Spatial mapping; always pointwise.
@ PICURV_TARGET_POINTWISE
@ PICURV_STATISTICS_MASK_FLUID
PetscInt end[3]
Exclusive end per dimension (i, j, k).
PetscInt start[3]
Inclusive start per dimension (i, j, k).
const FieldDescriptor * descriptor
Catalog metadata for the targeted field.
PicurvStatisticsMask mask
Point-eligibility mask.
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:1076
PetscInt k_periodic
Definition variables.h:961
PetscInt i_periodic
Definition variables.h:961
DMDALocalInfo info
Definition variables.h:1085
PetscInt j_periodic
Definition variables.h:961
The master context for the entire simulation.
Definition variables.h:866
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SpatialTargetPlanLocalPointCount()

PetscErrorCode SpatialTargetPlanLocalPointCount ( const SpatialTargetPlan *  plan,
PetscInt *  count 
)

Implementation of SpatialTargetPlanLocalPointCount().

Counts the points this rank contributes.

See also
SpatialTargetPlanLocalPointCount()

Definition at line 145 of file statistics_target.c.

146{
147 PetscInt total = 1;
148
149 PetscFunctionBeginUser;
150 PetscCheck(plan != NULL && count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
151 "Plan and count output are required.");
152 for (PetscInt dim = 0; dim < 3; ++dim) {
153 const PetscInt extent = plan->end[dim] - plan->start[dim];
154 if (extent <= 0) { *count = 0; PetscFunctionReturn(0); }
155 total *= extent;
156 }
157 *count = total;
158 PetscFunctionReturn(0);
159}
Here is the caller graph for this function:

◆ SpatialTargetPlanGlobalPointCount()

PetscErrorCode SpatialTargetPlanGlobalPointCount ( const SpatialTargetPlan *  plan,
MPI_Comm  comm,
PetscInt *  count 
)

Implementation of SpatialTargetPlanGlobalPointCount().

Counts the points contributed across a communicator.

See also
SpatialTargetPlanGlobalPointCount()

Definition at line 167 of file statistics_target.c.

168{
169 PetscInt local = 0;
170
171 PetscFunctionBeginUser;
173 PetscCheck(plan != NULL && count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
174 "Plan and count output are required.");
175 PetscCall(SpatialTargetPlanLocalPointCount(plan, &local));
176 PetscCallMPI(MPI_Allreduce(&local, count, 1, MPIU_INT, MPI_SUM, comm));
178 PetscFunctionReturn(0);
179}
PetscErrorCode SpatialTargetPlanLocalPointCount(const SpatialTargetPlan *plan, PetscInt *count)
Implementation of SpatialTargetPlanLocalPointCount().
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SpatialTargetPlanMaskAllows()

PetscBool SpatialTargetPlanMaskAllows ( const SpatialTargetPlan *  plan,
PetscReal  nvert_value 
)

Implementation of SpatialTargetPlanMaskAllows().

Reports whether a point passes the plan's mask.

See also
SpatialTargetPlanMaskAllows()

Definition at line 185 of file statistics_target.c.

186{
187 if (plan == NULL) return PETSC_FALSE;
188 return (PetscBool)(nvert_value < PICURV_STATISTICS_FLUID_THRESHOLD);
189}
#define PICURV_STATISTICS_FLUID_THRESHOLD
Threshold below which a cell counts as fluid for the default mask.
Here is the caller graph for this function:

◆ SpatialAverageSlot()

static PetscInt SpatialAverageSlot ( const PetscBool  average_direction[3],
const PetscInt  retained_extent[3],
PetscInt  i,
PetscInt  j,
PetscInt  k 
)
static

Flattens the retained global indices of one point into a reduction slot.

A direction being averaged over collapses to a single entry, so the buffer is indexed only by the directions left out.

Definition at line 197 of file statistics_target.c.

200{
201 return (average_direction[0] ? 0 : i) +
202 retained_extent[0] * ((average_direction[1] ? 0 : j) +
203 retained_extent[1] * (average_direction[2] ? 0 : k));
204}
Here is the caller graph for this function:

◆ PicurvSpatialRatioAverage()

PetscErrorCode PicurvSpatialRatioAverage ( UserCtx *  user,
const SpatialTargetPlan *  plan,
Vec  numerator,
Vec  denominator,
Vec  inclusion,
const PetscBool  average_direction[3],
MPI_Comm  comm,
Vec  ratio,
PetscReal *  scalar 
)

Implementation of PicurvSpatialRatioAverage().

Averages two fields over a target domain and divides the results.

See also
PicurvSpatialRatioAverage()

Definition at line 210 of file statistics_target.c.

214{
215 DM da = NULL;
216 DMDALocalInfo info;
217 PetscInt retained_extent[3];
218 PetscInt buffer_size = 1;
219 PetscInt averaged_count = 0;
220 PetscReal ***num = NULL, ***den = NULL, ***inc = NULL, ***out = NULL, ***nvert = NULL;
221 PetscReal *num_sum = NULL, *den_sum = NULL;
222
223 PetscFunctionBeginUser;
225 PetscCheck(user != NULL && plan != NULL && numerator != NULL && average_direction != NULL,
226 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
227 "Context, plan, numerator, and direction selector are required.");
228
229 da = user->da;
230 PetscCall(DMDAGetLocalInfo(da, &info));
231
232 retained_extent[0] = average_direction[0] ? 1 : info.mx;
233 retained_extent[1] = average_direction[1] ? 1 : info.my;
234 retained_extent[2] = average_direction[2] ? 1 : info.mz;
235 for (PetscInt axis = 0; axis < 3; axis++) {
236 if (average_direction[axis]) averaged_count++;
237 buffer_size *= retained_extent[axis];
238 }
239 PetscCheck(scalar == NULL || averaged_count == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
240 "A single averaged value exists only when every direction is averaged over; "
241 "%" PetscInt_FMT " of 3 were selected.", averaged_count);
242
243 PetscCall(DMDAVecGetArrayRead(da, numerator, &num));
244 if (denominator) PetscCall(DMDAVecGetArrayRead(da, denominator, &den));
245 if (inclusion) PetscCall(DMDAVecGetArrayRead(da, inclusion, &inc));
246 if (ratio) PetscCall(DMDAVecGetArray(da, ratio, &out));
247 PetscCall(DMDAVecGetArrayRead(da, user->lNvert, &nvert));
248
249 if (averaged_count == 0) {
250 /* Pointwise: the empty averaging set, which is a legitimate request rather
251 * than a degenerate one. It is what a local formulation asks for. The masks
252 * mean the same thing here as they do for an averaged set - a point they
253 * exclude contributes nothing and receives nothing - so that a caller can
254 * switch between the two without its exclusions quietly changing meaning. */
255 for (PetscInt k = plan->start[2]; k < plan->end[2]; k++)
256 for (PetscInt j = plan->start[1]; j < plan->end[1]; j++)
257 for (PetscInt i = plan->start[0]; i < plan->end[0]; i++) {
258 const PetscReal divisor = denominator ? den[k][j][i] : 1.0;
259
260 if (!SpatialTargetPlanMaskAllows(plan, nvert[k][j][i]) ||
261 (inc && inc[k][j][i] <= 0.0)) {
262 out[k][j][i] = 0.0;
263 continue;
264 }
265 out[k][j][i] = (PetscAbsReal(divisor) > 0.0) ? (num[k][j][i] / divisor) : 0.0;
266 }
267 } else {
268 PetscCheck(buffer_size <= PICURV_SPATIAL_AVERAGE_MAX_BUFFER, PETSC_COMM_SELF,
269 PETSC_ERR_ARG_OUTOFRANGE,
270 "Averaging over %" PetscInt_FMT " direction(s) would need a reduction buffer "
271 "of %" PetscInt_FMT " entries, above the %d entry limit. Average over more "
272 "directions.", averaged_count, buffer_size, PICURV_SPATIAL_AVERAGE_MAX_BUFFER);
273
274 PetscCall(PetscCalloc2(buffer_size, &num_sum, buffer_size, &den_sum));
275
276 for (PetscInt k = plan->start[2]; k < plan->end[2]; k++)
277 for (PetscInt j = plan->start[1]; j < plan->end[1]; j++)
278 for (PetscInt i = plan->start[0]; i < plan->end[0]; i++) {
279 PetscInt slot;
280
281 if (!SpatialTargetPlanMaskAllows(plan, nvert[k][j][i])) continue;
282 /* A point the caller marks unmeasured holds a zero that means absence, not
283 * a measurement; counting it would scale the answer toward zero. */
284 if (inc && inc[k][j][i] <= 0.0) continue;
285
286 slot = SpatialAverageSlot(average_direction, retained_extent, i, j, k);
287 num_sum[slot] += num[k][j][i];
288 den_sum[slot] += denominator ? den[k][j][i] : 1.0;
289 }
290
291 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, num_sum, (PetscMPIInt)buffer_size,
292 MPIU_REAL, MPI_SUM, comm));
293 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, den_sum, (PetscMPIInt)buffer_size,
294 MPIU_REAL, MPI_SUM, comm));
295
296 if (out) {
297 for (PetscInt k = plan->start[2]; k < plan->end[2]; k++)
298 for (PetscInt j = plan->start[1]; j < plan->end[1]; j++)
299 for (PetscInt i = plan->start[0]; i < plan->end[0]; i++) {
300 const PetscInt slot = SpatialAverageSlot(average_direction, retained_extent, i, j, k);
301
302 out[k][j][i] = (PetscAbsReal(den_sum[slot]) > 0.0)
303 ? (num_sum[slot] / den_sum[slot]) : 0.0;
304 }
305 }
306 if (scalar) {
307 *scalar = (PetscAbsReal(den_sum[0]) > 0.0) ? (num_sum[0] / den_sum[0]) : 0.0;
308 }
309
310 PetscCall(PetscFree2(num_sum, den_sum));
311 }
312
313 PetscCall(DMDAVecRestoreArrayRead(da, numerator, &num));
314 if (denominator) PetscCall(DMDAVecRestoreArrayRead(da, denominator, &den));
315 if (inclusion) PetscCall(DMDAVecRestoreArrayRead(da, inclusion, &inc));
316 if (ratio) PetscCall(DMDAVecRestoreArray(da, ratio, &out));
317 PetscCall(DMDAVecRestoreArrayRead(da, user->lNvert, &nvert));
318
320 PetscFunctionReturn(0);
321}
PetscBool SpatialTargetPlanMaskAllows(const SpatialTargetPlan *plan, PetscReal nvert_value)
Implementation of SpatialTargetPlanMaskAllows().
static PetscInt SpatialAverageSlot(const PetscBool average_direction[3], const PetscInt retained_extent[3], PetscInt i, PetscInt j, PetscInt k)
Flattens the retained global indices of one point into a reduction slot.
#define PICURV_SPATIAL_AVERAGE_MAX_BUFFER
Largest reduction buffer a directional average will allocate, in entries.
Vec lNvert
Definition variables.h:1113
Here is the call graph for this function:
Here is the caller graph for this function: