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 <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.
 
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 18 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 31 of file test_mpi_kernels.c.

32{
33 return offset + (PetscReal)(i + 10 * j + 100 * k);
34}
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 39 of file test_mpi_kernels.c.

40{
41 PetscMPIInt rank = 0, size = 1;
42 PetscInt local_particles = 0;
43 PetscInt remainder = 0;
44 PetscInt global_particles = 0;
45 PetscInt remainder_min = 0, remainder_max = 0;
46 const PetscInt total_particles = 137;
47
48 PetscFunctionBeginUser;
49 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
50 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
51 PetscCall(PicurvAssertBool((PetscBool)(size >= 2), "unit-mpi requires at least two MPI ranks"));
52
53 PetscCall(DistributeParticles(total_particles, rank, size, &local_particles, &remainder));
54
55 PetscCall(PicurvAssertIntEqual(
56 total_particles / size + (((PetscInt)rank < remainder) ? 1 : 0),
57 local_particles,
58 "local particle share should match quotient+remainder policy"));
59
60 PetscCallMPI(MPI_Allreduce(&local_particles, &global_particles, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
61 PetscCall(PicurvAssertIntEqual(total_particles, global_particles, "distributed particle count must conserve total particles"));
62
63 PetscCallMPI(MPI_Allreduce(&remainder, &remainder_min, 1, MPIU_INT, MPI_MIN, PETSC_COMM_WORLD));
64 PetscCallMPI(MPI_Allreduce(&remainder, &remainder_max, 1, MPIU_INT, MPI_MAX, PETSC_COMM_WORLD));
65 PetscCall(PicurvAssertIntEqual(remainder_min, remainder_max, "all ranks should report the same remainder"));
66 PetscFunctionReturn(0);
67}
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 72 of file test_mpi_kernels.c.

73{
74 SimCtx *simCtx = NULL;
75 UserCtx *user = NULL;
76 BoundingBox local_bbox;
77 BoundingBox *boxes = NULL;
78 PetscMPIInt rank = 0, size = 1;
79 PetscReal global_min_x = 0.0;
80 PetscReal global_max_x = 0.0;
81 PetscReal expected_global_max_x = 0.0;
82
83 PetscFunctionBeginUser;
84 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
85 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
86 PetscCall(PicurvAssertBool((PetscBool)(size >= 2), "unit-mpi requires at least two MPI ranks"));
87
88 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 8, 6, 4));
89 expected_global_max_x = ((PetscReal)(user->IM - 1) / (PetscReal)user->IM) + 1.0e-6;
90 PetscCall(ComputeLocalBoundingBox(user, &local_bbox));
91 PetscCall(GatherAllBoundingBoxes(user, &boxes));
92 PetscCall(BroadcastAllBoundingBoxes(user, &boxes));
93 PetscCall(PicurvAssertBool((PetscBool)(boxes != NULL), "all ranks should hold the gathered bounding-box table"));
94
95 for (PetscMPIInt r = 0; r < size; ++r) {
96 PetscCall(PicurvAssertBool((PetscBool)(boxes[r].min_coords.x <= boxes[r].max_coords.x), "bbox x-range should be valid"));
97 PetscCall(PicurvAssertBool((PetscBool)(boxes[r].min_coords.y <= boxes[r].max_coords.y), "bbox y-range should be valid"));
98 PetscCall(PicurvAssertBool((PetscBool)(boxes[r].min_coords.z <= boxes[r].max_coords.z), "bbox z-range should be valid"));
99 }
100
101 PetscCall(PicurvAssertRealNear(local_bbox.min_coords.x, boxes[rank].min_coords.x, 1.0e-10, "local bbox min x preserved"));
102 PetscCall(PicurvAssertRealNear(local_bbox.max_coords.x, boxes[rank].max_coords.x, 1.0e-10, "local bbox max x preserved"));
103
104 PetscCallMPI(MPI_Allreduce(&local_bbox.min_coords.x, &global_min_x, 1, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD));
105 PetscCallMPI(MPI_Allreduce(&local_bbox.max_coords.x, &global_max_x, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
106 PetscCall(PicurvAssertBool((PetscBool)(global_min_x <= 0.0), "global min x should include domain start"));
107 PetscCall(PicurvAssertRealNear(expected_global_max_x, global_max_x, 1.0e-10, "global max x should match the normalized physical-node domain end"));
108
109 free(boxes);
110 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
111 PetscFunctionReturn(0);
112}
PetscErrorCode BroadcastAllBoundingBoxes(UserCtx *user, BoundingBox **bboxlist)
Broadcasts the bounding box information collected on rank 0 to all other ranks.
Definition grid.c:1016
PetscErrorCode ComputeLocalBoundingBox(UserCtx *user, BoundingBox *localBBox)
Computes the local bounding box of the grid on the current process.
Definition grid.c:812
PetscErrorCode GatherAllBoundingBoxes(UserCtx *user, BoundingBox **allBBoxes)
Gathers local bounding boxes from all MPI processes to rank 0.
Definition grid.c:954
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:171
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:170
PetscScalar x
Definition variables.h:101
PetscInt IM
Definition variables.h:885
Defines a 3D axis-aligned bounding box.
Definition variables.h:169
The master context for the entire simulation.
Definition variables.h:684
User-defined context containing data specific to a single computational grid level.
Definition variables.h:876
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 117 of file test_mpi_kernels.c.

118{
119 SimCtx *simCtx = NULL;
120 UserCtx *user = NULL;
121 PetscReal ***p = NULL;
122 PetscReal ***cs = NULL;
123 PetscReal ***diffusivity = NULL;
124 Cmpnts ***ucat = NULL;
125 const char *fields[] = {"P", "CS", "Diffusivity", "Ucat"};
126 PetscInt xs, xe, ys, ye, zs, ze, mx;
127
128 PetscFunctionBeginUser;
129 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
130 MarkXPeriodic(user);
131 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
132 "periodic cell synchronization test requires the x axis to be partitioned"));
133 PetscCall(DMCreateGlobalVector(user->da, &user->CS));
134 PetscCall(DMCreateLocalVector(user->da, &user->lCs));
135
136 xs = user->info.xs;
137 xe = xs + user->info.xm;
138 ys = user->info.ys;
139 ye = ys + user->info.ym;
140 zs = user->info.zs;
141 ze = zs + user->info.zm;
142 mx = user->info.mx;
143
144 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
145 PetscCall(DMDAVecGetArray(user->da, user->CS, &cs));
146 PetscCall(DMDAVecGetArray(user->da, user->Diffusivity, &diffusivity));
147 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
148 for (PetscInt k = zs; k < ze; ++k) {
149 for (PetscInt j = ys; j < ye; ++j) {
150 for (PetscInt i = xs; i < xe; ++i) {
151 p[k][j][i] = PeriodicScalarValue(i, j, k, 0.0);
152 cs[k][j][i] = PeriodicScalarValue(i, j, k, 1000.0);
153 diffusivity[k][j][i] = PeriodicScalarValue(i, j, k, 2000.0);
154 ucat[k][j][i] = (Cmpnts){PeriodicScalarValue(i,j,k,3000.0),0.0,0.0};
155 }
156 }
157 }
158 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
159 PetscCall(DMDAVecRestoreArray(user->da, user->CS, &cs));
160 PetscCall(DMDAVecRestoreArray(user->da, user->Diffusivity, &diffusivity));
161 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
162
163 PetscCall(SynchronizePeriodicCellFields(user, 4, fields));
164
165 PetscCall(DMDAVecGetArrayRead(user->da, user->P, &p));
166 PetscCall(DMDAVecGetArrayRead(user->da, user->CS, &cs));
167 PetscCall(DMDAVecGetArrayRead(user->da, user->Diffusivity, &diffusivity));
168 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucat, &ucat));
169 if (xs == 0) {
170 for (PetscInt k = zs; k < ze; ++k) {
171 for (PetscInt j = ys; j < ye; ++j) {
172 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 0.0), p[k][j][0], 1.0e-12,
173 "distributed P negative endpoint should copy the opposite interior"));
174 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 1000.0), cs[k][j][0], 1.0e-12,
175 "distributed CS negative endpoint should copy the opposite interior"));
176 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx - 2, j, k, 2000.0), diffusivity[k][j][0], 1.0e-12,
177 "distributed Diffusivity negative endpoint should copy the opposite interior"));
178 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx-2,j,k,3000.0),ucat[k][j][0].x,1e-12,
179 "distributed Ucat negative endpoint should copy the opposite interior"));
180 }
181 }
182 }
183 if (xe == mx) {
184 for (PetscInt k = zs; k < ze; ++k) {
185 for (PetscInt j = ys; j < ye; ++j) {
186 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 0.0), p[k][j][mx - 1], 1.0e-12,
187 "distributed P positive endpoint should copy the opposite interior"));
188 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 1000.0), cs[k][j][mx - 1], 1.0e-12,
189 "distributed CS positive endpoint should copy the opposite interior"));
190 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1, j, k, 2000.0), diffusivity[k][j][mx - 1], 1.0e-12,
191 "distributed Diffusivity positive endpoint should copy the opposite interior"));
192 PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1,j,k,3000.0),ucat[k][j][mx-1].x,1e-12,
193 "distributed Ucat positive endpoint should copy the leading interior"));
194 }
195 }
196 }
197 PetscCall(DMDAVecRestoreArrayRead(user->da, user->P, &p));
198 PetscCall(DMDAVecRestoreArrayRead(user->da, user->CS, &cs));
199 PetscCall(DMDAVecRestoreArrayRead(user->da, user->Diffusivity, &diffusivity));
200 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucat, &ucat));
201 PetscCall(DMDAVecGetArrayRead(user->fda,user->lUcat,&ucat));
202 if(xs==0) PetscCall(PicurvAssertRealNear(PeriodicScalarValue(1,2,2,3000.0),ucat[2][2][-1].x,1e-12,
203 "distributed local Ucat negative ghost follows corrected global endpoint"));
204 if(xe==mx) PetscCall(PicurvAssertRealNear(PeriodicScalarValue(mx-2,2,2,3000.0),ucat[2][2][mx].x,1e-12,
205 "distributed local Ucat positive ghost follows corrected global endpoint"));
206 PetscCall(DMDAVecRestoreArrayRead(user->fda,user->lUcat,&ucat));
207
208 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
209 PetscFunctionReturn(0);
210}
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
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:935
Vec Ucat
Definition variables.h:904
Vec Diffusivity
Definition variables.h:907
DMDALocalInfo info
Definition variables.h:883
Vec lUcat
Definition variables.h:904
A 3D point or vector with PetscScalar components.
Definition variables.h:100
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 214 of file test_mpi_kernels.c.

215{
216 SimCtx *simCtx = NULL;
217 UserCtx *user = NULL;
218 PetscReal expected_translation = 0.0;
219
220 PetscFunctionBeginUser;
221 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 8, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
222 MarkXPeriodic(user);
223 PetscCall(PicurvAssertBool((PetscBool)(user->info.xm < user->info.mx),
224 "periodic geometry validation test requires the x axis to be partitioned"));
225
226 expected_translation = (PetscReal)(user->info.mx - 2) / (PetscReal)user->info.mx;
227 PetscCall(ValidatePeriodicGeometry(user));
228
230 "distributed X-periodic translation should be marked valid"));
231 PetscCall(PicurvAssertRealNear(expected_translation, user->periodic_translation[0].x, 1.0e-12,
232 "distributed X-periodic translation"));
233 PetscCall(PicurvAssertRealNear(0.0, user->periodic_translation[0].y, 1.0e-12,
234 "distributed X-periodic translation y component"));
235 PetscCall(PicurvAssertRealNear(0.0, user->periodic_translation[0].z, 1.0e-12,
236 "distributed X-periodic translation z component"));
237
238 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
239 PetscFunctionReturn(0);
240}
PetscErrorCode ValidatePeriodicGeometry(UserCtx *user)
Validates that configured geometric periodic seams match by translation.
Definition grid.c:380
PetscScalar z
Definition variables.h:101
PetscScalar y
Definition variables.h:101
Cmpnts periodic_translation[3]
Definition variables.h:892
PetscBool periodic_translation_valid[3]
Definition variables.h:893
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 245 of file test_mpi_kernels.c.

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

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

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

423{
424 SimCtx *simCtx = NULL;
425 UserCtx *user = NULL;
426 RankCellInfo my_cell_info;
427 PetscMPIInt rank = 0, size = 1;
428 PetscInt *cell_ids = NULL;
429 PetscReal *positions = NULL;
430 PetscInt nlocal = 0;
431
432 PetscFunctionBeginUser;
433 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
434 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
435 PetscCall(PicurvAssertIntEqual(2, size, "restart migration unit test expects exactly two MPI ranks"));
436
437 PetscCall(PetscMemzero(&my_cell_info, sizeof(my_cell_info)));
438 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 8, 4, 4));
439 PetscCall(PicurvCreateSwarmPair(user, 1, "ske"));
440 PetscCall(GetOwnedCellRange(&user->info, 0, &my_cell_info.xs_cell, &my_cell_info.xm_cell));
441 PetscCall(GetOwnedCellRange(&user->info, 1, &my_cell_info.ys_cell, &my_cell_info.ym_cell));
442 PetscCall(GetOwnedCellRange(&user->info, 2, &my_cell_info.zs_cell, &my_cell_info.zm_cell));
443 PetscCall(PetscMalloc1(size, &user->RankCellInfoMap));
444 PetscCallMPI(MPI_Allgather(&my_cell_info, sizeof(RankCellInfo), MPI_BYTE,
445 user->RankCellInfoMap, sizeof(RankCellInfo), MPI_BYTE,
446 PETSC_COMM_WORLD));
447
448 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
449 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void **)&positions));
450 if (rank == 0) {
451 cell_ids[0] = user->RankCellInfoMap[1].xs_cell;
452 cell_ids[1] = user->RankCellInfoMap[1].ys_cell;
453 cell_ids[2] = user->RankCellInfoMap[1].zs_cell;
454 positions[0] = 0.875;
455 positions[1] = 0.5;
456 positions[2] = 0.5;
457 } else {
458 cell_ids[0] = user->RankCellInfoMap[1].xs_cell;
459 cell_ids[1] = user->RankCellInfoMap[1].ys_cell;
460 cell_ids[2] = user->RankCellInfoMap[1].zs_cell;
461 positions[0] = 0.95;
462 positions[1] = 0.5;
463 positions[2] = 0.5;
464 }
465 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void **)&positions));
466 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
467
468 PetscCall(MigrateRestartParticlesUsingCellID(user));
469 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
470 PetscCall(PicurvAssertIntEqual((rank == 0) ? 0 : 2, nlocal,
471 "restart migration should move the foreign particle onto the owning rank"));
472
473 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
474 PetscFunctionReturn(0);
475}
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:2382
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:202
PetscInt xs_cell
Definition variables.h:202
PetscInt zm_cell
Definition variables.h:203
PetscInt zs_cell
Definition variables.h:202
PetscInt xm_cell
Definition variables.h:203
RankCellInfo * RankCellInfoMap
Definition variables.h:951
PetscInt ym_cell
Definition variables.h:203
A lean struct to hold the global cell ownership range for a single MPI rank.
Definition variables.h:201
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 480 of file test_mpi_kernels.c.

481{
482 PetscErrorCode ierr;
483 const PicurvTestCase cases[] = {
484 {"distribute-particles-collective-consistency", TestDistributeParticlesCollectiveConsistency},
485 {"bounding-box-collectives-multi-rank", TestBoundingBoxCollectivesMultiRank},
486 {"periodic-cell-field-synchronization-multi-rank", TestPeriodicCellFieldSynchronizationMultiRank},
487 {"periodic-geometry-validation-multi-rank", TestPeriodicGeometryValidationMultiRank},
488 {"periodic-face-center-coordinates-multi-rank", TestPeriodicFaceCenterCoordinatesMultiRank},
489 {"periodic-face-field-synchronization-multi-rank", TestPeriodicFaceFieldSynchronizationMultiRank},
490 {"periodic-staggered-field-synchronization-multi-rank", TestPeriodicStaggeredFieldSynchronizationMultiRank},
491 {"restart-cellid-migration-moves-particle-to-owner", TestRestartCellIdMigrationMovesParticleToOwner},
492 };
493
494 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv MPI-focused runtime tests");
495 if (ierr) {
496 return (int)ierr;
497 }
498
499 ierr = PicurvRunTests("unit-mpi", cases, sizeof(cases) / sizeof(cases[0]));
500 if (ierr) {
501 PetscFinalize();
502 return (int)ierr;
503 }
504
505 ierr = PetscFinalize();
506 return (int)ierr;
507}
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 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: