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

C unit tests for MPI collective helper routines. More...

#include "test_support.h"
#include "ParticleMotion.h"
#include "ParticleSwarm.h"
#include "Boundaries.h"
#include "grid.h"
#include "statistics_target.h"
#include "statistics_accumulator.h"
#include "statistics_window.h"
#include "io.h"
#include "field_catalog.h"
#include <stdlib.h>
Include dependency graph for test_mpi_kernels.c:

Go to the source code of this file.

Functions

static void MarkXPeriodic (UserCtx *user)
 Marks both x boundary faces as geometric periodic boundaries.
 
static PetscReal PeriodicScalarValue (PetscInt i, PetscInt j, PetscInt k, PetscReal offset)
 Returns a deterministic scalar value for periodic-transfer assertions.
 
static PetscErrorCode TestDistributeParticlesCollectiveConsistency (void)
 Tests collective particle distribution consistency across MPI ranks.
 
static PetscErrorCode TestBoundingBoxCollectivesMultiRank (void)
 Tests multi-rank bounding-box gather and broadcast helpers.
 
static PetscErrorCode TestPeriodicCellFieldSynchronizationMultiRank (void)
 Tests distributed synchronization of persistent cell-centered scalar fields.
 
static PetscErrorCode TestPeriodicGeometryValidationMultiRank (void)
 Tests periodic seam translation discovery when seam nodes are on different ranks.
 
static PetscErrorCode TestPeriodicFaceCenterCoordinatesMultiRank (void)
 Tests translated face-center ghosts when the periodic axis is partitioned.
 
static PetscErrorCode TestPeriodicFaceFieldSynchronizationMultiRank (void)
 Tests persistent I-face synchronization across an MPI-partitioned seam.
 
static PetscErrorCode TestPeriodicStaggeredFieldSynchronizationMultiRank (void)
 Tests persistent Ucont synchronization across an MPI-partitioned seam.
 
static PetscErrorCode TestRestartCellIdMigrationMovesParticleToOwner (void)
 Tests restart fast-path migration using preloaded cell ownership metadata.
 
static PetscErrorCode TestSpatialTargetIsDecompositionIndependent (void)
 Spatial target domains must not depend on how ranks divide the block.
 
static PetscErrorCode TestStatisticsCheckpointRoundTripMultiRank (void)
 Statistics payloads must survive a checkpoint round trip under decomposition.
 
int main (int argc, char **argv)
 Runs the unit-mpi PETSc test binary.
 

Detailed Description

C unit tests for MPI collective helper routines.

Definition in file test_mpi_kernels.c.

Function Documentation

◆ MarkXPeriodic()

static void MarkXPeriodic ( UserCtx user)
static

Marks both x boundary faces as geometric periodic boundaries.

Definition at line 23 of file test_mpi_kernels.c.

Here is the caller graph for this function:

◆ PeriodicScalarValue()

static PetscReal PeriodicScalarValue ( PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscReal  offset 
)
static

Returns a deterministic scalar value for periodic-transfer assertions.

Definition at line 36 of file test_mpi_kernels.c.

37{
38 return offset + (PetscReal)(i + 10 * j + 100 * k);
39}
Here is the caller graph for this function:

◆ TestDistributeParticlesCollectiveConsistency()

static PetscErrorCode TestDistributeParticlesCollectiveConsistency ( void  )
static

Tests collective particle distribution consistency across MPI ranks.

Definition at line 44 of file test_mpi_kernels.c.

45{
46 PetscMPIInt rank = 0, size = 1;
47 PetscInt local_particles = 0;
48 PetscInt remainder = 0;
49 PetscInt global_particles = 0;
50 PetscInt remainder_min = 0, remainder_max = 0;
51 const PetscInt total_particles = 137;
52
53 PetscFunctionBeginUser;
54 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
55 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
56 PetscCall(PicurvAssertBool((PetscBool)(size >= 2), "unit-mpi requires at least two MPI ranks"));
57
58 PetscCall(DistributeParticles(total_particles, rank, size, &local_particles, &remainder));
59
60 PetscCall(PicurvAssertIntEqual(
61 total_particles / size + (((PetscInt)rank < remainder) ? 1 : 0),
62 local_particles,
63 "local particle share should match quotient+remainder policy"));
64
65 PetscCallMPI(MPI_Allreduce(&local_particles, &global_particles, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
66 PetscCall(PicurvAssertIntEqual(total_particles, global_particles, "distributed particle count must conserve total particles"));
67
68 PetscCallMPI(MPI_Allreduce(&remainder, &remainder_min, 1, MPIU_INT, MPI_MIN, PETSC_COMM_WORLD));
69 PetscCallMPI(MPI_Allreduce(&remainder, &remainder_max, 1, MPIU_INT, MPI_MAX, PETSC_COMM_WORLD));
70 PetscCall(PicurvAssertIntEqual(remainder_min, remainder_max, "all ranks should report the same remainder"));
71 PetscFunctionReturn(0);
72}
PetscErrorCode DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
Distributes particles evenly across MPI processes, handling any remainders.
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.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestBoundingBoxCollectivesMultiRank()

static PetscErrorCode TestBoundingBoxCollectivesMultiRank ( void  )
static

Tests multi-rank bounding-box gather and broadcast helpers.

Definition at line 77 of file test_mpi_kernels.c.

78{
79 SimCtx *simCtx = NULL;
80 UserCtx *user = NULL;
81 BoundingBox local_bbox;
82 BoundingBox *boxes = NULL;
83 PetscMPIInt rank = 0, size = 1;
84 PetscReal global_min_x = 0.0;
85 PetscReal global_max_x = 0.0;
86 PetscReal expected_global_max_x = 0.0;
87
88 PetscFunctionBeginUser;
89 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
90 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
91 PetscCall(PicurvAssertBool((PetscBool)(size >= 2), "unit-mpi requires at least two MPI ranks"));
92
93 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 8, 6, 4));
94 expected_global_max_x = ((PetscReal)(user->IM - 1) / (PetscReal)user->IM) + 1.0e-6;
95 PetscCall(ComputeLocalBoundingBox(user, &local_bbox));
96 PetscCall(GatherAllBoundingBoxes(user, &boxes));
97 PetscCall(BroadcastAllBoundingBoxes(user, &boxes));
98 PetscCall(PicurvAssertBool((PetscBool)(boxes != NULL), "all ranks should hold the gathered bounding-box table"));
99
100 for (PetscMPIInt r = 0; r < size; ++r) {
101 PetscCall(PicurvAssertBool((PetscBool)(boxes[r].min_coords.x <= boxes[r].max_coords.x), "bbox x-range should be valid"));
102 PetscCall(PicurvAssertBool((PetscBool)(boxes[r].min_coords.y <= boxes[r].max_coords.y), "bbox y-range should be valid"));
103 PetscCall(PicurvAssertBool((PetscBool)(boxes[r].min_coords.z <= boxes[r].max_coords.z), "bbox z-range should be valid"));
104 }
105
106 PetscCall(PicurvAssertRealNear(local_bbox.min_coords.x, boxes[rank].min_coords.x, 1.0e-10, "local bbox min x preserved"));
107 PetscCall(PicurvAssertRealNear(local_bbox.max_coords.x, boxes[rank].max_coords.x, 1.0e-10, "local bbox max x preserved"));
108
109 PetscCallMPI(MPI_Allreduce(&local_bbox.min_coords.x, &global_min_x, 1, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD));
110 PetscCallMPI(MPI_Allreduce(&local_bbox.max_coords.x, &global_max_x, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
111 PetscCall(PicurvAssertBool((PetscBool)(global_min_x <= 0.0), "global min x should include domain start"));
112 PetscCall(PicurvAssertRealNear(expected_global_max_x, global_max_x, 1.0e-10, "global max x should match the normalized physical-node domain end"));
113
114 free(boxes);
115 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
116 PetscFunctionReturn(0);
117}
PetscErrorCode BroadcastAllBoundingBoxes(UserCtx *user, BoundingBox **bboxlist)
Broadcasts the bounding box information collected on rank 0 to all other ranks.
Definition grid.c:1061
PetscErrorCode ComputeLocalBoundingBox(UserCtx *user, BoundingBox *localBBox)
Computes the local bounding box of the grid on the current process.
Definition grid.c:850
PetscErrorCode GatherAllBoundingBoxes(UserCtx *user, BoundingBox **allBBoxes)
Gathers local bounding boxes from all MPI processes to rank 0.
Definition grid.c:999
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 PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:173
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:172
PetscScalar x
Definition variables.h:103
PetscInt IM
Definition variables.h:920
Defines a 3D axis-aligned bounding box.
Definition variables.h:171
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:906
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPeriodicCellFieldSynchronizationMultiRank()

static PetscErrorCode TestPeriodicCellFieldSynchronizationMultiRank ( void  )
static

Tests distributed synchronization of persistent cell-centered scalar fields.

Definition at line 122 of file test_mpi_kernels.c.

123{
124 SimCtx *simCtx = NULL;
125 UserCtx *user = NULL;
126 PetscReal ***p = NULL;
127 PetscReal ***cs = NULL;
128 PetscReal ***diffusivity = NULL;
129 Cmpnts ***ucat = NULL;
131 PetscInt xs, xe, ys, ye, zs, ze, mx;
132
133 PetscFunctionBeginUser;
134 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
135 MarkXPeriodic(user);
136 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
137 "periodic cell synchronization test requires the x axis to be partitioned"));
138 PetscCall(DMCreateGlobalVector(user->da, &user->CS));
139 PetscCall(DMCreateLocalVector(user->da, &user->lCs));
140
141 xs = user->info.xs;
142 xe = xs + user->info.xm;
143 ys = user->info.ys;
144 ye = ys + user->info.ym;
145 zs = user->info.zs;
146 ze = zs + user->info.zm;
147 mx = user->info.mx;
148
149 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
150 PetscCall(DMDAVecGetArray(user->da, user->CS, &cs));
151 PetscCall(DMDAVecGetArray(user->da, user->Diffusivity, &diffusivity));
152 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
153 for (PetscInt k = zs; k < ze; ++k) {
154 for (PetscInt j = ys; j < ye; ++j) {
155 for (PetscInt i = xs; i < xe; ++i) {
156 p[k][j][i] = PeriodicScalarValue(i, j, k, 0.0);
157 cs[k][j][i] = PeriodicScalarValue(i, j, k, 1000.0);
158 diffusivity[k][j][i] = PeriodicScalarValue(i, j, k, 2000.0);
159 ucat[k][j][i] = (Cmpnts){PeriodicScalarValue(i,j,k,3000.0),0.0,0.0};
160 }
161 }
162 }
163 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
164 PetscCall(DMDAVecRestoreArray(user->da, user->CS, &cs));
165 PetscCall(DMDAVecRestoreArray(user->da, user->Diffusivity, &diffusivity));
166 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
167
168 PetscCall(SynchronizePeriodicCellFields(user, 4, fields));
169
170 PetscCall(DMDAVecGetArrayRead(user->da, user->P, &p));
171 PetscCall(DMDAVecGetArrayRead(user->da, user->CS, &cs));
172 PetscCall(DMDAVecGetArrayRead(user->da, user->Diffusivity, &diffusivity));
173 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucat, &ucat));
174 if (xs == 0) {
175 for (PetscInt k = zs; k < ze; ++k) {
176 for (PetscInt j = ys; j < ye; ++j) {
177 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 0.0), p[k][j][0], 1.0e-12,
178 "distributed P negative endpoint should copy the opposite interior"));
179 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 1000.0), cs[k][j][0], 1.0e-12,
180 "distributed CS negative endpoint should copy the opposite interior"));
181 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 2000.0), diffusivity[k][j][0], 1.0e-12,
182 "distributed Diffusivity negative endpoint should copy the opposite interior"));
183 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx-2,j,k,3000.0),ucat[k][j][0].x,1e-12,
184 "distributed Ucat negative endpoint should copy the opposite interior"));
185 }
186 }
187 }
188 if (xe == mx) {
189 for (PetscInt k = zs; k < ze; ++k) {
190 for (PetscInt j = ys; j < ye; ++j) {
191 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 0.0), p[k][j][mx - 1], 1.0e-12,
192 "distributed P positive endpoint should copy the opposite interior"));
193 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 1000.0), cs[k][j][mx - 1], 1.0e-12,
194 "distributed CS positive endpoint should copy the opposite interior"));
195 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 2000.0), diffusivity[k][j][mx - 1], 1.0e-12,
196 "distributed Diffusivity positive endpoint should copy the opposite interior"));
197 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1,j,k,3000.0),ucat[k][j][mx-1].x,1e-12,
198 "distributed Ucat positive endpoint should copy the leading interior"));
199 }
200 }
201 }
202 PetscCall(DMDAVecRestoreArrayRead(user->da, user->P, &p));
203 PetscCall(DMDAVecRestoreArrayRead(user->da, user->CS, &cs));
204 PetscCall(DMDAVecRestoreArrayRead(user->da, user->Diffusivity, &diffusivity));
205 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucat, &ucat));
206 PetscCall(DMDAVecGetArrayRead(user->fda,user->lUcat,&ucat));
207 if(xs==0) PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1,2,2,3000.0),ucat[2][2][-1].x,1e-12,
208 "distributed local Ucat negative ghost follows corrected global endpoint"));
209 if(xe==mx) PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx-2,2,2,3000.0),ucat[2][2][mx].x,1e-12,
210 "distributed local Ucat positive ghost follows corrected global endpoint"));
211 PetscCall(DMDAVecRestoreArrayRead(user->fda,user->lUcat,&ucat));
212
213 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
214 PetscFunctionReturn(0);
215}
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_UCAT
@ FIELD_ID_CS
@ FIELD_ID_P
@ FIELD_ID_DIFFUSIVITY
static void MarkXPeriodic(UserCtx *user)
Marks both x boundary faces as geometric periodic boundaries.
static PetscReal PeriodicScalarValue(PetscInt i, PetscInt j, PetscInt k, PetscReal offset)
Returns a deterministic scalar value for periodic-transfer assertions.
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.
Vec lCs
Definition variables.h:982
Vec Ucat
Definition variables.h:939
Vec Diffusivity
Definition variables.h:942
DMDALocalInfo info
Definition variables.h:918
Vec lUcat
Definition variables.h:939
A 3D point or vector with PetscScalar components.
Definition variables.h:102
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPeriodicGeometryValidationMultiRank()

static PetscErrorCode TestPeriodicGeometryValidationMultiRank ( void  )
static

Tests periodic seam translation discovery when seam nodes are on different ranks.

Definition at line 219 of file test_mpi_kernels.c.

220{
221 SimCtx *simCtx = NULL;
222 UserCtx *user = NULL;
223 PetscReal expected_translation = 0.0;
224
225 PetscFunctionBeginUser;
226 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
227 MarkXPeriodic(user);
228 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
229 "periodic geometry validation test requires the x axis to be partitioned"));
230
231 expected_translation = (PetscReal)(user->info.mx - 2) / (PetscReal)user->info.mx;
232 PetscCall(ValidatePeriodicGeometry(user));
233
235 "distributed X-periodic translation should be marked valid"));
236 PetscCall(PicurvAssertRealNear(expected_translation, user->periodic_translation[0].x, 1.0e-12,
237 "distributed X-periodic translation"));
238 PetscCall(PicurvAssertRealNear(0.0, user->periodic_translation[0].y, 1.0e-12,
239 "distributed X-periodic translation y component"));
240 PetscCall(PicurvAssertRealNear(0.0, user->periodic_translation[0].z, 1.0e-12,
241 "distributed X-periodic translation z component"));
242
243 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
244 PetscFunctionReturn(0);
245}
PetscErrorCode ValidatePeriodicGeometry(UserCtx *user)
Validates that configured geometric periodic seams match by translation.
Definition grid.c:421
PetscScalar z
Definition variables.h:103
PetscScalar y
Definition variables.h:103
Cmpnts periodic_translation[3]
Definition variables.h:927
PetscBool periodic_translation_valid[3]
Definition variables.h:928
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPeriodicFaceCenterCoordinatesMultiRank()

static PetscErrorCode TestPeriodicFaceCenterCoordinatesMultiRank ( void  )
static

Tests translated face-center ghosts when the periodic axis is partitioned.

Definition at line 250 of file test_mpi_kernels.c.

251{
252 SimCtx *simCtx = NULL;
253 UserCtx *user = NULL;
254 Cmpnts ***centx = NULL;
255 const Cmpnts ***lcentx = NULL;
256 const FieldId fields[] = {FIELD_ID_CENTX};
257 PetscReal translation, spacing;
258 PetscInt xs, xe, mx;
259
260 PetscFunctionBeginUser;
261 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
262 MarkXPeriodic(user);
263 PetscCall(ValidatePeriodicGeometry(user));
264 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
265 "face-center coordinate test requires the x axis to be partitioned"));
266 translation = user->periodic_translation[0].x;
267 spacing = translation / (PetscReal)(user->info.mx - 2);
268 xs = user->info.xs;
269 xe = xs + user->info.xm;
270 mx = user->info.mx;
271
272 PetscCall(DMDAVecGetArray(user->fda, user->Centx, &centx));
273 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++) {
274 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++) {
275 for (PetscInt i = xs; i < xe; i++) {
276 centx[k][j][i] = (Cmpnts){spacing * i, 2.0 + j, 3.0 + k};
277 }
278 }
279 }
280 PetscCall(DMDAVecRestoreArray(user->fda, user->Centx, &centx));
281
282 PetscCall(SynchronizePeriodicFaceFields(user, 'i', 1, fields));
283 PetscCall(DMDAVecGetArrayRead(user->fda, user->lCentx, &lcentx));
284 if (xs == 0) {
285 PetscCall(PicurvAssertRealNear(-spacing, lcentx[2][2][-1].x, 1.0e-12,
286 "distributed translated Centx negative adjacent ghost"));
287 PetscCall(PicurvAssertRealNear(0.0, lcentx[2][2][0].x, 1.0e-12,
288 "distributed translated Centx negative endpoint"));
289 }
290 if (xe == mx) {
291 PetscCall(PicurvAssertRealNear(translation + spacing, lcentx[2][2][mx - 1].x, 1.0e-12,
292 "distributed translated Centx positive endpoint"));
293 PetscCall(PicurvAssertRealNear(translation + 2.0 * spacing, lcentx[2][2][mx].x, 1.0e-12,
294 "distributed translated Centx positive adjacent ghost"));
295 }
296 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lCentx, &lcentx));
297
298 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
299 PetscFunctionReturn(0);
300}
PetscErrorCode SynchronizePeriodicFaceFields(UserCtx *user, char face_direction, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent fields belonging to one face family.
@ FIELD_ID_CENTX
Vec Centx
Definition variables.h:975
Vec lCentx
Definition variables.h:976
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPeriodicFaceFieldSynchronizationMultiRank()

static PetscErrorCode TestPeriodicFaceFieldSynchronizationMultiRank ( void  )
static

Tests persistent I-face synchronization across an MPI-partitioned seam.

Definition at line 304 of file test_mpi_kernels.c.

305{
306 SimCtx *simCtx = NULL;
307 UserCtx *user = NULL;
308 PetscReal ***iaj = NULL;
309 const FieldId fields[] = {FIELD_ID_IAJ};
310 PetscInt xs, xe, ys, ye, zs, ze, mx;
311
312 PetscFunctionBeginUser;
313 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
314 MarkXPeriodic(user);
315 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
316 "periodic face synchronization test requires the x axis to be partitioned"));
317
318 xs = user->info.xs; xe = xs + user->info.xm;
319 ys = user->info.ys; ye = ys + user->info.ym;
320 zs = user->info.zs; ze = zs + user->info.zm;
321 mx = user->info.mx;
322
323 PetscCall(DMDAVecGetArray(user->da, user->IAj, &iaj));
324 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) for (PetscInt i = xs; i < xe; i++) {
325 iaj[k][j][i] = PeriodicScalarValue(i, j, k, 3000.0);
326 }
327 PetscCall(DMDAVecRestoreArray(user->da, user->IAj, &iaj));
328
329 PetscCall(SynchronizePeriodicFaceFields(user, 'i', 1, fields));
330
331 PetscCall(DMDAVecGetArrayRead(user->da, user->IAj, &iaj));
332 if (xs == 0) {
333 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) {
334 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 3000.0), iaj[k][j][0], 1.0e-12,
335 "distributed I-face negative seam should copy the opposite physical seam"));
336 }
337 }
338 if (xe == mx) {
339 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) {
340 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 3000.0), iaj[k][j][mx - 1], 1.0e-12,
341 "distributed I-face positive dummy should copy the leading physical face"));
342 }
343 }
344 PetscCall(DMDAVecRestoreArrayRead(user->da, user->IAj, &iaj));
345
346 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
347 PetscFunctionReturn(0);
348}
@ FIELD_ID_IAJ
Vec IAj
Definition variables.h:977
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPeriodicStaggeredFieldSynchronizationMultiRank()

static PetscErrorCode TestPeriodicStaggeredFieldSynchronizationMultiRank ( void  )
static

Tests persistent Ucont synchronization across an MPI-partitioned seam.

Definition at line 352 of file test_mpi_kernels.c.

353{
354 SimCtx *simCtx = NULL;
355 UserCtx *user = NULL;
356 Cmpnts ***ucont = NULL;
357 const FieldId fields[] = {FIELD_ID_UCONT};
358 PetscInt xs, xe, ys, ye, zs, ze, mx;
359
360 PetscFunctionBeginUser;
361 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
362 MarkXPeriodic(user);
363 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
364 "periodic staggered synchronization test requires the x axis to be partitioned"));
365
366 xs = user->info.xs; xe = xs + user->info.xm;
367 ys = user->info.ys; ye = ys + user->info.ym;
368 zs = user->info.zs; ze = zs + user->info.zm;
369 mx = user->info.mx;
370
371 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &ucont));
372 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) for (PetscInt i = xs; i < xe; i++) {
373 PetscReal value = PeriodicScalarValue(i, j, k, 0.0);
374 ucont[k][j][i] = (Cmpnts){value + 1000.0, value + 2000.0, value + 3000.0};
375 }
376 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &ucont));
377
378 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fields));
379
380 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucont, &ucont));
381 if (xs == 0) {
382 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) {
383 PetscReal expected = PeriodicScalarValue(mx - 2, j, k, 0.0);
384 PetscCall(PicurvAssertRealNear(expected + 1000.0, ucont[k][j][0].x, 1.0e-12,
385 "distributed Ucont.x negative seam"));
386 PetscCall(PicurvAssertRealNear(expected + 2000.0, ucont[k][j][0].y, 1.0e-12,
387 "distributed Ucont.y negative X endpoint"));
388 }
389 }
390 if (xe == mx) {
391 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) {
392 PetscReal expected = PeriodicScalarValue(1, j, k, 0.0);
393 PetscCall(PicurvAssertRealNear(expected + 2000.0, ucont[k][j][mx - 1].y, 1.0e-12,
394 "distributed Ucont.y positive X dummy"));
395 PetscCall(PicurvAssertRealNear(expected + 3000.0, ucont[k][j][mx - 1].z, 1.0e-12,
396 "distributed Ucont.z positive X dummy"));
397 }
398 }
399 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucont, &ucont));
400
401 PetscCall(DMDAVecGetArrayRead(user->fda, user->lUcont, &ucont));
402 if (xs == 0) {
403 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) {
404 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 3, j, k, 1000.0), ucont[k][j][-1].x, 1.0e-12,
405 "distributed Ucont.x negative adjacent ghost repair"));
406 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 2000.0), ucont[k][j][-1].y, 1.0e-12,
407 "distributed Ucont.y tangential X wraparound"));
408 }
409 }
410 if (xe == mx) {
411 for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) {
412 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(2, j, k, 1000.0), ucont[k][j][mx].x, 1.0e-12,
413 "distributed Ucont.x positive adjacent ghost repair"));
414 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 2000.0), ucont[k][j][mx].y, 1.0e-12,
415 "distributed Ucont.y positive tangential X wraparound"));
416 }
417 }
418 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lUcont, &ucont));
419
420 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
421 PetscFunctionReturn(0);
422}
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
@ FIELD_ID_UCONT
Vec Ucont
Definition variables.h:939
Vec lUcont
Definition variables.h:939
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestRestartCellIdMigrationMovesParticleToOwner()

static PetscErrorCode TestRestartCellIdMigrationMovesParticleToOwner ( void  )
static

Tests restart fast-path migration using preloaded cell ownership metadata.

Definition at line 427 of file test_mpi_kernels.c.

428{
429 SimCtx *simCtx = NULL;
430 UserCtx *user = NULL;
431 RankCellInfo my_cell_info;
432 PetscMPIInt rank = 0, size = 1;
433 PetscInt *cell_ids = NULL;
434 PetscReal *positions = NULL;
435 PetscInt nlocal = 0;
436
437 PetscFunctionBeginUser;
438 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
439 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
440 PetscCall(PicurvAssertIntEqual(2, size, "restart migration unit test expects exactly two MPI ranks"));
441
442 PetscCall(PetscMemzero(&my_cell_info, sizeof(my_cell_info)));
443 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 8, 4, 4));
444 PetscCall(PicurvCreateSwarmPair(user, 1, "ske"));
445 PetscCall(GetOwnedCellRange(&user->info, 0, &my_cell_info.xs_cell, &my_cell_info.xm_cell));
446 PetscCall(GetOwnedCellRange(&user->info, 1, &my_cell_info.ys_cell, &my_cell_info.ym_cell));
447 PetscCall(GetOwnedCellRange(&user->info, 2, &my_cell_info.zs_cell, &my_cell_info.zm_cell));
448 PetscCall(PetscMalloc1(size, &user->RankCellInfoMap));
449 PetscCallMPI(MPI_Allgather(&my_cell_info, sizeof(RankCellInfo), MPI_BYTE,
450 user->RankCellInfoMap, sizeof(RankCellInfo), MPI_BYTE,
451 PETSC_COMM_WORLD));
452
453 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
454 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void **)&positions));
455 if (rank == 0) {
456 cell_ids[0] = user->RankCellInfoMap[1].xs_cell;
457 cell_ids[1] = user->RankCellInfoMap[1].ys_cell;
458 cell_ids[2] = user->RankCellInfoMap[1].zs_cell;
459 positions[0] = 0.875;
460 positions[1] = 0.5;
461 positions[2] = 0.5;
462 } else {
463 cell_ids[0] = user->RankCellInfoMap[1].xs_cell;
464 cell_ids[1] = user->RankCellInfoMap[1].ys_cell;
465 cell_ids[2] = user->RankCellInfoMap[1].zs_cell;
466 positions[0] = 0.95;
467 positions[1] = 0.5;
468 positions[2] = 0.5;
469 }
470 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void **)&positions));
471 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
472
473 PetscCall(MigrateRestartParticlesUsingCellID(user));
474 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
475 PetscCall(PicurvAssertIntEqual((rank == 0) ? 0 : 2, nlocal,
476 "restart migration should move the foreign particle onto the owning rank"));
477
478 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
479 PetscFunctionReturn(0);
480}
PetscErrorCode MigrateRestartParticlesUsingCellID(UserCtx *user)
Fast-path migration for restart particles using preloaded Cell IDs.
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:2285
PetscErrorCode PicurvCreateSwarmPair(UserCtx *user, PetscInt nlocal, const char *post_field_name)
Creates matched solver and post-processing swarms for tests.
PetscInt ys_cell
Definition variables.h:204
PetscInt xs_cell
Definition variables.h:204
PetscInt zm_cell
Definition variables.h:205
PetscInt zs_cell
Definition variables.h:204
PetscInt xm_cell
Definition variables.h:205
RankCellInfo * RankCellInfoMap
Definition variables.h:995
PetscInt ym_cell
Definition variables.h:205
A lean struct to hold the global cell ownership range for a single MPI rank.
Definition variables.h:203
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSpatialTargetIsDecompositionIndependent()

static PetscErrorCode TestSpatialTargetIsDecompositionIndependent ( void  )
static

Spatial target domains must not depend on how ranks divide the block.

The global point count is a function of layout, global dimensions, and periodicity alone. Summing the per-rank counts must therefore reproduce the same analytic totals a single rank computes, with no point counted twice at a decomposition seam and none dropped.

Definition at line 489 of file test_mpi_kernels.c.

490{
491 SimCtx *simCtx = NULL;
492 UserCtx *user = NULL;
494 PetscInt local = 0, global = 0, rank_count = 0;
495 PetscMPIInt size = 0;
496 const PetscInt n = 6; /* DMDA is n + 1 = 7 per dimension */
497 const PetscInt cell = 5; /* cell-like span [1, 6) */
498 const PetscInt node = 6; /* node-like nonperiodic span [0, 6) */
499
500 PetscFunctionBeginUser;
501 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
502 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, n, n, n));
503
505 PetscCall(SpatialTargetPlanLocalPointCount(&plan, &local));
506 PetscCall(SpatialTargetPlanGlobalPointCount(&plan, PETSC_COMM_WORLD, &global));
507 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
508 "cell-centered global count must be decomposition independent"));
509
510 /* Every rank must contribute a non-negative count, and the ranks together
511 * must contribute the whole domain exactly once. */
512 PetscCall(PicurvAssertBool((PetscBool)(local >= 0), "local point count must be non-negative"));
513 PetscCallMPI(MPI_Allreduce(&local, &rank_count, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
514 PetscCall(PicurvAssertIntEqual(global, rank_count,
515 "summed local counts must equal the reduced global count"));
516
518 PetscCall(SpatialTargetPlanGlobalPointCount(&plan, PETSC_COMM_WORLD, &global));
519 PetscCall(PicurvAssertIntEqual(node * cell * cell, global,
520 "I-face global count must be decomposition independent"));
521
523 PetscCall(SpatialTargetPlanGlobalPointCount(&plan, PETSC_COMM_WORLD, &global));
524 PetscCall(PicurvAssertIntEqual(node * node * node, global,
525 "node-centered global count must be decomposition independent"));
526
527 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
528
529 /* Fully periodic: duplicate planes must be dropped once globally, not once per rank. */
530 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, n, n, n,
531 PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
533 PetscCall(SpatialTargetPlanGlobalPointCount(&plan, PETSC_COMM_WORLD, &global));
534 PetscCall(PicurvAssertIntEqual(cell * cell * cell, global,
535 "fully periodic node-centered count must drop duplicates exactly once"));
536 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
537 PetscFunctionReturn(0);
538}
@ FIELD_ID_CSI
@ FIELD_ID_COORDINATES
@ PICURV_STATISTICS_MASK_FLUID
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.
Resolved iteration domain for one field on one block.
A generic C-style linked list node for integers.
Definition variables.h:439
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestStatisticsCheckpointRoundTripMultiRank()

static PetscErrorCode TestStatisticsCheckpointRoundTripMultiRank ( void  )
static

Statistics payloads must survive a checkpoint round trip under decomposition.

The write path gathers each accumulator into natural ordering before it reaches disk, and the read path scatters it back. That pairing is where a decomposition bug would live, so this drives the whole cycle on more than one rank and requires an exact match: the format stores IEEE doubles, and natural ordering is defined to be independent of how ranks divide the block.

Definition at line 549 of file test_mpi_kernels.c.

550{
551 SimCtx *simCtx = NULL;
552 UserCtx *user = NULL;
553 PicurvWindow window;
554 PicurvWindowStorage storage;
555 PicurvWindowDefinition definition;
556 Vec *reference = NULL;
557 char tmpdir[PETSC_MAX_PATH_LEN];
558 PetscInt payload_count = 0;
559 PetscMPIInt size = 0;
560
561 PetscFunctionBeginUser;
562 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
563 PetscCall(PicurvAssertBool((PetscBool)(size >= 2), "unit-mpi requires at least two MPI ranks"));
564
565 memset(&definition, 0, sizeof(definition));
566 strncpy(definition.name, "production", PICURV_WINDOW_NAME_LENGTH - 1);
569 definition.step_cadence = 1;
570 definition.field_count = 2;
571 definition.fields[0].field_id = FIELD_ID_UCAT; definition.fields[0].want_second = PETSC_TRUE;
572 definition.fields[1].field_id = FIELD_ID_P; definition.fields[1].want_second = PETSC_TRUE;
573 definition.covariance_count = 1;
574 definition.covariances[0].first = FIELD_ID_UCAT;
575 definition.covariances[0].second = FIELD_ID_P;
576
577 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
578 tmpdir[0] = '\0';
579 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
580 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
581 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
582 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
583 PetscCall(PicurvPopulateIdentityMetrics(user));
584 PetscCall(VecSet(user->Nvert, 0.0));
585
586 PetscCall(PicurvWindowInit(&window, &definition));
587 PetscCall(PicurvWindowStorageCreate(user, &definition, &storage));
588 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
589 simCtx->fieldStatisticsWindowCount = 1;
590 simCtx->fieldStatisticsWindows = &window;
591 user->fieldStatisticsStorage = &storage;
592
593 /* A spatially varying field makes the assertion meaningful: a payload gathered
594 * or scattered through the wrong owner comes back permuted, which a uniform
595 * field could not reveal. */
596 for (PetscInt s = 0; s < 4; ++s) {
597 PetscBool accepted = PETSC_FALSE;
598 PetscReal weight = 0.0;
599 PetscReal ***p = NULL;
600 Cmpnts ***ucat = NULL;
601 const DMDALocalInfo info = user->info;
602
603 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
604 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
605 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k)
606 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j)
607 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
608 const PetscReal tag = (PetscReal)(100 * k + 10 * j + i);
609
610 p[k][j][i] = tag + 0.25 * (PetscReal)s;
611 ucat[k][j][i].x = tag;
612 ucat[k][j][i].y = tag + 1.0 + (PetscReal)s;
613 ucat[k][j][i].z = tag - 1.0;
614 }
615 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
616 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
617
618 PetscCall(PicurvWindowOfferState(&window, s, 0.5 * (PetscReal)s, &accepted, &weight));
619 if (accepted) PetscCall(PicurvWindowAccumulate(user, &definition, &storage, weight));
620 }
621 PetscCall(PicurvAssertIntEqual(3, window.sample_count, "three intervals are represented"));
622
623 PetscCall(WriteCheckpointBundle(simCtx, "test"));
624
625 PetscCall(PicurvWindowStoragePayloadCount(&storage, &payload_count));
626 PetscCall(PetscCalloc1((size_t)payload_count, &reference));
627 for (PetscInt index = 0; index < payload_count; ++index) {
629
630 PetscCall(PicurvWindowStoragePayload(user, &definition, &storage, index, &payload));
631 PetscCall(VecDuplicate(payload.vec, &reference[index]));
632 PetscCall(VecCopy(payload.vec, reference[index]));
633 PetscCall(VecZeroEntries(payload.vec));
634 }
635 PetscCall(PicurvWindowInit(&window, &definition));
636
637 simCtx->fieldStatisticsContinue = PETSC_TRUE;
638 PetscCall(RestoreFieldStatisticsState(simCtx, simCtx->step));
639 PetscCall(PicurvAssertIntEqual(3, window.sample_count, "window bookkeeping survives on every rank"));
640 PetscCall(PicurvAssertRealNear(1.5, window.total_weight, 1.0e-12,
641 "physical-time weights survive on every rank"));
642
643 for (PetscInt index = 0; index < payload_count; ++index) {
645 PetscReal difference = 0.0;
646 char context[192];
647
648 PetscCall(PicurvWindowStoragePayload(user, &definition, &storage, index, &payload));
649 PetscCall(VecAXPY(reference[index], -1.0, payload.vec));
650 PetscCall(VecNorm(reference[index], NORM_INFINITY, &difference));
651 PetscCall(PetscSNPrintf(context, sizeof(context),
652 "payload '%s' round trips exactly across %d ranks",
653 payload.name, (int)size));
654 PetscCall(PicurvAssertBool((PetscBool)(difference == 0.0), context));
655 PetscCall(VecDestroy(&reference[index]));
656 }
657 PetscCall(PetscFree(reference));
658
659 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
660 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
661 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
662 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
663 simCtx->fieldStatisticsWindowCount = 0;
664 simCtx->fieldStatisticsWindows = NULL;
665 user->fieldStatisticsStorage = NULL;
666 PetscCall(PicurvWindowStorageDestroy(&storage));
667 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
668 PetscFunctionReturn(0);
669}
PetscErrorCode RestoreFieldStatisticsState(SimCtx *simCtx, PetscInt ti)
Restores field-statistics window state and accumulators from a checkpoint.
Definition io.c:1667
PetscErrorCode WriteCheckpointBundle(SimCtx *simCtx, const char *reason)
Write and atomically publish one complete checkpoint bundle.
Definition io.c:2530
Vec vec
Borrowed accumulator vector; never owned by the caller.
PetscErrorCode PicurvWindowStorageCreate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage)
Allocates the accumulator state one window owns on one block.
PetscErrorCode PicurvWindowStoragePayload(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt index, PicurvStatisticsPayload *payload)
Resolves one enumerated payload of a window's storage.
char name[96]
File basename, no extension.
PetscErrorCode PicurvWindowAccumulate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage, PetscReal weight)
Applies one accepted completed state to a window's accumulators.
PetscErrorCode PicurvWindowStorageDestroy(PicurvWindowStorage *storage)
Releases accumulator state previously created for one window.
PetscErrorCode PicurvWindowStoragePayloadCount(const PicurvWindowStorage *storage, PetscInt *count)
Reports how many checkpointable vectors one window's storage holds.
One checkpointable accumulator vector, resolved by enumeration index.
Independent accumulator state for one window on one block.
PetscInt sample_count
PetscInt first
First member; must also appear in the field list.
PicurvWindowFieldRequest fields[16]
PicurvCadenceKind cadence_kind
PetscReal total_weight
PetscInt step_cadence
Used when cadence_kind is step; must be positive.
#define PICURV_WINDOW_NAME_LENGTH
Maximum stored length of a window name, including the terminator.
PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
Validates a definition and initializes a window to the pending state.
PetscErrorCode PicurvWindowOfferState(PicurvWindow *window, PetscInt step, PetscReal time, PetscBool *accepted, PetscReal *weight)
Offers one completed state to a window and reports the decision.
PetscBool want_second
Also keep the centered second moment.
PetscInt second
Second member; must also appear in the field list.
PicurvWindowCovarianceRequest covariances[16]
PetscInt field_id
Catalogued Eulerian field identity.
@ PICURV_WEIGHTING_PHYSICAL_TIME
Weight is the represented interval.
@ PICURV_CADENCE_STEP
Every n completed steps from activation.
Runtime state of one window.
The scientifically immutable definition of one window.
PetscErrorCode PicurvMakeTempDir(char *path, size_t path_len)
Creates a unique temporary directory for one test case.
PetscErrorCode PicurvPopulateIdentityMetrics(UserCtx *user)
Populates identity metric vectors on the minimal grid fixture.
PetscErrorCode PicurvRemoveTempDir(const char *path)
Recursively removes a temporary directory created by PicurvMakeTempDir.
PetscInt fieldStatisticsWindowCount
Definition variables.h:770
PetscMPIInt rank
Definition variables.h:698
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:717
PetscBool fieldStatisticsEnabled
Definition variables.h:769
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:771
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:962
PetscInt step
Definition variables.h:703
Vec Nvert
Definition variables.h:939
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:716
PetscBool fieldStatisticsContinue
Definition variables.h:776
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Runs the unit-mpi PETSc test binary.

Definition at line 674 of file test_mpi_kernels.c.

675{
676 PetscErrorCode ierr;
677 const PicurvTestCase cases[] = {
678 {"distribute-particles-collective-consistency", TestDistributeParticlesCollectiveConsistency},
679 {"bounding-box-collectives-multi-rank", TestBoundingBoxCollectivesMultiRank},
680 {"periodic-cell-field-synchronization-multi-rank", TestPeriodicCellFieldSynchronizationMultiRank},
681 {"periodic-geometry-validation-multi-rank", TestPeriodicGeometryValidationMultiRank},
682 {"periodic-face-center-coordinates-multi-rank", TestPeriodicFaceCenterCoordinatesMultiRank},
683 {"periodic-face-field-synchronization-multi-rank", TestPeriodicFaceFieldSynchronizationMultiRank},
684 {"periodic-staggered-field-synchronization-multi-rank", TestPeriodicStaggeredFieldSynchronizationMultiRank},
685 {"spatial-target-decomposition-independent", TestSpatialTargetIsDecompositionIndependent},
686 {"statistics-checkpoint-round-trip-multi-rank", TestStatisticsCheckpointRoundTripMultiRank},
687 {"restart-cellid-migration-moves-particle-to-owner", TestRestartCellIdMigrationMovesParticleToOwner},
688 };
689
690 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv MPI-focused runtime tests");
691 if (ierr) {
692 return (int)ierr;
693 }
694
695 ierr = PicurvRunTests("unit-mpi", cases, sizeof(cases) / sizeof(cases[0]));
696 if (ierr) {
697 PetscFinalize();
698 return (int)ierr;
699 }
700
701 ierr = PetscFinalize();
702 return (int)ierr;
703}
static PetscErrorCode TestSpatialTargetIsDecompositionIndependent(void)
Spatial target domains must not depend on how ranks divide the block.
static PetscErrorCode TestPeriodicFaceCenterCoordinatesMultiRank(void)
Tests translated face-center ghosts when the periodic axis is partitioned.
static PetscErrorCode TestPeriodicFaceFieldSynchronizationMultiRank(void)
Tests persistent I-face synchronization across an MPI-partitioned seam.
static PetscErrorCode TestRestartCellIdMigrationMovesParticleToOwner(void)
Tests restart fast-path migration using preloaded cell ownership metadata.
static PetscErrorCode TestPeriodicGeometryValidationMultiRank(void)
Tests periodic seam translation discovery when seam nodes are on different ranks.
static PetscErrorCode TestStatisticsCheckpointRoundTripMultiRank(void)
Statistics payloads must survive a checkpoint round trip under decomposition.
static PetscErrorCode TestPeriodicStaggeredFieldSynchronizationMultiRank(void)
Tests persistent Ucont synchronization across an MPI-partitioned seam.
static PetscErrorCode TestPeriodicCellFieldSynchronizationMultiRank(void)
Tests distributed synchronization of persistent cell-centered scalar fields.
static PetscErrorCode TestDistributeParticlesCollectiveConsistency(void)
Tests collective particle distribution consistency across MPI ranks.
static PetscErrorCode TestBoundingBoxCollectivesMultiRank(void)
Tests multi-rank bounding-box gather and broadcast helpers.
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.
Named test case descriptor consumed by PicurvRunTests.
Here is the call graph for this function: