PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
test_statistics_target.c
Go to the documentation of this file.
1/**
2 * @file test_statistics_target.c
3 * @brief C unit tests for pointwise spatial target resolution.
4 *
5 * Covers the Stage 2 acceptance items in
6 * @ref 60_Field_Statistics_Phase2_Implementation_Specification section 13: cell,
7 * node, and I/J/K-face layouts, and nonperiodic, mixed, and fully periodic
8 * domains with no duplicate planes.
9 *
10 * The fixture builds a DMDA of size `n + 1` per dimension, so with `n = 6` each
11 * dimension has seven slots: one extra non-physical high-side slot, and under the
12 * solver's shifted convention a boundary/dummy slot at index zero.
13 */
14
15#include "test_support.h"
16
17#include "statistics_target.h"
18#include "setup.h"
19
20#define TARGET_TEST_N 6 /* fixture size; DMDA is TARGET_TEST_N + 1 per dimension */
21#define TARGET_CELL_EXTENT 5 /* cell-like span: indices [1, 6) */
22#define TARGET_NODE_EXTENT 6 /* node-like nonperiodic span: indices [0, 6) */
23
24/** @brief Builds a plan and returns its global point count. */
25static PetscErrorCode PlanCount(UserCtx *user, FieldId field_id, PetscInt *count)
26{
28
29 PetscFunctionBeginUser;
30 PetscCall(SpatialTargetPlanCreate(user, field_id, PICURV_STATISTICS_MASK_FLUID, &plan));
31 PetscCall(SpatialTargetPlanGlobalPointCount(&plan, PETSC_COMM_WORLD, count));
32 PetscFunctionReturn(0);
33}
34
35/** @brief Cell-centered fields must exclude the dummy slot and the extra high slot. */
37{
38 SimCtx *simCtx = NULL;
39 UserCtx *user = NULL;
41 PetscInt local = 0, global = 0;
42
43 PetscFunctionBeginUser;
45
47 PetscCall(PicurvAssertIntEqual(PICURV_TARGET_POINTWISE, plan.kind, "plan kind should be pointwise"));
49 "P should resolve as cell-centered"));
50 /* On one rank the owned range spans the block, so the plan is the layout span. */
51 if (simCtx->size == 1) {
52 for (PetscInt dim = 0; dim < 3; ++dim) {
53 PetscCall(PicurvAssertIntEqual(1, plan.start[dim],
54 "cell-centered span must skip the index-zero dummy slot"));
55 PetscCall(PicurvAssertIntEqual(TARGET_TEST_N, plan.end[dim],
56 "cell-centered span must skip the extra high-side slot"));
57 }
58 }
59 PetscCall(SpatialTargetPlanLocalPointCount(&plan, &local));
60 PetscCall(SpatialTargetPlanGlobalPointCount(&plan, PETSC_COMM_WORLD, &global));
62 "cell-centered global point count"));
63 PetscCall(PicurvAssertBool((PetscBool)(local <= global), "local count cannot exceed global count"));
64
65 /* Vector and scalar cell-centered fields share one domain. */
66 PetscCall(PlanCount(user, FIELD_ID_UCAT, &global));
68 "Ucat shares the cell-centered domain regardless of dof"));
69
70 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
71 PetscFunctionReturn(0);
72}
73
74/** @brief Each face family is node-like in exactly its own direction. */
76{
77 SimCtx *simCtx = NULL;
78 UserCtx *user = NULL;
79 PetscInt global = 0;
80 const PetscInt cell = TARGET_CELL_EXTENT;
81 const PetscInt node = TARGET_NODE_EXTENT;
82
83 PetscFunctionBeginUser;
85
86 PetscCall(PlanCount(user, FIELD_ID_CSI, &global));
87 PetscCall(PicurvAssertIntEqual(node * cell * cell, global, "I-face domain is node-like in i only"));
88 PetscCall(PlanCount(user, FIELD_ID_ETA, &global));
89 PetscCall(PicurvAssertIntEqual(cell * node * cell, global, "J-face domain is node-like in j only"));
90 PetscCall(PlanCount(user, FIELD_ID_ZET, &global));
91 PetscCall(PicurvAssertIntEqual(cell * cell * node, global, "K-face domain is node-like in k only"));
92 PetscCall(PlanCount(user, FIELD_ID_COORDINATES, &global));
93 PetscCall(PicurvAssertIntEqual(node * node * node, global, "node-centered domain is node-like in all directions"));
94
95 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
96 PetscFunctionReturn(0);
97}
98
99/**
100 * @brief Periodic directions must drop the wrapped duplicate plane.
101 *
102 * The periodic repair algorithms write index zero and the final slot from the
103 * opposite side, so both are dependent duplicates. A node-like direction
104 * therefore loses one entry under periodicity, while a cell-like direction is
105 * unchanged because its duplicates were already outside the span.
106 */
108{
109 SimCtx *simCtx = NULL;
110 UserCtx *user = NULL;
111 PetscInt global = 0;
112 const PetscInt cell = TARGET_CELL_EXTENT;
113 const PetscInt node = TARGET_NODE_EXTENT;
114
115 PetscFunctionBeginUser;
116 /* Mixed: periodic in i only. */
117 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user,
119 PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
120 PetscCall(PlanCount(user, FIELD_ID_P, &global));
121 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
122 "cell-centered count is unchanged by periodicity"));
123 PetscCall(PlanCount(user, FIELD_ID_CSI, &global));
124 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
125 "I-face loses its duplicate plane when i is periodic"));
126 PetscCall(PlanCount(user, FIELD_ID_ETA, &global));
127 PetscCall(PicurvAssertIntEqual(cell * node * cell, global,
128 "J-face keeps its node-like span when only i is periodic"));
129 PetscCall(PlanCount(user, FIELD_ID_COORDINATES, &global));
130 PetscCall(PicurvAssertIntEqual(cell * node * node, global,
131 "node-centered loses only the periodic direction"));
132 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
133
134 /* Fully periodic: every node-like direction collapses to the cell extent. */
135 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user,
137 PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
138 PetscCall(PlanCount(user, FIELD_ID_COORDINATES, &global));
139 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
140 "fully periodic node-centered domain has no duplicate planes"));
141 PetscCall(PlanCount(user, FIELD_ID_CSI, &global));
142 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
143 "fully periodic I-face domain has no duplicate planes"));
144 PetscCall(PlanCount(user, FIELD_ID_P, &global));
145 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
146 "fully periodic cell-centered domain is unchanged"));
147 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
148 PetscFunctionReturn(0);
149}
150
151/** @brief Component-staggered fields cannot share one pointwise domain and are rejected. */
152static PetscErrorCode TestComponentStaggeredRejected(void)
153{
154 SimCtx *simCtx = NULL;
155 UserCtx *user = NULL;
157 PetscErrorCode staggered_ierr = 0;
158 PetscErrorCode classify_ierr = 0;
159 PetscBool node_like = PETSC_FALSE;
160
161 PetscFunctionBeginUser;
163
164 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
166 PetscCall(PetscPopErrorHandler());
167 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_WRONGSTATE, staggered_ierr,
168 "Ucont is component-staggered and must not resolve a pointwise domain"));
169
170 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
172 PetscCall(PetscPopErrorHandler());
173 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_WRONGSTATE, classify_ierr,
174 "component-staggered layout has no single per-dimension classification"));
175
176 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
177 classify_ierr = PicurvLayoutDimensionIsNodeLike(FIELD_LAYOUT_CELL_CENTERED, 3, &node_like);
178 PetscCall(PetscPopErrorHandler());
179 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_OUTOFRANGE, classify_ierr,
180 "dimension index outside 0..2 must be rejected"));
181
182 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
183 PetscFunctionReturn(0);
184}
185
186/** @brief The fluid mask admits fluid cells and rejects blanked ones at the documented threshold. */
187static PetscErrorCode TestFluidMaskThreshold(void)
188{
189 SimCtx *simCtx = NULL;
190 UserCtx *user = NULL;
192
193 PetscFunctionBeginUser;
196
197 PetscCall(PicurvAssertBool(SpatialTargetPlanMaskAllows(&plan, 0.0),
198 "open fluid must pass the fluid mask"));
199 PetscCall(PicurvAssertBool(SpatialTargetPlanMaskAllows(&plan, 0.05),
200 "values below the threshold must pass the fluid mask"));
201 PetscCall(PicurvAssertBool((PetscBool)!SpatialTargetPlanMaskAllows(&plan, 1.0),
202 "solid cells must fail the fluid mask"));
204 "the threshold itself is excluded, matching the existing Nvert < 0.1 rule"));
205 PetscCall(PicurvAssertBool((PetscBool)!SpatialTargetPlanMaskAllows(NULL, 0.0),
206 "a null plan must not admit points"));
207
208 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
209 PetscFunctionReturn(0);
210}
211
212/**
213 * @brief The cell-centered span must agree with the existing owned-cell helper.
214 *
215 * `GetOwnedCellRange` reports cells by their origin node index, while field
216 * storage uses the solver's shifted convention where the cell with origin `j`
217 * lives at array index `j + 1`. The two therefore describe the same cells in
218 * different index spaces. This pins that relationship so the target plan and the
219 * established helper cannot drift apart.
220 */
221static PetscErrorCode TestCellSpanAgreesWithOwnedCellRange(void)
222{
223 SimCtx *simCtx = NULL;
224 UserCtx *user = NULL;
226
227 PetscFunctionBeginUser;
230
231 for (PetscInt dim = 0; dim < 3; ++dim) {
232 PetscInt origin_start = 0;
233 PetscInt origin_count = 0;
234
235 PetscCall(GetOwnedCellRange(&user->info, dim, &origin_start, &origin_count));
236 /* Shift from origin-node indexing into field-storage indexing. */
237 PetscCall(PicurvAssertIntEqual(origin_start + 1, plan.start[dim],
238 "cell span start must be the owned-cell origin shifted by one"));
239 PetscCall(PicurvAssertIntEqual(origin_start + origin_count + 1, plan.end[dim],
240 "cell span end must be the owned-cell extent shifted by one"));
241 }
242
243 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
244 PetscFunctionReturn(0);
245}
246
247/**
248 * @brief Entry point for the spatial target suite.
249 */
250int main(int argc, char **argv)
251{
252 PetscErrorCode ierr;
253 const PicurvTestCase cases[] = {
254 {"cell-centered-excludes-boundary-and-dummy", TestCellCenteredExcludesBoundaryAndDummy},
255 {"face-layouts-node-like-in-own-direction", TestFaceLayoutsAreNodeLikeInOwnDirection},
256 {"periodic-directions-drop-duplicate-plane", TestPeriodicDirectionsDropDuplicatePlane},
257 {"component-staggered-rejected", TestComponentStaggeredRejected},
258 {"fluid-mask-threshold", TestFluidMaskThreshold},
259 {"cell-span-agrees-with-owned-cell-range", TestCellSpanAgreesWithOwnedCellRange},
260 };
261
262 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv spatial target tests");
263 if (ierr) {
264 return (int)ierr;
265 }
266
267 ierr = PicurvRunTests("unit-statistics-target", cases, sizeof(cases) / sizeof(cases[0]));
268 if (ierr) {
269 PetscFinalize();
270 return (int)ierr;
271 }
272
273 ierr = PetscFinalize();
274 return (int)ierr;
275}
FieldLayout layout
@ FIELD_LAYOUT_CELL_CENTERED
@ FIELD_LAYOUT_COMPONENT_STAGGERED
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_CSI
@ FIELD_ID_UCAT
@ FIELD_ID_COORDINATES
@ FIELD_ID_UCONT
@ FIELD_ID_ETA
@ FIELD_ID_P
@ FIELD_ID_ZET
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global_out, PetscInt *xm_cell_local_out)
Determines the global starting index and number of CELLS owned by the current processor in a specifie...
Definition setup.c:2278
Spatial target resolution for the field-statistics pipeline.
#define PICURV_STATISTICS_FLUID_THRESHOLD
Threshold below which a cell counts as fluid for the default mask.
PetscBool SpatialTargetPlanMaskAllows(const SpatialTargetPlan *plan, PetscReal nvert_value)
Reports whether a point passes the plan's mask.
PicurvTargetKind kind
Spatial mapping; always pointwise in Phase 2.
@ 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).
PetscErrorCode SpatialTargetPlanLocalPointCount(const SpatialTargetPlan *plan, PetscInt *count)
Counts the points this rank contributes.
PetscErrorCode SpatialTargetPlanGlobalPointCount(const SpatialTargetPlan *plan, MPI_Comm comm, PetscInt *count)
Counts the points contributed across a communicator.
PetscErrorCode SpatialTargetPlanCreate(UserCtx *user, FieldId field_id, PicurvStatisticsMask mask, SpatialTargetPlan *plan)
Resolves the iteration domain for one field on one block.
PetscErrorCode PicurvLayoutDimensionIsNodeLike(FieldLayout layout, PetscInt dim, PetscBool *node_like)
Reports whether a layout is node-like in one dimension.
const FieldDescriptor * descriptor
Catalog metadata for the targeted field.
Resolved iteration domain for one field on one block.
static PetscErrorCode TestComponentStaggeredRejected(void)
Component-staggered fields cannot share one pointwise domain and are rejected.
static PetscErrorCode PlanCount(UserCtx *user, FieldId field_id, PetscInt *count)
Builds a plan and returns its global point count.
static PetscErrorCode TestPeriodicDirectionsDropDuplicatePlane(void)
Periodic directions must drop the wrapped duplicate plane.
int main(int argc, char **argv)
Entry point for the spatial target suite.
static PetscErrorCode TestCellCenteredExcludesBoundaryAndDummy(void)
Cell-centered fields must exclude the dummy slot and the extra high slot.
static PetscErrorCode TestFaceLayoutsAreNodeLikeInOwnDirection(void)
Each face family is node-like in exactly its own direction.
static PetscErrorCode TestFluidMaskThreshold(void)
The fluid mask admits fluid cells and rejects blanked ones at the documented threshold.
#define TARGET_CELL_EXTENT
#define TARGET_NODE_EXTENT
#define TARGET_TEST_N
static PetscErrorCode TestCellSpanAgreesWithOwnedCellRange(void)
The cell-centered span must agree with the existing owned-cell helper.
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvCreateMinimalContextsWithPeriodicity(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz, PetscBool x_periodic, PetscBool y_periodic, PetscBool z_periodic)
Builds minimal SimCtx and UserCtx fixtures for C unit tests with configurable periodicity.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
DMDALocalInfo info
Definition variables.h:908
PetscMPIInt size
Definition variables.h:699
The master context for the entire simulation.
Definition variables.h:695
User-defined context containing data specific to a single computational grid level.
Definition variables.h:896
A generic C-style linked list node for integers.
Definition variables.h:439