PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
test_periodic_dev.c
Go to the documentation of this file.
1/**
2 * @file test_periodic_dev.c
3 * @brief Focused geometric-periodic boundary tests.
4 */
5
6#include "test_support.h"
7#include "Metric.h"
8
9#include "Boundaries.h"
10#include "walkingsearch.h"
11#include "setup.h"
12
13/**
14 * @brief Destroys one boundary-condition handler allocated by a periodic test.
15 */
16static PetscErrorCode DestroyBoundaryHandler(BoundaryCondition **bc_ptr)
17{
18 BoundaryCondition *bc = NULL;
19
20 PetscFunctionBeginUser;
21 if (!bc_ptr || !*bc_ptr) PetscFunctionReturn(0);
22
23 bc = *bc_ptr;
24 if (bc->Destroy) {
25 PetscCall(bc->Destroy(bc));
26 }
27 PetscCall(PetscFree(bc));
28 *bc_ptr = NULL;
29 PetscFunctionReturn(0);
30}
31/**
32 * @brief Marks the x faces as periodic for periodic-transfer harnesses.
33 */
43/**
44 * @brief Marks the y faces as periodic for periodic-transfer harnesses.
45 */
55/**
56 * @brief Tests periodic configuration rejects an unpaired geometric periodic face.
57 */
59{
60 SimCtx *simCtx = NULL;
61 UserCtx *user = NULL;
62 PetscErrorCode ierr_validate = 0;
63
64 PetscFunctionBeginUser;
65 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
68
69 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
70 ierr_validate = BoundarySystem_Validate(user);
71 PetscCall(PetscPopErrorHandler());
72
73 PetscCall(PicurvAssertBool((PetscBool)(ierr_validate != 0), "unpaired periodic faces should be rejected"));
74 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
75 PetscFunctionReturn(0);
76}
77/**
78 * @brief Tests constant translational periodic geometry is accepted and stored.
79 */
80static PetscErrorCode TestPeriodicGeometryStoresTranslation(void)
81{
82 SimCtx *simCtx = NULL;
83 UserCtx *user = NULL;
84 Vec gcoor = NULL;
85 const Cmpnts ***coor = NULL;
86 PetscReal expected_x = 0.0;
87
88 PetscFunctionBeginUser;
89 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
90 MarkXPeriodic(user);
91
92 PetscCall(DMGetCoordinates(user->da, &gcoor));
93 PetscCall(DMDAVecGetArrayRead(user->fda, gcoor, &coor));
94 expected_x = coor[0][0][user->info.mx - 2].x - coor[0][0][0].x;
95 PetscCall(DMDAVecRestoreArrayRead(user->fda, gcoor, &coor));
96
97 PetscCall(ValidatePeriodicGeometry(user));
98 PetscCall(PicurvAssertBool(user->periodic_translation_valid[0], "X-periodic translation should be marked valid"));
99 PetscCall(PicurvAssertBool((PetscBool)!user->periodic_translation_valid[1], "Y translation should remain invalid"));
100 PetscCall(PicurvAssertBool((PetscBool)!user->periodic_translation_valid[2], "Z translation should remain invalid"));
101 PetscCall(PicurvAssertRealNear(expected_x, user->periodic_translation[0].x, 1.0e-12, "stored X translation"));
102 PetscCall(PicurvAssertRealNear(0.0, user->periodic_translation[0].y, 1.0e-12, "stored X translation y component"));
103 PetscCall(PicurvAssertRealNear(0.0, user->periodic_translation[0].z, 1.0e-12, "stored X translation z component"));
104
105 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
106 PetscFunctionReturn(0);
107}
108/**
109 * @brief Tests that a particle beyond either x-periodic face re-enters through the paired face, shifted by the seam translation.
110 */
112{
113 SimCtx *simCtx = NULL;
114 UserCtx *user = NULL;
115 Particle particle;
117 Vec gcoor = NULL;
118 const Cmpnts ***coor = NULL;
119 PetscReal x0, y0, T, Ty, yc, zc;
120
121 PetscFunctionBeginUser;
122 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE));
123 MarkXPeriodic(user);
124 MarkYPeriodic(user);
125 PetscCall(ValidatePeriodicGeometry(user));
130 PetscCall(SetupDomainCellDecompositionMap(user));
132
133 /* Seam origin, translation, and the centre of the (., 1, 1) cell row in y and z. */
134 PetscCall(DMGetCoordinates(user->da, &gcoor));
135 PetscCall(DMDAVecGetArrayRead(user->fda, gcoor, &coor));
136 x0 = coor[0][0][0].x;
137 y0 = coor[0][0][0].y;
138 yc = 0.5 * (coor[1][1][0].y + coor[1][2][0].y);
139 zc = 0.5 * (coor[1][1][0].z + coor[2][1][0].z);
140 PetscCall(DMDAVecRestoreArrayRead(user->fda, gcoor, &coor));
141 T = user->periodic_translation[0].x;
142 Ty = user->periodic_translation[1].y;
143
144 /* Beyond -Xi out of cell 0: re-enters at the +Xi end. */
145 PetscCall(PetscMemzero(&particle, sizeof(particle)));
146 particle.PID = 51;
147 particle.cell[0] = 0; particle.cell[1] = 1; particle.cell[2] = 1;
148 particle.loc.x = x0 - 0.01 * T; particle.loc.y = yc; particle.loc.z = zc;
149 PetscCall(LocateParticleOrFindMigrationTarget(user, &particle, &status));
150 PetscCall(PicurvAssertIntEqual(ACTIVE_AND_LOCATED, status, "a wrapped particle should be located"));
151 PetscCall(PicurvAssertRealNear(x0 + 0.99 * T, particle.loc.x, 1.0e-12, "x shifts forward by the seam translation"));
152 PetscCall(PicurvAssertIntEqual(user->IM - 2, particle.cell[0], "the particle lands in the last cell"));
153
154 /* Beyond +Xi out of the last cell: re-enters at the -Xi end. */
155 PetscCall(PetscMemzero(&particle, sizeof(particle)));
156 particle.PID = 52;
157 particle.cell[0] = user->IM - 2; particle.cell[1] = 1; particle.cell[2] = 1;
158 particle.loc.x = x0 + 1.01 * T; particle.loc.y = yc; particle.loc.z = zc;
159 PetscCall(LocateParticleOrFindMigrationTarget(user, &particle, &status));
160 PetscCall(PicurvAssertIntEqual(ACTIVE_AND_LOCATED, status, "a wrapped particle should be located"));
161 PetscCall(PicurvAssertRealNear(x0 + 0.01 * T, particle.loc.x, 1.0e-12, "x shifts back by the seam translation"));
162 PetscCall(PicurvAssertIntEqual(0, particle.cell[0], "the particle lands in the first cell"));
163
164 /* Beyond -Xi and -Eta out of the corner cell: both seams are crossed in one wrap step. */
165 PetscCall(PetscMemzero(&particle, sizeof(particle)));
166 particle.PID = 53;
167 particle.cell[0] = 0; particle.cell[1] = 0; particle.cell[2] = 1;
168 particle.loc.x = x0 - 0.01 * T; particle.loc.y = y0 - 0.01 * Ty; particle.loc.z = zc;
169 PetscCall(LocateParticleOrFindMigrationTarget(user, &particle, &status));
170 PetscCall(PicurvAssertIntEqual(ACTIVE_AND_LOCATED, status, "a corner-wrapped particle should be located"));
171 PetscCall(PicurvAssertRealNear(x0 + 0.99 * T, particle.loc.x, 1.0e-12, "x shifts forward at the corner"));
172 PetscCall(PicurvAssertRealNear(y0 + 0.99 * Ty, particle.loc.y, 1.0e-12, "y shifts forward at the corner"));
173 PetscCall(PicurvAssertIntEqual(user->IM - 2, particle.cell[0], "the corner particle lands in the last i cell"));
174 PetscCall(PicurvAssertIntEqual(user->JM - 2, particle.cell[1], "the corner particle lands in the last j cell"));
175 PetscCall(PicurvAssertIntEqual(4, (PetscInt)simCtx->searchMetrics.wrapCount, "one wrap per crossed periodic face"));
176
177 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
178 PetscFunctionReturn(0);
179}
180/**
181 * @brief An off-axis seam: a rotated x-periodic grid validates the rotated translation and wraps by it.
182 *
183 * Rotates the grid 30 degrees about z, so the x seam translation gains a y component, then checks
184 * that the validated translation is the rotated one and that a particle beyond -Xi re-enters at the
185 * +Xi end shifted by it.
186 */
188{
189 SimCtx *simCtx = NULL;
190 UserCtx *user = NULL;
191 Particle particle;
193 Vec gcoor = NULL;
194 Cmpnts ***coor = NULL;
195 const Cmpnts ***lcoor = NULL;
196 const PetscReal c = PetscCosReal(PETSC_PI / 6.0), s = PetscSinReal(PETSC_PI / 6.0);
197 PetscReal T0, x0, yc, zc;
198 Cmpnts p0;
199
200 PetscFunctionBeginUser;
201 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
202 MarkXPeriodic(user);
203 PetscCall(ValidatePeriodicGeometry(user));
204 T0 = user->periodic_translation[0].x;
205
206 /* Seam origin and the centre of the (., 1, 1) row, before rotation. */
207 PetscCall(DMGetCoordinatesLocal(user->da, &gcoor));
208 PetscCall(DMDAVecGetArrayRead(user->fda, gcoor, &lcoor));
209 x0 = lcoor[0][0][0].x;
210 yc = 0.5 * (lcoor[1][1][0].y + lcoor[1][2][0].y);
211 zc = 0.5 * (lcoor[1][1][0].z + lcoor[2][1][0].z);
212 PetscCall(DMDAVecRestoreArrayRead(user->fda, gcoor, &lcoor));
213
214 /* Rotate every node about the z axis through the origin. */
215 PetscCall(DMGetCoordinates(user->da, &gcoor));
216 PetscCall(DMDAVecGetArray(user->fda, gcoor, &coor));
217 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++)
218 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++)
219 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; i++) {
220 const Cmpnts q = coor[k][j][i];
221 coor[k][j][i].x = c * q.x - s * q.y;
222 coor[k][j][i].y = s * q.x + c * q.y;
223 }
224 PetscCall(DMDAVecRestoreArray(user->fda, gcoor, &coor));
225 PetscCall(UpdateLocalGhosts(user, FIELD_ID_COORDINATES)); /* As the grid builders refresh them */
226 PetscCall(MetricDestroyFacePlanes(user)); /* The grid moved: its search planes are rebuilt */
227 PetscCall(MetricComputeFacePlanes(user));
228 PetscCall(ValidatePeriodicGeometry(user));
229 PetscCall(PicurvAssertRealNear(c * T0, user->periodic_translation[0].x, 1.0e-12, "translation x is rotated"));
230 PetscCall(PicurvAssertRealNear(s * T0, user->periodic_translation[0].y, 1.0e-12, "translation gains a y component"));
231
234 PetscCall(SetupDomainCellDecompositionMap(user));
236
237 /* Beyond -Xi out of cell 0: re-enters at the +Xi end, shifted along the rotated translation. */
238 PetscCall(PetscMemzero(&particle, sizeof(particle)));
239 particle.PID = 54;
240 particle.cell[0] = 0; particle.cell[1] = 1; particle.cell[2] = 1;
241 p0.x = x0 - 0.01 * T0; p0.y = yc; p0.z = zc;
242 particle.loc.x = c * p0.x - s * p0.y; particle.loc.y = s * p0.x + c * p0.y; particle.loc.z = p0.z;
243 PetscCall(LocateParticleOrFindMigrationTarget(user, &particle, &status));
244 PetscCall(PicurvAssertIntEqual(ACTIVE_AND_LOCATED, status, "a particle wrapped through an off-axis seam should be located"));
245 PetscCall(PicurvAssertRealNear(c * (p0.x + T0) - s * p0.y, particle.loc.x, 1.0e-12, "x shifts along the rotated translation"));
246 PetscCall(PicurvAssertRealNear(s * (p0.x + T0) + c * p0.y, particle.loc.y, 1.0e-12, "y shifts along the rotated translation"));
247 PetscCall(PicurvAssertIntEqual(user->IM - 2, particle.cell[0], "the particle lands in the last cell"));
248
249 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
250 PetscFunctionReturn(0);
251}
252/**
253 * @brief Tests mixed periodic directions are validated and stored independently.
254 */
256{
257 SimCtx *simCtx = NULL;
258 UserCtx *user = NULL;
259
260 PetscFunctionBeginUser;
261 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 6, 4, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE));
262 MarkXPeriodic(user);
263 MarkYPeriodic(user);
264
265 PetscCall(ValidatePeriodicGeometry(user));
266 PetscCall(PicurvAssertBool(user->periodic_translation_valid[0], "mixed-periodic X translation should be valid"));
267 PetscCall(PicurvAssertBool(user->periodic_translation_valid[1], "mixed-periodic Y translation should be valid"));
268 PetscCall(PicurvAssertBool((PetscBool)!user->periodic_translation_valid[2], "mixed-periodic Z translation should remain invalid"));
269 PetscCall(PicurvAssertBool((PetscBool)(PetscAbsReal(user->periodic_translation[0].x) > 0.0),
270 "mixed-periodic X translation should have nonzero x component"));
271 PetscCall(PicurvAssertBool((PetscBool)(PetscAbsReal(user->periodic_translation[1].y) > 0.0),
272 "mixed-periodic Y translation should have nonzero y component"));
273
274 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
275 PetscFunctionReturn(0);
276}
277/**
278 * @brief Tests non-translational seam geometry fails before metric construction.
279 */
281{
282 SimCtx *simCtx = NULL;
283 UserCtx *user = NULL;
284 Vec gcoor = NULL;
285 Cmpnts ***coor = NULL;
286 PetscErrorCode ierr_validate = 0;
287
288 PetscFunctionBeginUser;
289 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
290 MarkXPeriodic(user);
291
292 PetscCall(DMGetCoordinates(user->da, &gcoor));
293 PetscCall(DMDAVecGetArray(user->fda, gcoor, &coor));
294 coor[1][1][user->info.mx - 2].y += 0.25;
295 PetscCall(DMDAVecRestoreArray(user->fda, gcoor, &coor));
296 PetscCall(UpdateLocalGhosts(user, FIELD_ID_COORDINATES));
297
298 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
299 ierr_validate = ValidatePeriodicGeometry(user);
300 PetscCall(PetscPopErrorHandler());
301
302 PetscCall(PicurvAssertBool((PetscBool)(ierr_validate != 0), "varying seam translation should be rejected"));
303 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
304 PetscFunctionReturn(0);
305}
306
307/**
308 * @brief Tests face-center coordinates remain geometrically continuous across a periodic seam.
309 */
311{
312 SimCtx *simCtx = NULL;
313 UserCtx *user = NULL;
314 Cmpnts ***centx = NULL;
315 const Cmpnts ***lcentx = NULL;
316 const FieldId fields[] = {FIELD_ID_CENTX};
317 PetscReal translation, spacing;
318
319 PetscFunctionBeginUser;
320 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 6, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
321 MarkXPeriodic(user);
322 PetscCall(ValidatePeriodicGeometry(user));
323 translation = user->periodic_translation[0].x;
324 spacing = translation / (PetscReal)(user->info.mx - 2);
325
326 PetscCall(DMDAVecGetArray(user->fda, user->Centx, &centx));
327 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++) {
328 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++) {
329 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; i++) {
330 centx[k][j][i] = (Cmpnts){spacing * i, 2.0 + j, 3.0 + k};
331 }
332 }
333 }
334 PetscCall(DMDAVecRestoreArray(user->fda, user->Centx, &centx));
335
336 PetscCall(SynchronizePeriodicFaceFields(user, 'i', 1, fields));
337 PetscCall(DMDAVecGetArrayRead(user->fda, user->lCentx, &lcentx));
338 PetscCall(PicurvAssertRealNear(-spacing, lcentx[2][2][-1].x, 1.0e-12,
339 "translated Centx negative adjacent ghost"));
340 PetscCall(PicurvAssertRealNear(0.0, lcentx[2][2][0].x, 1.0e-12,
341 "translated Centx negative endpoint"));
342 PetscCall(PicurvAssertRealNear(translation + spacing, lcentx[2][2][user->info.mx - 1].x, 1.0e-12,
343 "translated Centx positive endpoint"));
344 PetscCall(PicurvAssertRealNear(translation + 2.0 * spacing, lcentx[2][2][user->info.mx].x, 1.0e-12,
345 "translated Centx positive adjacent ghost"));
346 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lCentx, &lcentx));
347
348 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
349 PetscFunctionReturn(0);
350}
351
352/**
353 * @brief Tests the dedicated QUICK outer-ghost repair for cell-centered inputs.
354 */
355static PetscErrorCode TestPeriodicQuickStencilPreparation(void)
356{
357 SimCtx *simCtx = NULL;
358 UserCtx *user = NULL;
359 Cmpnts ***ucat = NULL;
360 PetscReal ***nvert = NULL;
361
362 PetscFunctionBeginUser;
363 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 6, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
364 MarkXPeriodic(user);
365
366 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
367 PetscCall(DMDAVecGetArray(user->da, user->Nvert, &nvert));
368 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++) {
369 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++) {
370 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; i++) {
371 ucat[k][j][i] = (Cmpnts){100.0 + i, 200.0 + i, 300.0 + i};
372 nvert[k][j][i] = 400.0 + i;
373 }
374 }
375 }
376 PetscCall(DMDAVecRestoreArray(user->da, user->Nvert, &nvert));
377 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
378 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCAT));
379 PetscCall(UpdateLocalGhosts(user, FIELD_ID_NVERT));
380 PetscCall(PreparePeriodicQuickStencilFields(user, user->lUcat, user->lNvert));
381
382 PetscCall(DMDAVecGetArrayRead(user->fda, user->lUcat, &ucat));
383 PetscCall(DMDAVecGetArrayRead(user->da, user->lNvert, &nvert));
384 PetscCall(PicurvAssertRealNear(100.0 + user->info.mx - 3, ucat[2][2][-1].x, 1.0e-12,
385 "QUICK Ucat negative outer ghost"));
386 PetscCall(PicurvAssertRealNear(102.0, ucat[2][2][user->info.mx].x, 1.0e-12,
387 "QUICK Ucat positive outer ghost"));
388 PetscCall(PicurvAssertRealNear(400.0 + user->info.mx - 3, nvert[2][2][-1], 1.0e-12,
389 "QUICK Nvert negative outer ghost"));
390 PetscCall(PicurvAssertRealNear(402.0, nvert[2][2][user->info.mx], 1.0e-12,
391 "QUICK Nvert positive outer ghost"));
392 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lNvert, &nvert));
393 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lUcat, &ucat));
394
395 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
396 PetscFunctionReturn(0);
397}
398/**
399 * @brief Tests periodic geometric factory construction.
400 */
401static PetscErrorCode TestPeriodicGeometricFactoryAssignment(void)
402{
403 BoundaryCondition *bc = NULL;
404
405 PetscFunctionBeginUser;
407 PetscCall(PicurvAssertBool((PetscBool)(bc != NULL), "periodic geometric factory should allocate a handler"));
408 PetscCall(PicurvAssertIntEqual(BC_PRIORITY_WALL, bc->priority, "periodic geometric handler priority"));
409 PetscCall(PicurvAssertBool((PetscBool)(bc->Apply == NULL), "periodic geometric handler should not expose Apply"));
410 PetscCall(PicurvAssertBool((PetscBool)(bc->Initialize == NULL), "periodic geometric handler should not expose Initialize"));
411 PetscCall(DestroyBoundaryHandler(&bc));
412 PetscFunctionReturn(0);
413}
414/**
415 * @brief Tests periodic metric transfer through the aggregate periodic-metrics helper.
416 */
418{
419 SimCtx *simCtx = NULL;
420 UserCtx *user = NULL;
421 PetscReal ***aj = NULL;
422 PetscReal expected_neg_face = 0.0;
423 PetscReal expected_pos_face = 0.0;
424 PetscReal expected_neg_ghost = 0.0;
425 PetscReal expected_pos_ghost = 0.0;
426
427 PetscFunctionBeginUser;
428 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
429 MarkXPeriodic(user);
430 PetscCall(ValidatePeriodicGeometry(user));
431
432 PetscCall(DMDAVecGetArray(user->da, user->Aj, &aj));
433 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
434 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
435 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
436 aj[k][j][i] = 100.0 + (PetscReal)i;
437 }
438 }
439 }
440 PetscCall(DMDAVecRestoreArray(user->da, user->Aj, &aj));
441 PetscCall(DMGlobalToLocalBegin(user->da, user->Aj, INSERT_VALUES, user->lAj));
442 PetscCall(DMGlobalToLocalEnd(user->da, user->Aj, INSERT_VALUES, user->lAj));
443 PetscCall(DMDAVecGetArrayRead(user->da, user->lAj, &aj));
444 expected_neg_face = aj[2][2][user->info.mx - 2];
445 expected_pos_face = aj[2][2][1];
446 expected_neg_ghost = expected_pos_face;
447 expected_pos_ghost = expected_neg_face;
448 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lAj, &aj));
449
450 PetscCall(ApplyMetricsPeriodicBCs(user));
451
452 PetscCall(DMDAVecGetArrayRead(user->da, user->lAj, &aj));
453 PetscCall(PicurvAssertRealNear(expected_neg_face, aj[2][2][0], 1.0e-12, "NEG_X periodic metric face should copy from the opposite interior face"));
454 PetscCall(PicurvAssertRealNear(expected_pos_face, aj[2][2][user->info.mx - 1], 1.0e-12, "POS_X periodic metric face should copy from the leading interior face"));
455 PetscCall(PicurvAssertRealNear(expected_neg_ghost, aj[2][2][-1], 1.0e-12, "cell-centered Aj negative ghost should retain PETSc wraparound"));
456 PetscCall(PicurvAssertRealNear(expected_pos_ghost, aj[2][2][user->info.mx], 1.0e-12, "cell-centered Aj positive ghost should retain PETSc wraparound"));
457 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lAj, &aj));
458
459 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
460 PetscFunctionReturn(0);
461}
462/**
463 * @brief Tests ordered cell-field synchronization across two periodic directions.
464 */
466{
467 SimCtx *simCtx = NULL;
468 UserCtx *user = NULL;
469 PetscReal ***p = NULL;
470 PetscReal ***cs = NULL;
471 PetscReal ***diffusivity = NULL;
472 Cmpnts ***ucat = NULL;
473 PetscInt mx, my;
475
476 PetscFunctionBeginUser;
477 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE));
478 MarkXPeriodic(user);
479 MarkYPeriodic(user);
480
481 PetscCall(DMCreateGlobalVector(user->da, &user->Nu_t));
482 PetscCall(DMCreateLocalVector(user->da, &user->lNu_t));
483 PetscCall(VecSet(user->Nu_t, 5.0));
484 PetscCall(VecSet(user->lNu_t, 0.0));
485 PetscCall(DMCreateGlobalVector(user->da, &user->CS));
486 PetscCall(DMCreateLocalVector(user->da, &user->lCs));
487 PetscCall(VecSet(user->Phi, 3.0));
488 PetscCall(VecSet(user->Nvert, 4.0));
489
490 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
491 PetscCall(DMDAVecGetArray(user->da, user->CS, &cs));
492 PetscCall(DMDAVecGetArray(user->da, user->Diffusivity, &diffusivity));
493 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
494 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
495 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
496 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
497 PetscReal value = (PetscReal)(i + 10 * j + 100 * k);
498 p[k][j][i] = value;
499 cs[k][j][i] = value + 4000.0;
500 diffusivity[k][j][i] = value + 5000.0;
501 ucat[k][j][i].x = value + 1000.0;
502 ucat[k][j][i].y = value + 2000.0;
503 ucat[k][j][i].z = value + 3000.0;
504 }
505 }
506 }
507 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
508 PetscCall(DMDAVecRestoreArray(user->da, user->CS, &cs));
509 PetscCall(DMDAVecRestoreArray(user->da, user->Diffusivity, &diffusivity));
510 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
511
512 PetscCall(SynchronizePeriodicCellFields(user, 7, fields));
513
514 mx = user->info.mx;
515 my = user->info.my;
516 PetscCall(DMDAVecGetArrayRead(user->da, user->P, &p));
517 PetscCall(DMDAVecGetArrayRead(user->da, user->CS, &cs));
518 PetscCall(DMDAVecGetArrayRead(user->da, user->Diffusivity, &diffusivity));
519 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucat, &ucat));
520 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 20 + 200), p[2][2][0], 1.0e-12,
521 "x-periodic negative endpoint should copy the opposite interior value"));
522 PetscCall(PicurvAssertRealNear((PetscReal)(1 + 20 + 200), p[2][2][mx - 1], 1.0e-12,
523 "x-periodic positive endpoint should copy the leading interior value"));
524 PetscCall(PicurvAssertRealNear((PetscReal)(2 + 10 * (my - 2) + 200), p[2][0][2], 1.0e-12,
525 "y-periodic negative endpoint should copy the opposite interior value"));
526 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 10 * (my - 2) + 200), p[2][0][0], 1.0e-12,
527 "ordered synchronization should propagate the opposite periodic corner"));
528 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 10 * (my - 2) + 1200), ucat[2][0][0].x, 1.0e-12,
529 "vector fields should use the same ordered periodic-corner protocol"));
530 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 10 * (my - 2) + 4200), cs[2][0][0], 1.0e-12,
531 "CS should use the ordered periodic-corner protocol"));
532 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 10 * (my - 2) + 5200), diffusivity[2][0][0], 1.0e-12,
533 "Diffusivity should use the ordered periodic-corner protocol"));
534 PetscCall(DMDAVecRestoreArrayRead(user->da, user->P, &p));
535 PetscCall(DMDAVecRestoreArrayRead(user->da, user->CS, &cs));
536 PetscCall(DMDAVecRestoreArrayRead(user->da, user->Diffusivity, &diffusivity));
537 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucat, &ucat));
538 PetscCall(PicurvAssertVecConstant(user->Nu_t, 5.0, 1.0e-12, "Nu_t should be accepted by periodic cell synchronization"));
539
540 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
541 PetscFunctionReturn(0);
542}
543
544/**
545 * @brief Tests ordered persistent synchronization for an I-face scalar metric.
546 */
548{
549 SimCtx *simCtx = NULL;
550 UserCtx *user = NULL;
551 PetscReal ***iaj = NULL;
552 Cmpnts ***csi = NULL;
553 const FieldId fields[] = {FIELD_ID_CSI, FIELD_ID_IAJ};
554 PetscInt mx, my;
555
556 PetscFunctionBeginUser;
557 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE));
558 MarkXPeriodic(user);
559 MarkYPeriodic(user);
560 mx = user->info.mx;
561 my = user->info.my;
562
563 PetscCall(DMDAVecGetArray(user->da, user->IAj, &iaj));
564 PetscCall(DMDAVecGetArray(user->fda, user->Csi, &csi));
565 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++) {
566 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++) {
567 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; i++) {
568 PetscReal value = (PetscReal)(i + 10 * j + 100 * k);
569 iaj[k][j][i] = value;
570 csi[k][j][i] = (Cmpnts){value + 1000.0, value + 2000.0, value + 3000.0};
571 }
572 }
573 }
574 PetscCall(DMDAVecRestoreArray(user->da, user->IAj, &iaj));
575 PetscCall(DMDAVecRestoreArray(user->fda, user->Csi, &csi));
576
577 PetscCall(SynchronizePeriodicFaceFields(user, 'i', 2, fields));
578
579 PetscCall(DMDAVecGetArrayRead(user->da, user->IAj, &iaj));
580 PetscCall(DMDAVecGetArrayRead(user->fda, user->Csi, &csi));
581 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 2 + 20 + 200), iaj[2][2][0], 1.0e-12,
582 "I-face negative seam should copy the opposite physical seam face"));
583 PetscCall(PicurvAssertRealNear((PetscReal)(1 + 20 + 200), iaj[2][2][mx - 1], 1.0e-12,
584 "I-face positive dummy should copy the leading physical face"));
585 PetscCall(PicurvAssertRealNear((PetscReal)(2 + 10 * (my - 2) + 200), iaj[2][0][2], 1.0e-12,
586 "I-face field should use cell-style synchronization tangentially"));
587 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 2 + 10 * (my - 2) + 200), iaj[2][0][0], 1.0e-12,
588 "ordered face synchronization should propagate mixed-axis corners"));
589 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 2 + 10 * (my - 2) + 1200), csi[2][0][0].x, 1.0e-12,
590 "vector I-face fields should use the same ordered synchronization"));
591 PetscCall(DMDAVecRestoreArrayRead(user->da, user->IAj, &iaj));
592 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Csi, &csi));
593
594 PetscCall(DMDAVecGetArrayRead(user->da, user->lIAj, &iaj));
595 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 3 + 20 + 200), iaj[2][2][-1], 1.0e-12,
596 "I-face negative adjacent ghost should be shifted to the prior face"));
597 PetscCall(PicurvAssertRealNear((PetscReal)(2 + 20 + 200), iaj[2][2][mx], 1.0e-12,
598 "I-face positive adjacent ghost should be shifted to the next face"));
599 PetscCall(PicurvAssertRealNear((PetscReal)(2 + 10 + 200), iaj[2][-1][2], 1.0e-12,
600 "I-face tangential ghosts should retain cell-style wraparound"));
601 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lIAj, &iaj));
602
603 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
604 PetscFunctionReturn(0);
605}
606
607/**
608 * @brief Tests ordered persistent synchronization for component-staggered Ucont.
609 */
611{
612 SimCtx *simCtx = NULL;
613 UserCtx *user = NULL;
614 Cmpnts ***ucont = NULL;
615 const FieldId fields[] = {FIELD_ID_UCONT};
616 PetscInt mx, my;
617
618 PetscFunctionBeginUser;
619 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE));
620 MarkXPeriodic(user);
621 MarkYPeriodic(user);
622 mx = user->info.mx;
623 my = user->info.my;
624
625 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &ucont));
626 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++) {
627 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++) {
628 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; i++) {
629 PetscReal value = (PetscReal)(i + 10 * j + 100 * k);
630 ucont[k][j][i] = (Cmpnts){value + 1000.0, value + 2000.0, value + 3000.0};
631 }
632 }
633 }
634 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &ucont));
635
636 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fields));
637
638 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucont, &ucont));
639 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 2 + 20 + 1200), ucont[2][2][0].x, 1.0e-12,
640 "Ucont.x negative X seam should copy the opposite physical seam"));
641 PetscCall(PicurvAssertRealNear((PetscReal)(1 + 20 + 2200), ucont[2][2][mx - 1].y, 1.0e-12,
642 "Ucont.y positive X dummy should copy the leading physical value"));
643 PetscCall(PicurvAssertRealNear((PetscReal)(2 + 10 * (my - 2) + 3200), ucont[2][0][2].z, 1.0e-12,
644 "Ucont.z should synchronize tangentially in Y"));
645 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 2 + 10 * (my - 2) + 2200), ucont[2][0][0].y, 1.0e-12,
646 "ordered staggered synchronization should propagate mixed-axis corners"));
647 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucont, &ucont));
648
649 PetscCall(DMDAVecGetArrayRead(user->fda, user->lUcont, &ucont));
650 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 3 + 20 + 1200), ucont[2][2][-1].x, 1.0e-12,
651 "Ucont.x should use face-normal X ghost repair"));
652 PetscCall(PicurvAssertRealNear((PetscReal)(1 + 20 + 2200), ucont[2][2][-1].y, 1.0e-12,
653 "Ucont.y should retain cell-style wraparound tangentially in X"));
654 PetscCall(PicurvAssertRealNear((PetscReal)(2 + 20 + 1200), ucont[2][2][mx].x, 1.0e-12,
655 "Ucont.x positive adjacent ghost should use the next face"));
656 PetscCall(PicurvAssertRealNear((PetscReal)(mx - 2 + 20 + 2200), ucont[2][2][mx].y, 1.0e-12,
657 "Ucont.y positive X ghost should retain cell-style wraparound"));
658 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lUcont, &ucont));
659
660 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
661 PetscFunctionReturn(0);
662}
663
664/**
665 * @brief Tests mixed-boundary post-projection cell finalization and Ucont preservation.
666 */
668{
669 SimCtx *simCtx = NULL;
670 UserCtx *user = NULL;
671 Vec ucont_before = NULL;
672 Vec ucont_difference = NULL;
673 Cmpnts ***ucat = NULL;
674 Cmpnts ***ucont = NULL;
675 PetscReal ***p = NULL;
676 PetscReal difference_norm = 0.0;
677 PetscInt mx;
678
679 PetscFunctionBeginUser;
680 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE));
681 MarkXPeriodic(user);
682 PetscCall(VecSet(user->Bcs.Ubcs, 0.0));
683
684 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
685 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &ucont));
686 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
687 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
688 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
689 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
690 PetscReal value = (PetscReal)(i + 10 * j + 100 * k);
691 ucat[k][j][i].x = value + 1000.0;
692 ucat[k][j][i].y = value + 2000.0;
693 ucat[k][j][i].z = value + 3000.0;
694 ucont[k][j][i].x = value + 4000.0;
695 ucont[k][j][i].y = value + 5000.0;
696 ucont[k][j][i].z = value + 6000.0;
697 p[k][j][i] = value;
698 }
699 }
700 }
701 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
702 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &ucont));
703 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
704
705 PetscCall(VecDuplicate(user->Ucont, &ucont_before));
706 PetscCall(VecDuplicate(user->Ucont, &ucont_difference));
707 PetscCall(VecCopy(user->Ucont, ucont_before));
708
709 PetscCall(FinalizePostProjectionCellFields(user));
710
711 PetscCall(VecWAXPY(ucont_difference, -1.0, user->Ucont, ucont_before));
712 PetscCall(VecNorm(ucont_difference, NORM_INFINITY, &difference_norm));
713 PetscCall(PicurvAssertRealNear(0.0, difference_norm, 1.0e-12,
714 "post-projection cell finalization must preserve mixed-boundary Ucont"));
715
716 mx = user->info.mx;
717 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucat, &ucat));
718 PetscCall(DMDAVecGetArrayRead(user->da, user->P, &p));
719 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 20 + 200 + 1000), ucat[2][2][0].x, 1.0e-12,
720 "mixed finalization should restore the negative x-periodic Ucat endpoint"));
721 PetscCall(PicurvAssertRealNear((PetscReal)(-(2 + 10 + 200 + 1000)), ucat[2][0][2].x, 1.0e-12,
722 "mixed finalization should extrapolate the non-periodic y dummy face"));
723 PetscCall(PicurvAssertRealNear((PetscReal)(-((mx - 2) + 10 + 200 + 1000)), ucat[2][0][0].x, 1.0e-12,
724 "periodic synchronization should win at a mixed x-periodic/y-physical edge"));
725 PetscCall(PicurvAssertRealNear((PetscReal)((mx - 2) + 20 + 200), p[2][2][0], 1.0e-12,
726 "mixed finalization should restore the negative x-periodic pressure endpoint"));
727 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucat, &ucat));
728 PetscCall(DMDAVecRestoreArrayRead(user->da, user->P, &p));
729
730 PetscCall(VecDestroy(&ucont_difference));
731 PetscCall(VecDestroy(&ucont_before));
732 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
733 PetscFunctionReturn(0);
734}
735
736/** @brief Verifies reconstructed Ucat periodic duplicates and local values are finalized. */
738{
739 SimCtx *simCtx=NULL; UserCtx *user=NULL; Cmpnts ***ucont=NULL,***ucat=NULL,***lucat=NULL;
740 const FieldId staggered_fields[] = {FIELD_ID_UCONT}, cell_fields[] = {FIELD_ID_UCAT};
741 PetscInt mx;
742 PetscFunctionBeginUser;
743 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx,&user,4,4,4,PETSC_TRUE,PETSC_FALSE,PETSC_FALSE));
744 MarkXPeriodic(user); mx=user->info.mx;
745 PetscCall(VecSet(user->Ucont,0.0));
746 PetscCall(DMDAVecGetArray(user->fda,user->Ucont,&ucont));
747 for(PetscInt k=1;k<user->info.mz-1;k++) for(PetscInt j=1;j<user->info.my-1;j++)
748 for(PetscInt i=1;i<mx-1;i++) ucont[k][j][i].x=(PetscReal)i;
749 PetscCall(DMDAVecRestoreArray(user->fda,user->Ucont,&ucont));
750 PetscCall(SynchronizePeriodicStaggeredFields(user,1,staggered_fields));
751 PetscCall(VecSet(user->Ucat,-99.0));
752 PetscCall(Contra2Cart(user));
753 PetscCall(SynchronizePeriodicCellFields(user,1,cell_fields));
754 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCAT));
755
756 PetscCall(DMDAVecGetArrayRead(user->fda,user->Ucat,&ucat));
757 PetscCall(PicurvAssertRealNear(ucat[2][2][mx-2].x,ucat[2][2][0].x,1e-12,"negative Ucat duplicate follows opposite independent cell"));
758 PetscCall(PicurvAssertRealNear(ucat[2][2][1].x,ucat[2][2][mx-1].x,1e-12,"positive Ucat duplicate follows leading independent cell"));
759 PetscCall(DMDAVecGetArrayRead(user->fda,user->lUcat,&lucat));
760 PetscCall(PicurvAssertRealNear(ucat[2][2][0].x,lucat[2][2][0].x,1e-12,"local negative Ucat endpoint matches corrected global"));
761 PetscCall(PicurvAssertRealNear(ucat[2][2][mx-1].x,lucat[2][2][mx-1].x,1e-12,"local positive Ucat endpoint matches corrected global"));
762 PetscCall(DMDAVecRestoreArrayRead(user->fda,user->lUcat,&lucat));
763 PetscCall(DMDAVecRestoreArrayRead(user->fda,user->Ucat,&ucat));
764 PetscCall(PicurvDestroyMinimalContexts(&simCtx,&user));
765 PetscFunctionReturn(0);
766}
767/**
768 * @brief Runs the focused geometric-periodic PETSc test binary.
769 */
770int main(int argc, char **argv)
771{
772 PetscErrorCode ierr;
773 const PicurvTestCase cases[] = {
774 {"periodic-geometric-factory-assignment", TestPeriodicGeometricFactoryAssignment},
775 {"periodic-configuration-requires-paired-faces", TestPeriodicConfigurationRequiresPairedFaces},
776 {"periodic-geometry-stores-translation", TestPeriodicGeometryStoresTranslation},
777 {"periodic-geometry-stores-mixed-translations", TestPeriodicGeometryStoresMixedTranslations},
778 {"locate-particle-wraps-through-periodic-face", TestLocateParticleWrapsThroughPeriodicFace},
779 {"locate-particle-wraps-through-off-axis-seam", TestLocateParticleWrapsThroughOffAxisSeam},
780 {"periodic-geometry-rejects-varying-translation", TestPeriodicGeometryRejectsVaryingTranslation},
781 {"periodic-face-center-coordinate-synchronization", TestPeriodicFaceCenterCoordinateSynchronization},
782 {"periodic-quick-stencil-preparation", TestPeriodicQuickStencilPreparation},
783 {"apply-metrics-periodic-bcs-synchronizes-aj", TestApplyMetricsPeriodicBCsSynchronizesAj},
784 {"synchronize-periodic-cell-fields-copies-mixed-axes", TestSynchronizePeriodicCellFieldsCopiesMixedAxes},
785 {"synchronize-periodic-face-fields-copies-mixed-axes", TestSynchronizePeriodicFaceFieldsCopiesMixedAxes},
786 {"synchronize-periodic-staggered-fields-copies-mixed-axes", TestSynchronizePeriodicStaggeredFieldsCopiesMixedAxes},
787 {"finalize-post-projection-cell-fields-mixed-boundaries", TestFinalizePostProjectionCellFieldsMixedBoundaries},
788 {"contra2cart-periodic-ucat-finalization", TestContra2CartPeriodicUcatFinalization},
789 };
790
791 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv geometric-periodic tests");
792 if (ierr) {
793 return (int)ierr;
794 }
795
796 ierr = PicurvRunTests("unit-periodic", cases, sizeof(cases) / sizeof(cases[0]));
797 if (ierr) {
798 PetscFinalize();
799 return (int)ierr;
800 }
801
802 ierr = PetscFinalize();
803 return (int)ierr;
804}
PetscErrorCode PreparePeriodicQuickStencilFields(UserCtx *user, Vec local_vector_field, Vec local_scalar_field)
Repairs the outer adjacent periodic ghosts used by QUICK cell stencils.
PetscErrorCode ApplyMetricsPeriodicBCs(UserCtx *user)
(Orchestrator) Updates all metric-related fields in the local ghost cell regions for periodic boundar...
PetscErrorCode BoundarySystem_Validate(UserCtx *user)
(Public) Validates the consistency and compatibility of the parsed boundary condition system.
Definition Boundaries.c:817
PetscErrorCode BoundaryCondition_Create(BCHandlerType handler_type, BoundaryCondition **new_bc_ptr)
(Private) Creates and configures a specific BoundaryCondition handler object.
Definition Boundaries.c:726
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode FinalizePostProjectionCellFields(UserCtx *user)
Finalizes cell-centered fields after the projection step.
PetscErrorCode SynchronizePeriodicFaceFields(UserCtx *user, char face_direction, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent fields belonging to one face family.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
PetscErrorCode MetricDestroyFacePlanes(UserCtx *user)
Frees the face-plane fields MetricComputeFacePlanes() built, if any.
Definition Metric.c:301
PetscErrorCode MetricComputeFacePlanes(UserCtx *user)
Builds the block's particle face planes once, as catalogued per-face fields.
Definition Metric.c:136
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_CSI
@ FIELD_ID_IAJ
@ FIELD_ID_NVERT
@ FIELD_ID_UCAT
@ FIELD_ID_COORDINATES
@ FIELD_ID_NU_T
@ FIELD_ID_UCONT
@ FIELD_ID_PHI
@ FIELD_ID_CS
@ FIELD_ID_P
@ FIELD_ID_CENTX
@ FIELD_ID_DIFFUSIVITY
PetscErrorCode ValidatePeriodicGeometry(UserCtx *user)
Validates that configured geometric periodic seams match by translation.
Definition grid.c:470
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
Definition setup.c:3462
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:2678
PetscErrorCode SetupDomainCellDecompositionMap(UserCtx *user)
Creates and distributes a map of the domain's cell decomposition to all ranks.
Definition setup.c:3657
The "virtual table" struct for a boundary condition handler object.
Definition variables.h:414
PetscErrorCode(* Destroy)(BoundaryCondition *self)
Definition variables.h:423
PetscErrorCode(* Initialize)(BoundaryCondition *self, BCContext *ctx)
Definition variables.h:418
PetscErrorCode(* Apply)(BoundaryCondition *self, BCContext *ctx)
Definition variables.h:420
BCPriorityType priority
Definition variables.h:416
static PetscErrorCode TestContra2CartPeriodicUcatFinalization(void)
Verifies reconstructed Ucat periodic duplicates and local values are finalized.
static void MarkXPeriodic(UserCtx *user)
Marks the x faces as periodic for periodic-transfer harnesses.
static PetscErrorCode TestPeriodicGeometricFactoryAssignment(void)
Tests periodic geometric factory construction.
static PetscErrorCode TestPeriodicFaceCenterCoordinateSynchronization(void)
Tests face-center coordinates remain geometrically continuous across a periodic seam.
int main(int argc, char **argv)
Runs the focused geometric-periodic PETSc test binary.
static PetscErrorCode TestLocateParticleWrapsThroughPeriodicFace(void)
Tests that a particle beyond either x-periodic face re-enters through the paired face,...
static PetscErrorCode TestPeriodicGeometryStoresTranslation(void)
Tests constant translational periodic geometry is accepted and stored.
static PetscErrorCode TestSynchronizePeriodicFaceFieldsCopiesMixedAxes(void)
Tests ordered persistent synchronization for an I-face scalar metric.
static PetscErrorCode TestFinalizePostProjectionCellFieldsMixedBoundaries(void)
Tests mixed-boundary post-projection cell finalization and Ucont preservation.
static PetscErrorCode TestPeriodicConfigurationRequiresPairedFaces(void)
Tests periodic configuration rejects an unpaired geometric periodic face.
static PetscErrorCode TestPeriodicQuickStencilPreparation(void)
Tests the dedicated QUICK outer-ghost repair for cell-centered inputs.
static PetscErrorCode TestSynchronizePeriodicCellFieldsCopiesMixedAxes(void)
Tests ordered cell-field synchronization across two periodic directions.
static PetscErrorCode TestPeriodicGeometryRejectsVaryingTranslation(void)
Tests non-translational seam geometry fails before metric construction.
static PetscErrorCode TestSynchronizePeriodicStaggeredFieldsCopiesMixedAxes(void)
Tests ordered persistent synchronization for component-staggered Ucont.
static PetscErrorCode DestroyBoundaryHandler(BoundaryCondition **bc_ptr)
Destroys one boundary-condition handler allocated by a periodic test.
static PetscErrorCode TestPeriodicGeometryStoresMixedTranslations(void)
Tests mixed periodic directions are validated and stored independently.
static PetscErrorCode TestApplyMetricsPeriodicBCsSynchronizesAj(void)
Tests periodic metric transfer through the aggregate periodic-metrics helper.
static void MarkYPeriodic(UserCtx *user)
Marks the y faces as periodic for periodic-transfer harnesses.
static PetscErrorCode TestLocateParticleWrapsThroughOffAxisSeam(void)
An off-axis seam: a rotated x-periodic grid validates the rotated translation and wraps by it.
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.
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 PicurvAssertVecConstant(Vec vec, PetscScalar expected, PetscReal tol, const char *context)
Asserts that a PETSc vector is spatially constant within tolerance.
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.
@ PERIODIC
Definition variables.h:348
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:1166
PetscInt cell[3]
Definition variables.h:235
Vec lNvert
Definition variables.h:1180
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Definition variables.h:174
@ NEEDS_LOCATION
Definition variables.h:175
@ ACTIVE_AND_LOCATED
Definition variables.h:176
PetscInt64 wrapCount
Definition variables.h:307
@ PARTICLE_BOUNDARY_WRAP
Periodic faces: the particle re-enters through the paired face.
Definition variables.h:362
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:377
BCHandlerType handler_type
Definition variables.h:430
PetscInt currentSettlementPass
Definition variables.h:308
Vec Ucont
Definition variables.h:1180
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
Definition variables.h:160
PetscScalar x
Definition variables.h:133
Cmpnts loc
Definition variables.h:236
Vec Centx
Definition variables.h:1235
Vec lNu_t
Definition variables.h:1242
ParticleBoundaryPolicy particle_policy
What a particle crossing this face becomes (BC param particle_policy).
Definition variables.h:431
PetscScalar z
Definition variables.h:133
PetscInt JM
Definition variables.h:1155
Vec lCentx
Definition variables.h:1236
SearchMetricsState searchMetrics
Definition variables.h:1069
Vec lUcont
Definition variables.h:1180
Vec Diffusivity
Definition variables.h:1183
DMDALocalInfo info
Definition variables.h:1153
@ BC_PRIORITY_WALL
Definition variables.h:388
Vec lUcat
Definition variables.h:1180
PetscScalar y
Definition variables.h:133
PetscInt IM
Definition variables.h:1155
Cmpnts periodic_translation[3]
Definition variables.h:1162
Vec Nvert
Definition variables.h:1180
PetscBool periodic_translation_valid[3]
Definition variables.h:1163
BCType mathematical_type
Definition variables.h:429
PetscInt64 PID
Definition variables.h:234
@ BC_FACE_NEG_X
Definition variables.h:318
@ BC_FACE_POS_Y
Definition variables.h:319
@ BC_FACE_POS_X
Definition variables.h:318
@ BC_FACE_NEG_Y
Definition variables.h:319
A 3D point or vector with PetscScalar components.
Definition variables.h:132
Defines a particle's core properties for Lagrangian tracking.
Definition variables.h:233
The master context for the entire simulation.
Definition variables.h:918
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1141
Header file for particle location functions using the walking search algorithm.
PetscErrorCode LocateParticleOrFindMigrationTarget(UserCtx *user, Particle *particle, ParticleLocationStatus *status_out)
Locates a particle's host cell or identifies its migration target using a robust walk search.