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

C unit tests for setup, initialization, and cleanup lifecycle entry points. More...

#include "test_support.h"
#include "ParticleSwarm.h"
#include "ParticlePhysics.h"
#include "initialcondition.h"
#include "runloop.h"
#include "setup.h"
#include <stdio.h>
#include <string.h>
Include dependency graph for test_setup_lifecycle.c:

Go to the source code of this file.

Functions

static PetscErrorCode AssertDirectoryExists (const char *path, const char *context)
 Asserts that a directory path exists and is readable.
 
static PetscErrorCode WriteContextOnlyFile (const char *path, const char *contents)
 Writes one small temporary text file used by the partial-lifecycle context-only fixture.
 
static PetscErrorCode PrepareContextOnlyConfig (char *tmpdir, size_t tmpdir_len, char *control_path, size_t control_path_len)
 Creates the control-file bundle needed for the context-only cleanup test.
 
static PetscErrorCode FreeLifecycleContext (SimCtx **simCtx_ptr)
 Finalizes and frees one lifecycle test context, then clears any PETSc options used to build it.
 
static PetscErrorCode BuildLifecycleContext (PetscBool enable_particles, SimCtx **simCtx_out, char *tmpdir, size_t tmpdir_len)
 Builds a full setup fixture through environment, grid, BC, and domain-rank initialization.
 
static PetscErrorCode BuildContextOnly (SimCtx **simCtx_out, char *tmpdir, size_t tmpdir_len)
 Builds only the top-level simulation context used by partial-initialization cleanup tests.
 
static PetscErrorCode TestSetupRejectsUnimplementedFeatureFlags (void)
 Tests that setup refuses every flag whose feature is planned but not implemented.
 
static PetscErrorCode TryContextWithExtraLines (const char *extra_lines, SimCtx **simCtx_out, PetscErrorCode *ierr_out, char *tmpdir, size_t tmpdir_len)
 Builds a context from the fixture control file with extra lines appended.
 
static PetscErrorCode TestIEMConstantIsConfigurable (void)
 Tests that the IEM mixing constant defaults to 2.0, follows -iem_constant, accepts zero (no micromixing), and refuses a negative or non-finite value.
 
static PetscErrorCode TestUnsolvedFlowUsesOneGridLevel (void)
 Ensures a run that solves no pressure builds one grid level whatever -mg_level asks, and a solved flow keeps the levels it asks for.
 
static PetscErrorCode TestParticleCountMustFitPetscInt (void)
 Ensures setup refuses a particle count whose widest swarm field PetscInt cannot index.
 
static PetscErrorCode TestSetupRejectsNonpositivePostInterval (void)
 Ensures setup propagates invalid post intervals before either executable can loop.
 
static PetscErrorCode TestConfiguredParticleInitialValue (void)
 Checks a configured particle initial value through the production setup path.
 
static PetscErrorCode TestConfiguredIEMUpdatesSwarm (void)
 Checks configured IEM relaxation through the production swarm update.
 
static PetscErrorCode TestIEMRelaxesTowardOwnCellMean (void)
 Checks that IEM relaxes each particle toward its own cell's scattered mean.
 
static PetscErrorCode TestPostprocessorLoadsSavedParticleAverages (void)
 Checks that post-processing loads the particle averages a checkpoint holds.
 
static PetscErrorCode TestSharedRuntimeFixtureContracts (void)
 Tests that the shared richer runtime fixture mirrors normalized production setup contracts.
 
static PetscErrorCode AssertStoredLocalInfoMatchesDMs (UserCtx *user)
 Asserts that one block's stored local info matches what its DMs report.
 
static PetscErrorCode TestSetupLifecycleCoreSolverSetup (void)
 Tests the core setup lifecycle through environment, grid, BC, rank-info, and Eulerian-state initialization.
 
static PetscErrorCode TestSetupLifecycleParticleInitialization (void)
 Tests particle-swarm initialization and deterministic settlement on a tiny fully initialized case.
 
static PetscErrorCode TestSetupLifecycleScatterMetricsAtStepZero (void)
 Tests that step-zero scalar verification emits scatter_metrics.csv during initialized setup.
 
static PetscErrorCode TestSetupLifecycleRandomGeneratorsAndCleanup (void)
 Tests standalone RNG initialization helpers and minimal-context cleanup.
 
static PetscErrorCode TestSetupLifecycleCleanupAcrossInitializationStates (void)
 Tests cleanup after partial and fuller setup states without requiring unsupported double-finalization behavior.
 
static PetscErrorCode TestFieldCatalogMetadataAndViews (void)
 Verifies catalog completeness, stable name resolution, and runtime view binding.
 
static PetscErrorCode TestParticleFieldCatalogMetadata (void)
 Verifies the separate DMSwarm field catalog and its Eulerian bridge metadata.
 
static PetscErrorCode TestFieldCatalogTypedGhostUpdates (void)
 Verifies typed ghost updates preserve scalar, vector, face, and staggered behavior.
 
int main (int argc, char **argv)
 Runs the unit-setup PETSc test binary.
 

Detailed Description

C unit tests for setup, initialization, and cleanup lifecycle entry points.

Definition in file test_setup_lifecycle.c.

Function Documentation

◆ AssertDirectoryExists()

static PetscErrorCode AssertDirectoryExists ( const char *  path,
const char *  context 
)
static

Asserts that a directory path exists and is readable.

Definition at line 20 of file test_setup_lifecycle.c.

21{
22 PetscBool exists = PETSC_FALSE;
23
24 PetscFunctionBeginUser;
25 PetscCall(PetscTestDirectory(path, 'r', &exists));
26 PetscCall(PicurvAssertBool(exists, context));
27 PetscFunctionReturn(0);
28}
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:

◆ WriteContextOnlyFile()

static PetscErrorCode WriteContextOnlyFile ( const char *  path,
const char *  contents 
)
static

Writes one small temporary text file used by the partial-lifecycle context-only fixture.

Definition at line 33 of file test_setup_lifecycle.c.

34{
35 FILE *file = NULL;
36
37 PetscFunctionBeginUser;
38 file = fopen(path, "w");
39 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open '%s' for writing.", path);
40 fputs(contents, file);
41 fclose(file);
42 PetscFunctionReturn(0);
43}
Here is the caller graph for this function:

◆ PrepareContextOnlyConfig()

static PetscErrorCode PrepareContextOnlyConfig ( char *  tmpdir,
size_t  tmpdir_len,
char *  control_path,
size_t  control_path_len 
)
static

Creates the control-file bundle needed for the context-only cleanup test.

Definition at line 48 of file test_setup_lifecycle.c.

52{
53 char bcs_path[PETSC_MAX_PATH_LEN];
54 char post_path[PETSC_MAX_PATH_LEN];
55 char output_dir[PETSC_MAX_PATH_LEN];
56 char log_dir[PETSC_MAX_PATH_LEN];
57 char control_buffer[8192];
58
59 PetscFunctionBeginUser;
60 PetscCall(PicurvMakeTempDir(tmpdir, tmpdir_len));
61 PetscCall(PetscSNPrintf(bcs_path, sizeof(bcs_path), "%s/bcs.run", tmpdir));
62 PetscCall(PetscSNPrintf(post_path, sizeof(post_path), "%s/post.run", tmpdir));
63 PetscCall(PetscSNPrintf(output_dir, sizeof(output_dir), "%s/results", tmpdir));
64 PetscCall(PetscSNPrintf(log_dir, sizeof(log_dir), "%s/logs", tmpdir));
65 PetscCall(PetscSNPrintf(control_path, control_path_len, "%s/test.control", tmpdir));
66
67 PetscCall(WriteContextOnlyFile(
68 bcs_path,
69 "-Xi WALL noslip\n"
70 "+Xi WALL noslip\n"
71 "-Eta WALL noslip\n"
72 "+Eta WALL noslip\n"
73 "-Zeta INLET constant_velocity vx=0.0 vy=0.0 vz=1.5\n"
74 "+Zeta OUTLET conservation\n"));
75 PetscCall(WriteContextOnlyFile(
76 post_path,
77 "startTime = 0\n"
78 "endTime = 1\n"
79 "timeStep = 1\n"
80 "output_particles = false\n"));
81 PetscCall(PetscSNPrintf(
82 control_buffer,
83 sizeof(control_buffer),
84 "-start_step 0\n"
85 "-totalsteps 2\n"
86 "-ren 100.0\n"
87 "-dt 0.001\n"
88 "-finit 1\n"
89 "-ucont_x 0.0\n"
90 "-ucont_y 0.0\n"
91 "-ucont_z 1.5\n"
92 "-bcs_files %s\n"
93 "-profiling_timestep_mode off\n"
94 "-profiling_final_summary true\n"
95 "-postprocessing_config_file %s\n"
96 "-grid\n"
97 "-im 6\n"
98 "-jm 6\n"
99 "-km 6\n"
100 "-xMins 0.0\n"
101 "-xMaxs 1.0\n"
102 "-yMins 0.0\n"
103 "-yMaxs 1.0\n"
104 "-zMins 0.0\n"
105 "-zMaxs 1.0\n"
106 "-rxs 1.0\n"
107 "-rys 1.0\n"
108 "-rzs 1.0\n"
109 "-cgrids 0\n"
110 "-nblk 1\n"
111 "-euler_field_source solve\n"
112 "-mom_solver_type DUALTIME_PICARD_RK4\n"
113 "-mom_dt_rk4_residual_norm_noise_allowance_factor 1.07\n"
114 "-mom_resid_atol 1.0e-8\n"
115 "-mom_resid_rtol 1.0e-3\n"
116 "-mom_nk_pic_monitor\n"
117 "-mg_level 1\n"
118 "-poisson 0\n"
119 "-tio 0\n"
120 "-particle_console_output_freq 0\n"
121 "-logfreq 1\n"
122 "-output_dir %s\n"
123 "-restart_dir %s\n"
124 /* This fixture owns its temporary tree and wants it wiped. That is an external
125 * absolute path, so it authorizes the delete explicitly - the runtime guard
126 * makes no exception for tests. */
127 "-allow_unsafe_log_dir true\n"
128 "-log_dir %s\n"
129 "-numParticles 0\n"
130 "-pinit 2\n",
131 bcs_path,
132 post_path,
133 output_dir,
134 output_dir,
135 log_dir));
136 PetscCall(WriteContextOnlyFile(control_path, control_buffer));
137 PetscFunctionReturn(0);
138}
static PetscErrorCode WriteContextOnlyFile(const char *path, const char *contents)
Writes one small temporary text file used by the partial-lifecycle context-only fixture.
PetscErrorCode PicurvMakeTempDir(char *path, size_t path_len)
Creates a unique temporary directory for one test case.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FreeLifecycleContext()

static PetscErrorCode FreeLifecycleContext ( SimCtx **  simCtx_ptr)
static

Finalizes and frees one lifecycle test context, then clears any PETSc options used to build it.

Definition at line 143 of file test_setup_lifecycle.c.

144{
145 PetscFunctionBeginUser;
146 PetscCall(PicurvDestroyRuntimeContext(simCtx_ptr));
147 PetscFunctionReturn(0);
148}
PetscErrorCode PicurvDestroyRuntimeContext(SimCtx **simCtx_ptr)
Finalizes and frees a runtime context built by PicurvBuildTinyRuntimeContext.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildLifecycleContext()

static PetscErrorCode BuildLifecycleContext ( PetscBool  enable_particles,
SimCtx **  simCtx_out,
char *  tmpdir,
size_t  tmpdir_len 
)
static

Builds a full setup fixture through environment, grid, BC, and domain-rank initialization.

Definition at line 153 of file test_setup_lifecycle.c.

154{
155 PetscFunctionBeginUser;
156 PetscCall(PicurvBuildTinyRuntimeContext(NULL, enable_particles, simCtx_out, NULL, tmpdir, tmpdir_len));
157 PetscFunctionReturn(0);
158}
PetscErrorCode PicurvBuildTinyRuntimeContext(const char *bcs_contents, PetscBool enable_particles, SimCtx **simCtx_out, UserCtx **user_out, char *tmpdir, size_t tmpdir_len)
Builds a tiny runtime context through the real setup path for behavior-level tests.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildContextOnly()

static PetscErrorCode BuildContextOnly ( SimCtx **  simCtx_out,
char *  tmpdir,
size_t  tmpdir_len 
)
static

Builds only the top-level simulation context used by partial-initialization cleanup tests.

Definition at line 163 of file test_setup_lifecycle.c.

164{
165 char control_path[PETSC_MAX_PATH_LEN];
166 SimCtx *simCtx = NULL;
167
168 PetscFunctionBeginUser;
169 PetscCall(PetscOptionsClear(NULL));
170 PetscCall(PrepareContextOnlyConfig(tmpdir, tmpdir_len, control_path, sizeof(control_path)));
171 PetscCall(PetscOptionsSetValue(NULL, "-control_file", control_path));
172 PetscCall(CreateSimulationContext(0, NULL, &simCtx));
173 simCtx->exec_mode = EXEC_MODE_SOLVER;
174 *simCtx_out = simCtx;
175 PetscFunctionReturn(0);
176}
PetscErrorCode CreateSimulationContext(int argc, char **argv, SimCtx **p_simCtx)
Allocates and populates the master SimulationContext object.
Definition setup.c:452
static PetscErrorCode PrepareContextOnlyConfig(char *tmpdir, size_t tmpdir_len, char *control_path, size_t control_path_len)
Creates the control-file bundle needed for the context-only cleanup test.
@ EXEC_MODE_SOLVER
Definition variables.h:879
ExecutionMode exec_mode
Definition variables.h:928
The master context for the entire simulation.
Definition variables.h:907
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupRejectsUnimplementedFeatureFlags()

static PetscErrorCode TestSetupRejectsUnimplementedFeatureFlags ( void  )
static

Tests that setup refuses every flag whose feature is planned but not implemented.

Multi-block coupling, immersed boundaries, moving bodies, moving frames and the immersed-body flux corrections were all accepted before, and each ran a different problem without saying so. The conductor refuses the YAML switches; this covers the same flags arriving through a PETSc passthrough. Each flag is appended to an otherwise valid control file, so a later duplicate overrides the fixture's own value.

Definition at line 187 of file test_setup_lifecycle.c.

188{
189 const char *refused[] = {"-nblk 2", "-imm 1", "-fsi 1", "-rfsi 1",
190 "-mframe 1", "-rframe 1", "-mhv 1", "-lv 1"};
191
192 PetscFunctionBeginUser;
193 for (size_t n = 0; n < sizeof(refused) / sizeof(refused[0]); ++n) {
194 char tmpdir[PETSC_MAX_PATH_LEN];
195 char control_path[PETSC_MAX_PATH_LEN];
196 char message[128];
197 SimCtx *simCtx = NULL;
198 PetscErrorCode setup_ierr;
199 FILE *file = NULL;
200
201 PetscCall(PetscOptionsClear(NULL));
202 PetscCall(PrepareContextOnlyConfig(tmpdir, sizeof(tmpdir), control_path, sizeof(control_path)));
203 file = fopen(control_path, "a");
204 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to reopen '%s'.", control_path);
205 fprintf(file, "%s\n", refused[n]);
206 fclose(file);
207 PetscCall(PetscOptionsSetValue(NULL, "-control_file", control_path));
208
209 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
210 setup_ierr = CreateSimulationContext(0, NULL, &simCtx);
211 PetscCall(PetscPopErrorHandler());
212 PetscCall(PetscSNPrintf(message, sizeof(message), "setup must refuse '%s'", refused[n]));
213 PetscCall(PicurvAssertIntEqual(PETSC_ERR_SUP, setup_ierr, message));
214
215 /* The refusal fires mid-parse, before any solver state exists; only the top-level
216 context has been allocated. */
217 PetscCall(PetscFree(simCtx));
218 PetscCall(PetscOptionsClear(NULL));
219 PetscCall(PicurvRemoveTempDir(tmpdir));
220 }
221 PetscFunctionReturn(0);
222}
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvRemoveTempDir(const char *path)
Recursively removes a temporary directory created by PicurvMakeTempDir.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TryContextWithExtraLines()

static PetscErrorCode TryContextWithExtraLines ( const char *  extra_lines,
SimCtx **  simCtx_out,
PetscErrorCode *  ierr_out,
char *  tmpdir,
size_t  tmpdir_len 
)
static

Builds a context from the fixture control file with extra lines appended.

Parameters
[in]extra_linesControl-file lines appended after the fixture's own.
[out]simCtx_outContext on success; the partially built context on failure.
[out]ierr_outCreateSimulationContext's return code, errors suppressed.
[out]tmpdirFixture directory, removed by the caller.
[in]tmpdir_lenCapacity of tmpdir.

Definition at line 232 of file test_setup_lifecycle.c.

235{
236 char control_path[PETSC_MAX_PATH_LEN];
237 FILE *file = NULL;
238
239 PetscFunctionBeginUser;
240 PetscCall(PetscOptionsClear(NULL));
241 PetscCall(PrepareContextOnlyConfig(tmpdir, tmpdir_len, control_path, sizeof(control_path)));
242 file = fopen(control_path, "a");
243 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to reopen '%s'.", control_path);
244 fputs(extra_lines, file);
245 fclose(file);
246 PetscCall(PetscOptionsSetValue(NULL, "-control_file", control_path));
247 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
248 *ierr_out = CreateSimulationContext(0, NULL, simCtx_out);
249 PetscCall(PetscPopErrorHandler());
250 PetscFunctionReturn(0);
251}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestIEMConstantIsConfigurable()

static PetscErrorCode TestIEMConstantIsConfigurable ( void  )
static

Tests that the IEM mixing constant defaults to 2.0, follows -iem_constant, accepts zero (no micromixing), and refuses a negative or non-finite value.

Definition at line 257 of file test_setup_lifecycle.c.

258{
259 const char *cases[] = {"", "-iem_constant 3.5\n", "-iem_constant 0\n", "-iem_constant -1\n",
260 "-iem_constant nan\n", "-iem_constant inf\n"};
261 const PetscReal expected[] = {2.0, 3.5, 0.0, -1.0, -1.0, -1.0}; /* -1: refused */
262
263 PetscFunctionBeginUser;
264 for (size_t n = 0; n < sizeof(cases) / sizeof(cases[0]); ++n) {
265 char tmpdir[PETSC_MAX_PATH_LEN];
266 SimCtx *simCtx = NULL;
267 PetscErrorCode setup_ierr = 0;
268
269 PetscCall(TryContextWithExtraLines(cases[n], &simCtx, &setup_ierr, tmpdir, sizeof(tmpdir)));
270 if (expected[n] >= 0.0) {
271 PetscCall(PicurvAssertIntEqual(0, setup_ierr, "a non-negative -iem_constant must be accepted"));
272 PetscCall(PicurvAssertRealNear(expected[n], simCtx->iem_constant, 0.0,
273 "the IEM constant must follow -iem_constant, default 2.0"));
274 } else {
275 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_OUTOFRANGE, setup_ierr,
276 "a negative or non-finite -iem_constant must be refused"));
277 }
278 PetscCall(FreeLifecycleContext(&simCtx));
279 PetscCall(PetscOptionsClear(NULL));
280 PetscCall(PicurvRemoveTempDir(tmpdir));
281 }
282 PetscFunctionReturn(0);
283}
static PetscErrorCode TryContextWithExtraLines(const char *extra_lines, SimCtx **simCtx_out, PetscErrorCode *ierr_out, char *tmpdir, size_t tmpdir_len)
Builds a context from the fixture control file with extra lines appended.
static PetscErrorCode FreeLifecycleContext(SimCtx **simCtx_ptr)
Finalizes and frees one lifecycle test context, then clears any PETSc options used to build it.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscReal iem_constant
IEM mixing constant C_IEM in Omega = C_IEM Gamma / Delta^2 (default 2.0).
Definition variables.h:999
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestUnsolvedFlowUsesOneGridLevel()

static PetscErrorCode TestUnsolvedFlowUsesOneGridLevel ( void  )
static

Ensures a run that solves no pressure builds one grid level whatever -mg_level asks, and a solved flow keeps the levels it asks for.

Definition at line 289 of file test_setup_lifecycle.c.

290{
291 const char *cases[] = {"-mg_level 3\n", "-mg_level 3\n-euler_field_source analytical\n",
292 "-mg_level 3\n-euler_field_source load\n"};
293 const PetscInt expected[] = {3, 1, 1};
294
295 PetscFunctionBeginUser;
296 for (size_t n = 0; n < sizeof(cases) / sizeof(cases[0]); ++n) {
297 char tmpdir[PETSC_MAX_PATH_LEN];
298 SimCtx *simCtx = NULL;
299 PetscErrorCode setup_ierr = 0;
300
301 PetscCall(TryContextWithExtraLines(cases[n], &simCtx, &setup_ierr, tmpdir, sizeof(tmpdir)));
302 PetscCall(PicurvAssertIntEqual(0, setup_ierr, "the multigrid level options must be accepted"));
303 PetscCall(PicurvAssertIntEqual(expected[n], simCtx->mglevels,
304 "only a solved flow keeps its coarse grid levels"));
305 PetscCall(FreeLifecycleContext(&simCtx));
306 PetscCall(PetscOptionsClear(NULL));
307 PetscCall(PicurvRemoveTempDir(tmpdir));
308 }
309 PetscFunctionReturn(0);
310}
PetscInt mglevels
Definition variables.h:952
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParticleCountMustFitPetscInt()

static PetscErrorCode TestParticleCountMustFitPetscInt ( void  )
static

Ensures setup refuses a particle count whose widest swarm field PetscInt cannot index.

Particle fields have up to three components, so the limit is PETSC_MAX_INT / 3 particles; with 64-bit indices no representable -numParticles reaches it.

Definition at line 317 of file test_setup_lifecycle.c.

318{
319 char tmpdir[PETSC_MAX_PATH_LEN], line[64];
320 SimCtx *simCtx = NULL;
321 PetscErrorCode setup_ierr = 0;
322
323 PetscFunctionBeginUser;
324 if (sizeof(PetscInt) > 4) PetscFunctionReturn(0);
325 PetscCall(PetscSNPrintf(line, sizeof(line), "-numParticles %" PetscInt_FMT "\n", (PetscInt)(PETSC_MAX_INT / 3) + 1));
326 PetscCall(TryContextWithExtraLines(line, &simCtx, &setup_ierr, tmpdir, sizeof(tmpdir)));
327 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_OUTOFRANGE, setup_ierr,
328 "a particle count past PETSC_MAX_INT / 3 must be refused with 32-bit indices"));
329 PetscCall(FreeLifecycleContext(&simCtx));
330 PetscCall(PetscOptionsClear(NULL));
331 PetscCall(PicurvRemoveTempDir(tmpdir));
332 PetscFunctionReturn(0);
333}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupRejectsNonpositivePostInterval()

static PetscErrorCode TestSetupRejectsNonpositivePostInterval ( void  )
static

Ensures setup propagates invalid post intervals before either executable can loop.

Definition at line 338 of file test_setup_lifecycle.c.

339{
340 const char *options[] = {"-timeStep 0\n", "-timeStep -1\n"};
341
342 PetscFunctionBeginUser;
343 for (size_t n = 0; n < sizeof(options) / sizeof(options[0]); ++n) {
344 SimCtx *simCtx = NULL;
345 char tmpdir[PETSC_MAX_PATH_LEN];
346 PetscErrorCode setup_ierr;
347 PetscCall(TryContextWithExtraLines(options[n], &simCtx, &setup_ierr, tmpdir, sizeof(tmpdir)));
348 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_OUTOFRANGE, setup_ierr,
349 "setup must propagate rejection of a nonpositive post interval"));
350 PetscCall(FreeLifecycleContext(&simCtx));
351 PetscCall(PicurvRemoveTempDir(tmpdir));
352 }
353 PetscFunctionReturn(0);
354}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestConfiguredParticleInitialValue()

static PetscErrorCode TestConfiguredParticleInitialValue ( void  )
static

Checks a configured particle initial value through the production setup path.

Psi = x + 2*pid is read from the options, compiled, and applied once positions are final; it varies across particles wherever they are seeded. Particles fill the volume, so cells next to every face are occupied. Every particle must carry exactly its value, and the t=0 scatter must already reflect it: the count-weighted Eulerian Psi sums to the particles' total, so the first IEM update relaxes toward the right mean, and each non-periodic face's dummy cells carry the adjacent cell's mean.

Definition at line 366 of file test_setup_lifecycle.c.

367{
368 const char *options = "-numParticles 400\n"
369 "-pinit 1\n"
370 "-particle_fields_count 1\n"
371 "-particle_fields_0_name Psi\n"
372 "-particle_fields_0_expr_0 \"x + 2*pid\"\n";
373 SimCtx *simCtx = NULL;
374 UserCtx *user = NULL;
375 char tmpdir[PETSC_MAX_PATH_LEN];
376 PetscInt nlocal = 0;
377 const PetscReal *psi = NULL, *position = NULL;
378 const PetscInt64 *pid = NULL;
379 PetscReal particle_sum = 0.0, eulerian_sum = 0.0;
380
381 PetscFunctionBeginUser;
382 PetscCall(PicurvBuildTinyRuntimeContextWithOptions(NULL, PETSC_TRUE, options, &simCtx, &user,
383 tmpdir, sizeof(tmpdir)));
384 PetscCall(PicurvAssertBool((PetscBool)(simCtx->particleFieldPlan != NULL), "the plan is read from the options"));
385 PetscCall(InitializeEulerianState(simCtx));
386 PetscCall(InitializeParticleSwarm(simCtx));
387 PetscCall(PerformInitializedParticleSetup(simCtx));
388
389 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
390 PetscCall(DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
391 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void **)&position));
392 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_pid", NULL, NULL, (void **)&pid));
393 for (PetscInt p = 0; p < nlocal; ++p) {
394 const PetscReal expected = position[3 * p] * simCtx->scaling.L_ref + 2.0 * (PetscReal)pid[p];
395 PetscCall(PicurvAssertRealNear(expected, psi[p], 1.0e-12, "each particle carries its initial value"));
396 particle_sum += psi[p];
397 }
398 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_pid", NULL, NULL, (void **)&pid));
399 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void **)&position));
400 PetscCall(DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
401 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &particle_sum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
402 PetscCall(VecDot(user->Psi, user->ParticleCount, &eulerian_sum));
403 PetscCall(PicurvAssertRealNear(particle_sum, eulerian_sum, 1.0e-9,
404 "the t=0 scatter carries the initial value to the Eulerian mean"));
405 {
406 /* The scatter leaves empty dummy cells at zero; the production path must then give
407 each non-periodic face's dummy the adjacent cell's mean. */
408 const DMDALocalInfo info = user->info;
409 const PetscReal ***mean = NULL, ***count = NULL;
410 PetscReal checked = 0.0;
411
412 PetscCall(DMDAVecGetArrayRead(user->da, user->Psi, &mean));
413 PetscCall(DMDAVecGetArrayRead(user->da, user->ParticleCount, &count));
414 for (PetscInt k = info.zs; k < info.zs + info.zm; k++)
415 for (PetscInt j = info.ys; j < info.ys + info.ym; j++)
416 for (PetscInt i = info.xs; i < info.xs + info.xm; i++) {
417 /* A flat-face dummy cell and its adjacent interior cell, one axis at a time. */
418 const PetscInt index[3] = {i, j, k}, extent[3] = {info.mx, info.my, info.mz};
419 PetscInt dummy_axes = 0, axis = -1;
420
421 for (PetscInt d = 0; d < 3; d++) {
422 if (index[d] == 0 || index[d] == extent[d] - 1) { dummy_axes++; axis = d; }
423 }
424 if (dummy_axes != 1) continue;
425 if (user->boundary_faces[2 * axis].mathematical_type == PERIODIC) continue;
426 {
427 const PetscInt step = (index[axis] == 0) ? 1 : -1;
428 const PetscInt ai = i + (axis == 0 ? step : 0), aj = j + (axis == 1 ? step : 0),
429 ak = k + (axis == 2 ? step : 0);
430
431 if (count[ak][aj][ai] < 0.5) continue;
432 PetscCall(PicurvAssertRealNear(mean[ak][aj][ai], mean[k][j][i], 0.0,
433 "the scatter fills each dummy cell with the adjacent cell mean"));
434 checked += 1.0;
435 }
436 }
437 PetscCall(DMDAVecRestoreArrayRead(user->da, user->ParticleCount, &count));
438 PetscCall(DMDAVecRestoreArrayRead(user->da, user->Psi, &mean));
439 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &checked, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
440 PetscCall(PicurvAssertBool((PetscBool)(checked > 0.0),
441 "the fixture must seed particles next to a non-periodic face"));
442 }
443
444 PetscCall(FreeLifecycleContext(&simCtx));
445 PetscCall(PicurvRemoveTempDir(tmpdir));
446 PetscFunctionReturn(0);
447}
PetscErrorCode InitializeParticleSwarm(SimCtx *simCtx)
High-level particle initialization orchestrator for a simulation run.
PetscErrorCode InitializeEulerianState(SimCtx *simCtx)
High-level orchestrator to set the complete initial state of the Eulerian solver.
PetscErrorCode PerformInitializedParticleSetup(SimCtx *simCtx)
Finalizes the simulation setup at t=0, ensuring a consistent state before time marching.
Definition runloop.c:398
PetscErrorCode PicurvBuildTinyRuntimeContextWithOptions(const char *bcs_contents, PetscBool enable_particles, const char *extra_options, SimCtx **simCtx_out, UserCtx **user_out, char *tmpdir, size_t tmpdir_len)
Builds the tiny runtime context with extra control-file options appended.
@ PERIODIC
Definition variables.h:337
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:1155
PetscReal L_ref
Definition variables.h:889
Vec ParticleCount
Definition variables.h:1240
ScalingCtx scaling
Definition variables.h:996
DMDALocalInfo info
Definition variables.h:1142
BCType mathematical_type
Definition variables.h:418
struct ParticleFieldPlan * particleFieldPlan
Configured initial particle-field values, or NULL.
Definition variables.h:1053
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1130
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestConfiguredIEMUpdatesSwarm()

static PetscErrorCode TestConfiguredIEMUpdatesSwarm ( void  )
static

Checks configured IEM relaxation through the production swarm update.

Each particle must relax toward the mean of the particles now in its cell, at the configured rate. A zero constant switches micromixing off, and must leave Psi bit-identical: alternating values 0.1 and 0.7 do not survive m + (0.1 - m) * 1 exactly in mixed cells, so the exact comparison shows the update is skipped, not run at a zero rate.

Definition at line 457 of file test_setup_lifecycle.c.

458{
459 const char *options[] = {"", "-iem_constant 3.5\n", "-iem_constant 0\n"};
460 const PetscReal constants[] = {2.0, 3.5, 0.0};
461
462 PetscFunctionBeginUser;
463 for (size_t n = 0; n < sizeof(constants) / sizeof(constants[0]); ++n) {
464 SimCtx *simCtx = NULL;
465 UserCtx *user = NULL;
466 char tmpdir[PETSC_MAX_PATH_LEN];
467 PetscInt nlocal;
468 PetscReal *psi = NULL, *diffusivity = NULL, *psi_initial = NULL, *cell_mean = NULL;
469 PetscInt *cell = NULL;
470 const char *psi_name = ParticleFieldName(PARTICLE_FIELD_ID_PSI);
471 const char *diff_name = ParticleFieldName(PARTICLE_FIELD_ID_DIFFUSIVITY);
472 const char *cell_name = ParticleFieldName(PARTICLE_FIELD_ID_CELL_ID);
473
474 PetscCall(PicurvBuildTinyRuntimeContextWithOptions(NULL, PETSC_TRUE, options[n],
475 &simCtx, &user, tmpdir, sizeof(tmpdir)));
476 PetscCall(InitializeEulerianState(simCtx));
477 PetscCall(InitializeParticleSwarm(simCtx));
478 PetscCall(PerformInitializedParticleSetup(simCtx));
479 simCtx->dt = 0.5;
480 /* Controlled nonzero test data; no public scalar initializer is implied. A unit
481 * Jacobian makes the mixing length 1, and alternating particle values give every
482 * cell with two or more particles a mean the particles must relax toward. */
483 PetscCall(VecSet(user->lAj, 1.0));
484 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
485 PetscCall(PicurvAssertBool((PetscBool)(nlocal > 0), "IEM fixture must contain particles"));
486 PetscCall(DMSwarmGetField(user->swarm, psi_name, NULL, NULL, (void **)&psi));
487 PetscCall(DMSwarmGetField(user->swarm, diff_name, NULL, NULL, (void **)&diffusivity));
488 PetscCall(DMSwarmGetField(user->swarm, cell_name, NULL, NULL, (void **)&cell));
489 PetscCall(PetscMalloc2(nlocal, &psi_initial, nlocal, &cell_mean));
490 for (PetscInt p = 0; p < nlocal; ++p) {
491 psi[p] = psi_initial[p] = (p % 2) ? 0.7 : 0.1;
492 diffusivity[p] = 0.2;
493 }
494 /* Each particle's own-cell mean, from the particles where they are now. */
495 for (PetscInt p = 0; p < nlocal; ++p) {
496 PetscReal sum = 0.0, count = 0.0;
497 for (PetscInt q = 0; q < nlocal; ++q) {
498 if (cell[3*q] == cell[3*p] && cell[3*q+1] == cell[3*p+1] && cell[3*q+2] == cell[3*p+2]) {
499 sum += psi_initial[q]; count += 1.0;
500 }
501 }
502 cell_mean[p] = sum / count;
503 }
504 PetscCall(DMSwarmRestoreField(user->swarm, cell_name, NULL, NULL, (void **)&cell));
505 PetscCall(DMSwarmRestoreField(user->swarm, diff_name, NULL, NULL, (void **)&diffusivity));
506 PetscCall(DMSwarmRestoreField(user->swarm, psi_name, NULL, NULL, (void **)&psi));
507 PetscCall(UpdateAllParticleFields(user));
508 PetscCall(DMSwarmGetField(user->swarm, psi_name, NULL, NULL, (void **)&psi));
509 for (PetscInt p = 0; p < nlocal; ++p) {
510 if (constants[n] == 0.0) {
511 PetscCall(PicurvAssertBool((PetscBool)(psi[p] == psi_initial[p]),
512 "a zero IEM constant must leave Psi bit-identical"));
513 } else {
514 PetscCall(PicurvAssertRealNear(cell_mean[p] + (psi_initial[p] - cell_mean[p]) * PetscExpReal(-constants[n] * 0.2 * 0.5),
515 psi[p], 1.e-12, "configured IEM constant must relax each particle toward its cell's current mean"));
516 }
517 }
518 PetscCall(DMSwarmRestoreField(user->swarm, psi_name, NULL, NULL, (void **)&psi));
519 PetscCall(PetscFree2(psi_initial, cell_mean));
520 PetscCall(FreeLifecycleContext(&simCtx));
521 PetscCall(PicurvRemoveTempDir(tmpdir));
522 }
523 PetscFunctionReturn(0);
524}
PetscErrorCode UpdateAllParticleFields(UserCtx *user)
Orchestrates the update of all physical properties for particles.
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_CELL_ID
@ PARTICLE_FIELD_ID_PSI
@ PARTICLE_FIELD_ID_DIFFUSIVITY
PetscReal dt
Definition variables.h:924
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestIEMRelaxesTowardOwnCellMean()

static PetscErrorCode TestIEMRelaxesTowardOwnCellMean ( void  )
static

Checks that IEM relaxes each particle toward its own cell's scattered mean.

Particles start at random 0 or 1, so cell means differ from cell to cell and from the zero in the boundary storage slots. Relaxing toward the particle's own cell mean at a rate uniform within the cell conserves every cell's scalar sum, so the total is unchanged while the spread shrinks; reading a neighbour's mean, or a boundary slot, breaks the conservation.

Definition at line 534 of file test_setup_lifecycle.c.

535{
536 const char *options = "-particle_fields_count 1\n"
537 "-particle_fields_0_name Psi\n"
538 "-particle_fields_0_expr_0 \"where(uniform() < 0.5, 0, 1)\"\n";
539 SimCtx *simCtx = NULL;
540 UserCtx *user = NULL;
541 char tmpdir[PETSC_MAX_PATH_LEN];
542 PetscInt nlocal = 0;
543 PetscReal *psi = NULL, *diffusivity = NULL;
544 PetscReal sums[2][2] = {{0.0, 0.0}, {0.0, 0.0}}; /* [before|after][sum|sum of squares] */
545
546 PetscFunctionBeginUser;
547 PetscCall(PicurvBuildTinyRuntimeContextWithOptions(NULL, PETSC_TRUE, options, &simCtx, &user,
548 tmpdir, sizeof(tmpdir)));
549 PetscCall(InitializeEulerianState(simCtx));
550 PetscCall(InitializeParticleSwarm(simCtx));
551 PetscCall(PerformInitializedParticleSetup(simCtx));
552 simCtx->dt = 0.5;
553
554 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
555 PetscCall(DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
556 PetscCall(DMSwarmGetField(user->swarm, "Diffusivity", NULL, NULL, (void **)&diffusivity));
557 for (PetscInt p = 0; p < nlocal; ++p) {
558 diffusivity[p] = 0.2;
559 sums[0][0] += psi[p];
560 sums[0][1] += psi[p] * psi[p];
561 }
562 PetscCall(DMSwarmRestoreField(user->swarm, "Diffusivity", NULL, NULL, (void **)&diffusivity));
563 PetscCall(DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
564
565 PetscCall(UpdateAllParticleFields(user));
566
567 PetscCall(DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
568 for (PetscInt p = 0; p < nlocal; ++p) {
569 sums[1][0] += psi[p];
570 sums[1][1] += psi[p] * psi[p];
571 }
572 PetscCall(DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
573 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, sums, 4, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
574
575 PetscCall(PicurvAssertBool((PetscBool)(sums[0][0] > 0.0 && sums[0][0] < (PetscReal)simCtx->np),
576 "the fixture must start with both values present"));
577 PetscCall(PicurvAssertRealNear(sums[0][0], sums[1][0], 1.0e-9,
578 "relaxing toward each particle's own cell mean conserves the scalar"));
579 PetscCall(PicurvAssertBool((PetscBool)(sums[1][1] < sums[0][1] - 1.0e-6),
580 "the update must reduce the scalar's spread"));
581
582 PetscCall(FreeLifecycleContext(&simCtx));
583 PetscCall(PicurvRemoveTempDir(tmpdir));
584 PetscFunctionReturn(0);
585}
PetscInt np
Definition variables.h:1040
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPostprocessorLoadsSavedParticleAverages()

static PetscErrorCode TestPostprocessorLoadsSavedParticleAverages ( void  )
static

Checks that post-processing loads the particle averages a checkpoint holds.

A case with restart_mode: init reseeds particles on a solver restart, so the solver must not restore the averages of the particles it discards; the postprocessor reads the same control settings but visualizes what was saved, so it must load them, and refresh the ghosted copy that nodal averaging reads.

Definition at line 594 of file test_setup_lifecycle.c.

595{
596 const char *options = "-particle_fields_count 1\n"
597 "-particle_fields_0_name Psi\n"
598 "-particle_fields_0_expr_0 \"where(uniform() < 0.5, 0, 1)\"\n"
599 "-particle_restart_mode init\n";
600 SimCtx *simCtx = NULL;
601 UserCtx *user = NULL;
602 char tmpdir[PETSC_MAX_PATH_LEN];
603 Vec saved = NULL, local_saved = NULL;
604 PetscReal saved_norm = 0.0, difference = 0.0;
605
606 PetscFunctionBeginUser;
607 PetscCall(PicurvBuildTinyRuntimeContextWithOptions(NULL, PETSC_TRUE, options, &simCtx, &user,
608 tmpdir, sizeof(tmpdir)));
609 PetscCall(InitializeEulerianState(simCtx));
610 PetscCall(InitializeParticleSwarm(simCtx));
611 PetscCall(PerformInitializedParticleSetup(simCtx));
612 PetscCall(VecDuplicate(user->Psi, &saved));
613 PetscCall(VecCopy(user->Psi, saved));
614 PetscCall(VecNorm(saved, NORM_INFINITY, &saved_norm));
615 PetscCall(PicurvAssertBool((PetscBool)(saved_norm > 0.0), "the fixture must scatter a nonzero Psi"));
616 PetscCall(WriteCheckpointBundle(simCtx, "test"));
617
618 PetscCall(PetscCalloc1(1, &simCtx->pps));
619 PetscCall(PetscStrncpy(simCtx->pps->source_dir, simCtx->output_dir, sizeof(simCtx->pps->source_dir)));
621 PetscCall(VecSet(user->Psi, 0.0));
622 PetscCall(VecSet(user->lPsi, 0.0));
623 PetscCall(ReadSimulationFields(user, simCtx->step));
624
625 PetscCall(VecAXPY(saved, -1.0, user->Psi));
626 PetscCall(VecNorm(saved, NORM_INFINITY, &difference));
627 PetscCall(PicurvAssertRealNear(0.0, difference, 1.0e-12, "post-processing restores the saved Psi average"));
628 PetscCall(DMCreateLocalVector(user->da, &local_saved));
629 PetscCall(DMGlobalToLocalBegin(user->da, user->Psi, INSERT_VALUES, local_saved));
630 PetscCall(DMGlobalToLocalEnd(user->da, user->Psi, INSERT_VALUES, local_saved));
631 PetscCall(VecAXPY(local_saved, -1.0, user->lPsi));
632 PetscCall(VecNorm(local_saved, NORM_INFINITY, &difference));
633 PetscCall(PicurvAssertRealNear(0.0, difference, 1.0e-12, "the ghosted Psi is refreshed for nodal averaging"));
634
635 simCtx->exec_mode = EXEC_MODE_SOLVER;
636 PetscCall(PetscFree(simCtx->pps));
637 PetscCall(VecDestroy(&local_saved));
638 PetscCall(VecDestroy(&saved));
639 PetscCall(FreeLifecycleContext(&simCtx));
640 PetscCall(PicurvRemoveTempDir(tmpdir));
641 PetscFunctionReturn(0);
642}
PetscErrorCode ReadSimulationFields(UserCtx *user, PetscInt ti)
Reads binary field data for velocity, pressure, and other required vectors.
Definition io.c:1434
PetscErrorCode WriteCheckpointBundle(SimCtx *simCtx, const char *reason)
Write and atomically publish one complete checkpoint bundle.
Definition io.c:2542
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:931
char source_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:786
PetscInt step
Definition variables.h:915
PostProcessParams * pps
Definition variables.h:1114
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:880
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSharedRuntimeFixtureContracts()

static PetscErrorCode TestSharedRuntimeFixtureContracts ( void  )
static

Tests that the shared richer runtime fixture mirrors normalized production setup contracts.

Definition at line 647 of file test_setup_lifecycle.c.

648{
649 SimCtx *simCtx = NULL;
650 UserCtx *user = NULL;
651 char tmpdir[PETSC_MAX_PATH_LEN];
652
653 PetscFunctionBeginUser;
654 PetscCall(PicurvBuildTinyRuntimeContext(NULL, PETSC_FALSE, &simCtx, &user, tmpdir, sizeof(tmpdir)));
655
656 PetscCall(PicurvAssertBool((PetscBool)(user->bbox.min_coords.x >= -2.0e-6), "runtime fixture bbox xmin should stay inside normalized domain tolerance"));
657 PetscCall(PicurvAssertBool((PetscBool)(user->bbox.max_coords.x <= 1.0 + 2.0e-6), "runtime fixture bbox xmax should stay inside normalized domain tolerance"));
658 PetscCall(PicurvAssertBool((PetscBool)(user->bbox.max_coords.y <= 1.0 + 2.0e-6), "runtime fixture bbox ymax should stay inside normalized domain tolerance"));
659 PetscCall(PicurvAssertBool((PetscBool)(user->bbox.max_coords.z <= 1.0 + 2.0e-6), "runtime fixture bbox zmax should stay inside normalized domain tolerance"));
660 PetscCall(PicurvAssertBool((PetscBool)(simCtx->bboxlist != NULL), "runtime fixture should gather bboxlist through SetupDomainRankInfo"));
661 PetscCall(PicurvAssertBool((PetscBool)(user->RankCellInfoMap != NULL), "runtime fixture should gather rank-cell ownership metadata"));
662 PetscCall(PicurvAssertBool((PetscBool)(simCtx->bboxlist[simCtx->rank].max_coords.x >= user->bbox.max_coords.x - 1.0e-10),
663 "runtime fixture rank bbox entry should include the local bbox extent"));
664
665 PetscCall(PicurvRemoveTempDir(tmpdir));
666 PetscCall(FreeLifecycleContext(&simCtx));
667 PetscFunctionReturn(0);
668}
PetscMPIInt rank
Definition variables.h:910
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:200
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:199
PetscScalar x
Definition variables.h:122
RankCellInfo * RankCellInfoMap
Definition variables.h:1238
BoundingBox * bboxlist
Definition variables.h:1043
PetscScalar z
Definition variables.h:122
PetscScalar y
Definition variables.h:122
BoundingBox bbox
Definition variables.h:1146
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AssertStoredLocalInfoMatchesDMs()

static PetscErrorCode AssertStoredLocalInfoMatchesDMs ( UserCtx *  user)
static

Asserts that one block's stored local info matches what its DMs report.

Grid, rank and particle code read user->info in place of DMDAGetLocalInfo on user->da and user->fda, which relies on both DMs sharing one decomposition.

Definition at line 675 of file test_setup_lifecycle.c.

676{
677 DMDALocalInfo dm_info[2];
678 const char *names[2] = {"da", "fda"};
679
680 PetscFunctionBeginUser;
681 PetscCall(DMDAGetLocalInfo(user->da, &dm_info[0]));
682 PetscCall(DMDAGetLocalInfo(user->fda, &dm_info[1]));
683 for (PetscInt d = 0; d < 2; ++d) {
684 const DMDALocalInfo *a = &dm_info[d], *b = &user->info;
685 const PetscInt got[15] = {a->mx, a->my, a->mz, a->xs, a->ys, a->zs, a->xm, a->ym, a->zm,
686 a->gxs, a->gys, a->gzs, a->gxm, a->gym, a->gzm};
687 const PetscInt want[15] = {b->mx, b->my, b->mz, b->xs, b->ys, b->zs, b->xm, b->ym, b->zm,
688 b->gxs, b->gys, b->gzs, b->gxm, b->gym, b->gzm};
689 char msg[128];
690 for (PetscInt f = 0; f < 15; ++f) {
691 PetscCall(PetscSNPrintf(msg, sizeof(msg), "user->info range %" PetscInt_FMT " should match %s", f, names[d]));
692 PetscCall(PicurvAssertIntEqual(want[f], got[f], msg));
693 }
694 PetscCall(PicurvAssertBool((PetscBool)(a->bx == b->bx && a->by == b->by && a->bz == b->bz),
695 "user->info boundary types should match the DM"));
696 }
697 PetscFunctionReturn(0);
698}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupLifecycleCoreSolverSetup()

static PetscErrorCode TestSetupLifecycleCoreSolverSetup ( void  )
static

Tests the core setup lifecycle through environment, grid, BC, rank-info, and Eulerian-state initialization.

Definition at line 703 of file test_setup_lifecycle.c.

704{
705 SimCtx *simCtx = NULL;
706 UserCtx *user = NULL;
707 char tmpdir[PETSC_MAX_PATH_LEN];
708 char results_dir[PETSC_MAX_PATH_LEN];
709 char logs_dir[PETSC_MAX_PATH_LEN];
710 Cmpnts ***ucont = NULL;
711
712 PetscFunctionBeginUser;
713 PetscCall(BuildLifecycleContext(PETSC_FALSE, &simCtx, tmpdir, sizeof(tmpdir)));
714 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
715
716 PetscCall(PetscSNPrintf(results_dir, sizeof(results_dir), "%s/results", tmpdir));
717 PetscCall(PetscSNPrintf(logs_dir, sizeof(logs_dir), "%s/logs", tmpdir));
718 PetscCall(PicurvAssertBool((PetscBool)(user->da != NULL), "SetupGridAndSolvers should allocate da"));
719 PetscCall(PicurvAssertBool((PetscBool)(user->fda != NULL), "SetupGridAndSolvers should allocate coordinate DM"));
720 PetscCall(PicurvAssertIntEqual(user->IM + 1, user->info.mx, "DM node count should match IM+1"));
721 for (PetscInt level = 0; level < simCtx->usermg.mglevels; ++level) {
722 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
723 PetscCall(AssertStoredLocalInfoMatchesDMs(&simCtx->usermg.mgctx[level].user[bi]));
724 }
725 }
726 PetscCall(PicurvAssertBool(user->inletFaceDefined, "SetupBoundaryConditions should identify the inlet face"));
727 PetscCall(PicurvAssertIntEqual(BC_FACE_NEG_Z, user->identifiedInletBCFace, "NEG_Z should be the configured inlet face"));
728 PetscCall(PicurvAssertBool((PetscBool)(simCtx->bboxlist != NULL), "SetupDomainRankInfo should build bboxlist"));
729 PetscCall(PicurvAssertBool((PetscBool)(user->RankCellInfoMap != NULL), "SetupDomainRankInfo should build rank-cell decomposition map"));
730 PetscCall(AssertDirectoryExists(results_dir, "SetupSimulationEnvironment should create the output directory"));
731 PetscCall(AssertDirectoryExists(logs_dir, "SetupSimulationEnvironment should create the log directory"));
732
733 PetscCall(InitializeEulerianState(simCtx));
734 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucont, &ucont));
735 PetscCall(PicurvAssertBool((PetscBool)(ucont[1][1][1].z > 0.0),
736 "InitializeEulerianState should seed a positive inlet-aligned interior field"));
737 PetscCall(PicurvAssertRealNear(ucont[1][1][1].z, ucont[2][2][2].z, 1.0e-12,
738 "InitializeEulerianState should initialize a spatially consistent interior field"));
739 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucont, &ucont));
740
741 PetscCall(PicurvRemoveTempDir(tmpdir));
742 PetscCall(FreeLifecycleContext(&simCtx));
743 PetscFunctionReturn(0);
744}
static PetscErrorCode AssertDirectoryExists(const char *path, const char *context)
Asserts that a directory path exists and is readable.
static PetscErrorCode BuildLifecycleContext(PetscBool enable_particles, SimCtx **simCtx_out, char *tmpdir, size_t tmpdir_len)
Builds a full setup fixture through environment, grid, BC, and domain-rank initialization.
static PetscErrorCode AssertStoredLocalInfoMatchesDMs(UserCtx *user)
Asserts that one block's stored local info matches what its DMs report.
UserCtx * user
Definition variables.h:759
PetscBool inletFaceDefined
Definition variables.h:1156
PetscInt block_number
Definition variables.h:1002
BCFace identifiedInletBCFace
Definition variables.h:1157
UserMG usermg
Definition variables.h:1067
Vec Ucont
Definition variables.h:1169
PetscInt mglevels
Definition variables.h:766
PetscInt IM
Definition variables.h:1144
MGCtx * mgctx
Definition variables.h:769
@ BC_FACE_NEG_Z
Definition variables.h:309
A 3D point or vector with PetscScalar components.
Definition variables.h:121
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupLifecycleParticleInitialization()

static PetscErrorCode TestSetupLifecycleParticleInitialization ( void  )
static

Tests particle-swarm initialization and deterministic settlement on a tiny fully initialized case.

Definition at line 749 of file test_setup_lifecycle.c.

750{
751 SimCtx *simCtx = NULL;
752 UserCtx *user = NULL;
753 char tmpdir[PETSC_MAX_PATH_LEN];
754 PetscInt nlocal = 0;
755 PetscInt *cell_ids = NULL;
756 PetscInt *status = NULL;
757
758 PetscFunctionBeginUser;
759 PetscCall(BuildLifecycleContext(PETSC_TRUE, &simCtx, tmpdir, sizeof(tmpdir)));
760 PetscCall(InitializeEulerianState(simCtx));
761 PetscCall(InitializeParticleSwarm(simCtx));
762 PetscCall(PerformInitializedParticleSetup(simCtx));
763
764 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
765 PetscCall(PicurvAssertBool((PetscBool)(user->swarm != NULL), "InitializeParticleSwarm should allocate the solver swarm"));
766 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
767 PetscCall(PicurvAssertIntEqual(8, nlocal, "single-rank lifecycle particle setup should own all seeded particles"));
768
769 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
770 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
771 for (PetscInt p = 0; p < nlocal; ++p) {
772 PetscCall(PicurvAssertBool((PetscBool)(cell_ids[3 * p + 0] >= 0), "settled particles should have a valid i cell id"));
773 PetscCall(PicurvAssertBool((PetscBool)(cell_ids[3 * p + 1] >= 0), "settled particles should have a valid j cell id"));
774 PetscCall(PicurvAssertBool((PetscBool)(cell_ids[3 * p + 2] >= 0), "settled particles should have a valid k cell id"));
775 PetscCall(PicurvAssertIntEqual(ACTIVE_AND_LOCATED, status[p], "settled particles should be marked ACTIVE_AND_LOCATED"));
776 }
777 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
778 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
779
780 PetscCall(PicurvRemoveTempDir(tmpdir));
781 PetscCall(FreeLifecycleContext(&simCtx));
782 PetscFunctionReturn(0);
783}
@ ACTIVE_AND_LOCATED
Definition variables.h:165
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupLifecycleScatterMetricsAtStepZero()

static PetscErrorCode TestSetupLifecycleScatterMetricsAtStepZero ( void  )
static

Tests that step-zero scalar verification emits scatter_metrics.csv during initialized setup.

Definition at line 788 of file test_setup_lifecycle.c.

789{
790 SimCtx *simCtx = NULL;
791 UserCtx *user = NULL;
792 char tmpdir[PETSC_MAX_PATH_LEN];
793 char metrics_path[PETSC_MAX_PATH_LEN];
794
795 PetscFunctionBeginUser;
796 PetscCall(BuildLifecycleContext(PETSC_TRUE, &simCtx, tmpdir, sizeof(tmpdir)));
797 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
798 PetscCall(PetscStrncpy(simCtx->eulerianSource, "analytical", sizeof(simCtx->eulerianSource)));
799 PetscCall(PetscStrncpy(simCtx->AnalyticalSolutionType, "ZERO_FLOW", sizeof(simCtx->AnalyticalSolutionType)));
800 simCtx->StepsToRun = 0;
801 simCtx->StartStep = 0;
802 simCtx->verificationScalar.enabled = PETSC_TRUE;
803 PetscCall(PetscStrncpy(simCtx->verificationScalar.mode,
804 "analytical",
805 sizeof(simCtx->verificationScalar.mode)));
806 PetscCall(PetscStrncpy(simCtx->verificationScalar.profile,
807 "CONSTANT",
808 sizeof(simCtx->verificationScalar.profile)));
809 simCtx->verificationScalar.value = 1.25;
810
811 PetscCall(InitializeEulerianState(simCtx));
812 PetscCall(InitializeParticleSwarm(simCtx));
813 PetscCall(PerformInitializedParticleSetup(simCtx));
814
815 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/results/analysis/metrics/scatter_metrics.csv", tmpdir));
816 PetscCall(PicurvAssertFileExists(metrics_path,
817 "PerformInitializedParticleSetup should emit scatter_metrics.csv for a zero-step scalar verification run"));
818 PetscCall(PicurvAssertBool((PetscBool)(user->swarm != NULL),
819 "zero-step scalar verification setup should leave the swarm initialized"));
820
821 PetscCall(PicurvRemoveTempDir(tmpdir));
822 PetscCall(FreeLifecycleContext(&simCtx));
823 PetscFunctionReturn(0);
824}
PetscErrorCode PicurvAssertFileExists(const char *path, const char *context)
Asserts that a filesystem path exists as a readable file.
PetscInt StepsToRun
Definition variables.h:918
PetscInt StartStep
Definition variables.h:917
VerificationScalarConfig verificationScalar
Definition variables.h:990
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:929
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:943
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupLifecycleRandomGeneratorsAndCleanup()

static PetscErrorCode TestSetupLifecycleRandomGeneratorsAndCleanup ( void  )
static

Tests standalone RNG initialization helpers and minimal-context cleanup.

Definition at line 829 of file test_setup_lifecycle.c.

830{
831 SimCtx *simCtx = NULL;
832 UserCtx *user = NULL;
833 PetscRandom randx = NULL, randy = NULL, randz = NULL;
834 PetscRandom rand_i = NULL, rand_j = NULL, rand_k = NULL;
835 PetscScalar sample_x = 0.0, sample_i = 0.0;
836 PetscReal seconds = 0.0;
837
838 PetscFunctionBeginUser;
839 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
840 user->bbox.min_coords.x = 0.0;
841 user->bbox.min_coords.y = 0.0;
842 user->bbox.min_coords.z = 0.0;
843 user->bbox.max_coords.x = 1.0;
844 user->bbox.max_coords.y = 2.0;
845 user->bbox.max_coords.z = 3.0;
846
847 PetscCall(InitializeRandomGenerators(user, &randx, &randy, &randz));
848 PetscCall(InitializeLogicalSpaceRNGs(simCtx->particleRandomSeed, &rand_i, &rand_j, &rand_k));
849 PetscCall(PicurvAssertBool(RuntimeWalltimeGuardParsePositiveSeconds("12.5", &seconds), "RuntimeWalltimeGuardParsePositiveSeconds should parse positive numeric strings"));
850 PetscCall(PicurvAssertRealNear(12.5, seconds, 1.0e-12, "RuntimeWalltimeGuardParsePositiveSeconds parsed value"));
851
852 PetscCall(PetscRandomGetValue(randx, &sample_x));
853 PetscCall(PetscRandomGetValue(rand_i, &sample_i));
854 PetscCall(PicurvAssertBool((PetscBool)(PetscRealPart(sample_x) >= 0.0 && PetscRealPart(sample_x) <= 1.0),
855 "InitializeRandomGenerators should honor the configured bbox interval"));
856 PetscCall(PicurvAssertBool((PetscBool)(PetscRealPart(sample_i) >= 0.0 && PetscRealPart(sample_i) <= 1.0),
857 "InitializeLogicalSpaceRNGs should generate logical coordinates in [0,1]"));
858
859 PetscCall(PetscRandomDestroy(&randx));
860 PetscCall(PetscRandomDestroy(&randy));
861 PetscCall(PetscRandomDestroy(&randz));
862 PetscCall(PetscRandomDestroy(&rand_i));
863 PetscCall(PetscRandomDestroy(&rand_j));
864 PetscCall(PetscRandomDestroy(&rand_k));
865 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
866 PetscFunctionReturn(0);
867}
PetscErrorCode InitializeRandomGenerators(UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
Initializes random number generators for assigning particle properties.
Definition setup.c:3950
PetscErrorCode InitializeLogicalSpaceRNGs(PetscInt base_seed, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
Initializes random number generators for logical space operations [0.0, 1.0).
Definition setup.c:3992
PetscBool RuntimeWalltimeGuardParsePositiveSeconds(const char *text, PetscReal *seconds_out)
Parse a positive floating-point seconds value from runtime metadata.
Definition setup.c:143
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscInt particleRandomSeed
Base seed for every particle RNG stream (-particle_random_seed).
Definition variables.h:1041
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSetupLifecycleCleanupAcrossInitializationStates()

static PetscErrorCode TestSetupLifecycleCleanupAcrossInitializationStates ( void  )
static

Tests cleanup after partial and fuller setup states without requiring unsupported double-finalization behavior.

Definition at line 872 of file test_setup_lifecycle.c.

873{
874 SimCtx *context_only = NULL;
875 SimCtx *grid_only = NULL;
876 char context_tmpdir[PETSC_MAX_PATH_LEN];
877 char grid_tmpdir[PETSC_MAX_PATH_LEN];
878
879 PetscFunctionBeginUser;
880 PetscCall(BuildContextOnly(&context_only, context_tmpdir, sizeof(context_tmpdir)));
881 PetscCall(PicurvAssertBool((PetscBool)(context_only != NULL), "CreateSimulationContext should allocate the top-level SimCtx"));
882 PetscCall(PicurvAssertIntEqual(1, context_only->block_number, "CreateSimulationContext should parse the configured block count"));
884 "deprecated RK4 selector should normalize to the Jameson solver enum"));
886 "deprecated RK4 residual-noise option should populate the Jameson control"));
887 PetscCall(PicurvAssertRealNear(1.0e-8, context_only->mom_resid_atol, 1.0e-12,
888 "momentum absolute residual tolerance should be parsed"));
889 PetscCall(PicurvAssertRealNear(1.0e-3, context_only->mom_resid_rtol, 1.0e-12,
890 "momentum relative residual tolerance should be parsed"));
891 PetscCall(PicurvAssertBool(context_only->mom_nk_monitor_history,
892 "Newton structured history monitor should be parsed"));
893 PetscCall(PetscOptionsClear(NULL));
894 PetscCall(PicurvRemoveTempDir(context_tmpdir));
895 PetscCall(FreeLifecycleContext(&context_only));
896
897 PetscCall(BuildContextOnly(&grid_only, grid_tmpdir, sizeof(grid_tmpdir)));
898 PetscCall(SetupSimulationEnvironment(grid_only));
899 PetscCall(SetupGridAndSolvers(grid_only));
900 PetscCall(PicurvAssertBool((PetscBool)(grid_only->usermg.mgctx[grid_only->usermg.mglevels - 1].user->Ucont != NULL),
901 "SetupGridAndSolvers should allocate baseline Eulerian vectors"));
902 PetscCall(PicurvRemoveTempDir(grid_tmpdir));
903 PetscCall(FreeLifecycleContext(&grid_only));
904 PetscFunctionReturn(0);
905}
PetscErrorCode SetupGridAndSolvers(SimCtx *simCtx)
The main orchestrator for setting up all grid-related components.
Definition setup.c:2154
PetscErrorCode SetupSimulationEnvironment(SimCtx *simCtx)
Verifies and prepares the complete I/O environment for a simulation run.
Definition setup.c:1840
static PetscErrorCode BuildContextOnly(SimCtx **simCtx_out, char *tmpdir, size_t tmpdir_len)
Builds only the top-level simulation context used by partial-initialization cleanup tests.
PetscBool mom_nk_monitor_history
Definition variables.h:964
@ MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK
Definition variables.h:721
PetscReal mom_dt_jameson_residual_norm_noise_allowance_factor
Definition variables.h:959
PetscReal mom_resid_rtol
Definition variables.h:951
PetscReal mom_resid_atol
Definition variables.h:951
MomentumSolverType mom_solver_type
Definition variables.h:949
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestFieldCatalogMetadataAndViews()

static PetscErrorCode TestFieldCatalogMetadataAndViews ( void  )
static

Verifies catalog completeness, stable name resolution, and runtime view binding.

Definition at line 910 of file test_setup_lifecycle.c.

911{
912 SimCtx *simCtx = NULL;
913 UserCtx *user = NULL;
914 FieldId parsed_id = FIELD_ID_INVALID;
915 FieldView view;
916 const FieldDescriptor *descriptor = NULL;
917 Vec coordinates = NULL;
918 Vec local_coordinates = NULL;
919 PetscErrorCode unknown_name_ierr;
920 PetscErrorCode unavailable_view_ierr;
921
922 PetscFunctionBeginUser;
923 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
924
925 for (PetscInt raw_id = 0; raw_id < FIELD_ID_COUNT; ++raw_id) {
926 PetscCall(FieldGetDescriptor((FieldId)raw_id, &descriptor));
927 PetscCall(PicurvAssertIntEqual(raw_id, (PetscInt)descriptor->id,
928 "catalog entry should retain its declared FieldId"));
929 PetscCall(PicurvAssertBool((PetscBool)(descriptor->canonical_name != NULL &&
930 descriptor->canonical_name[0] != '\0'),
931 "every field descriptor should have a canonical name"));
932 PetscCall(PicurvAssertBool((PetscBool)(descriptor->dof == 1 ||
933 descriptor->dof == 2 ||
934 descriptor->dof == 3),
935 "every ghost-updatable catalog field should declare a supported dof"));
936 PetscCall(PicurvAssertBool((PetscBool)((descriptor->capabilities &
938 "every phase-one field should advertise ghost-update capability"));
939 PetscCall(FieldIdFromName(descriptor->canonical_name, &parsed_id));
940 PetscCall(PicurvAssertIntEqual(raw_id, (PetscInt)parsed_id,
941 "canonical field names should round-trip to their IDs"));
942 PetscCall(PicurvAssertBool((PetscBool)(strcmp(FieldCanonicalName((FieldId)raw_id),
943 descriptor->canonical_name) == 0),
944 "FieldCanonicalName should return catalog-owned canonical text"));
945 }
946
947 PetscCall(FieldIdFromName("eddy viscosity", &parsed_id));
948 PetscCall(PicurvAssertIntEqual(FIELD_ID_NU_T, parsed_id,
949 "Nu_t compatibility alias should resolve case-insensitively"));
950 PetscCall(FieldIdFromName("cs", &parsed_id));
951 PetscCall(PicurvAssertIntEqual(FIELD_ID_CS, parsed_id,
952 "CS compatibility alias should resolve case-insensitively"));
953 PetscCall(FieldIdFromName("X-Face-Centers", &parsed_id));
954 PetscCall(PicurvAssertIntEqual(FIELD_ID_CENTX, parsed_id,
955 "diagnostic face-center name should resolve to the canonical field"));
956
957 PetscCall(FieldGetDescriptor(FIELD_ID_UCONT, &descriptor));
959 "Ucont should retain component-staggered topology metadata"));
961 "Ucont should retain component-staggered ghost repair metadata"));
962 PetscCall(FieldGetDescriptor(FIELD_ID_CSI, &descriptor));
963 PetscCall(PicurvAssertIntEqual(FIELD_LAYOUT_I_FACE, descriptor->layout,
964 "Csi should retain I-face topology metadata"));
966 "Csi should retain I-face ghost repair metadata"));
967 PetscCall(FieldGetDescriptor(FIELD_ID_IAJ, &descriptor));
968 PetscCall(PicurvAssertIntEqual(1, descriptor->dof,
969 "IAj should retain scalar face-field metadata"));
970
971 PetscCall(FieldGetView(user, FIELD_ID_P, &view));
972 PetscCall(PicurvAssertBool((PetscBool)(view.dm == user->da &&
973 view.global_vec == user->P &&
974 view.local_vec == user->lP),
975 "P field view should bind the existing scalar DM and Vec pair"));
976 PetscCall(FieldGetView(user, FIELD_ID_UCAT, &view));
977 PetscCall(PicurvAssertBool((PetscBool)(view.dm == user->fda &&
978 view.global_vec == user->Ucat &&
979 view.local_vec == user->lUcat),
980 "Ucat field view should bind the existing vector DM and Vec pair"));
981
982 PetscCall(DMGetCoordinates(user->da, &coordinates));
983 PetscCall(DMGetCoordinatesLocal(user->da, &local_coordinates));
984 PetscCall(FieldGetView(user, FIELD_ID_COORDINATES, &view));
985 PetscCall(PicurvAssertBool((PetscBool)(view.dm == user->fda &&
986 view.global_vec == coordinates &&
987 view.local_vec == local_coordinates),
988 "coordinate field view should bind PETSc-owned coordinate vectors"));
989
990 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
991 unknown_name_ierr = FieldIdFromName("NotARegisteredEulerianField", &parsed_id);
992 PetscCall(PetscPopErrorHandler());
993 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_UNKNOWN_TYPE, unknown_name_ierr,
994 "unknown field names should fail at the name-ingress boundary"));
995 PetscCall(PicurvAssertIntEqual(FIELD_ID_INVALID, parsed_id,
996 "failed field-name resolution should return FIELD_ID_INVALID"));
997
998 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
999 unavailable_view_ierr = FieldGetView(user, FIELD_ID_CS, &view);
1000 PetscCall(PetscPopErrorHandler());
1001 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_WRONGSTATE, unavailable_view_ierr,
1002 "catalogued optional fields without storage should report unavailable state"));
1003
1004 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1005 PetscFunctionReturn(0);
1006}
FieldLayout layout
PetscErrorCode FieldIdFromName(const char *field_name, FieldId *field_id)
Resolve a user-facing field name once into its typed identity.
@ FIELD_CAPABILITY_GHOST_UPDATE
@ FIELD_SYNC_COMPONENT_STAGGERED
@ FIELD_SYNC_I_FACE
unsigned int capabilities
const char * FieldCanonicalName(FieldId field_id)
Return the canonical printable name for an ID.
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Resolve the existing DM and global/local vectors for one field.
@ FIELD_LAYOUT_I_FACE
@ FIELD_LAYOUT_COMPONENT_STAGGERED
const char * canonical_name
FieldSyncClass sync_class
PetscErrorCode FieldGetDescriptor(FieldId field_id, const FieldDescriptor **descriptor)
Return immutable metadata for a valid field identifier.
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_CSI
@ FIELD_ID_IAJ
@ FIELD_ID_UCAT
@ FIELD_ID_COORDINATES
@ FIELD_ID_NU_T
@ FIELD_ID_UCONT
@ FIELD_ID_CS
@ FIELD_ID_INVALID
@ FIELD_ID_P
@ FIELD_ID_CENTX
@ FIELD_ID_COUNT
Immutable metadata for one field identity.
Non-owning runtime objects resolved for one field and UserCtx.
Vec lUcat
Definition variables.h:1169
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParticleFieldCatalogMetadata()

static PetscErrorCode TestParticleFieldCatalogMetadata ( void  )
static

Verifies the separate DMSwarm field catalog and its Eulerian bridge metadata.

Definition at line 1011 of file test_setup_lifecycle.c.

1012{
1014 const ParticleFieldDescriptor *descriptor = NULL;
1015 PetscErrorCode unknown_name_ierr;
1016
1017 PetscFunctionBeginUser;
1018 for (PetscInt raw_id = 0; raw_id < PARTICLE_FIELD_ID_COUNT; ++raw_id) {
1019 PetscCall(ParticleFieldGetDescriptor((ParticleFieldId)raw_id, &descriptor));
1020 PetscCall(PicurvAssertIntEqual(raw_id, (PetscInt)descriptor->id,
1021 "particle catalog entry should retain its declared ID"));
1022 PetscCall(PicurvAssertBool((PetscBool)(descriptor->canonical_name != NULL &&
1023 descriptor->canonical_name[0] != '\0'),
1024 "every particle field should have a canonical DMSwarm name"));
1025 PetscCall(PicurvAssertBool((PetscBool)(descriptor->components == 1 ||
1026 descriptor->components == 3),
1027 "persistent particle fields should declare one or three components"));
1028 PetscCall(ParticleFieldIdFromName(descriptor->canonical_name, &parsed_id));
1029 PetscCall(PicurvAssertIntEqual(raw_id, (PetscInt)parsed_id,
1030 "canonical particle field names should round-trip to their IDs"));
1031 PetscCall(PicurvAssertBool((PetscBool)(strcmp(ParticleFieldName((ParticleFieldId)raw_id),
1032 descriptor->canonical_name) == 0),
1033 "ParticleFieldName should return catalog-owned PETSc text"));
1034 }
1035
1036 PetscCall(ParticleFieldIdFromName("particlevelocity", &parsed_id));
1038 "particle velocity alias should resolve case-insensitively"));
1039 PetscCall(ParticleFieldIdFromName("Migration Status", &parsed_id));
1041 "migration-status output alias should resolve to the PETSc field"));
1042
1043 PetscCall(ParticleFieldGetDescriptor(PARTICLE_FIELD_ID_PSI, &descriptor));
1044 PetscCall(PicurvAssertBool((PetscBool)((descriptor->capabilities &
1046 "Psi should advertise its active particle-to-Eulerian scatter"));
1048 "particle Psi should target Eulerian Psi"));
1049 PetscCall(ParticleFieldGetDescriptor(PARTICLE_FIELD_ID_PID, &descriptor));
1051 "particle IDs should be marked as PETSc-managed"));
1052 PetscCall(PicurvAssertIntEqual(PETSC_INT64, descriptor->data_type,
1053 "particle IDs should retain 64-bit storage metadata"));
1054
1055 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
1056 unknown_name_ierr = ParticleFieldIdFromName("NotARegisteredParticleField", &parsed_id);
1057 PetscCall(PetscPopErrorHandler());
1058 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_UNKNOWN_TYPE, unknown_name_ierr,
1059 "unknown particle names should fail at the text-ingress boundary"));
1061 "failed particle name resolution should return the invalid ID"));
1062 PetscFunctionReturn(0);
1063}
@ FIELD_ID_PSI
ParticleFieldId
Compile-time identity for a persistent solver-particle field.
@ PARTICLE_FIELD_ID_LOCATION_STATUS
@ PARTICLE_FIELD_ID_PID
@ PARTICLE_FIELD_ID_COUNT
@ PARTICLE_FIELD_ID_INVALID
@ PARTICLE_FIELD_ID_VELOCITY
ParticleFieldRegistration registration
PetscErrorCode ParticleFieldIdFromName(const char *field_name, ParticleFieldId *field_id)
Resolve a canonical name or registered alias at a text-ingress boundary.
@ PARTICLE_FIELD_CAPABILITY_EULERIAN_SCATTER
@ PARTICLE_FIELD_REGISTRATION_PETSC
PetscErrorCode ParticleFieldGetDescriptor(ParticleFieldId field_id, const ParticleFieldDescriptor **descriptor)
Return immutable metadata for a valid particle field ID.
Immutable metadata for one persistent particle field.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestFieldCatalogTypedGhostUpdates()

static PetscErrorCode TestFieldCatalogTypedGhostUpdates ( void  )
static

Verifies typed ghost updates preserve scalar, vector, face, and staggered behavior.

Definition at line 1068 of file test_setup_lifecycle.c.

1069{
1070 SimCtx *simCtx = NULL;
1071 UserCtx *user = NULL;
1072
1073 PetscFunctionBeginUser;
1074 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1075
1076 PetscCall(VecSet(user->P, 4.25));
1077 PetscCall(VecSet(user->lP, -1.0));
1078 PetscCall(UpdateLocalGhosts(user, FIELD_ID_P));
1079 PetscCall(PicurvAssertVecConstant(user->lP, 4.25, 1.0e-12,
1080 "typed scalar ghost update should scatter P"));
1081
1082 PetscCall(VecSet(user->Ucat, 7.5));
1083 PetscCall(VecSet(user->lUcat, -1.0));
1084 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCAT));
1085 PetscCall(PicurvAssertVecConstant(user->lUcat, 7.5, 1.0e-12,
1086 "typed cell-vector ghost update should scatter Ucat"));
1087
1088 PetscCall(VecSet(user->IAj, 2.0));
1089 PetscCall(VecSet(user->lIAj, -1.0));
1090 PetscCall(UpdateLocalGhosts(user, FIELD_ID_IAJ));
1091 PetscCall(PicurvAssertVecConstant(user->lIAj, 2.0, 1.0e-12,
1092 "typed scalar face-field ghost update should scatter IAj"));
1093
1094 PetscCall(VecSet(user->Ucont, 3.0));
1095 PetscCall(VecSet(user->lUcont, -1.0));
1096 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCONT));
1097 PetscCall(PicurvAssertVecConstant(user->lUcont, 3.0, 1.0e-12,
1098 "typed component-staggered ghost update should scatter Ucont"));
1099
1100 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1101 PetscFunctionReturn(0);
1102}
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:2675
PetscErrorCode PicurvAssertVecConstant(Vec vec, PetscScalar expected, PetscReal tol, const char *context)
Asserts that a PETSc vector is spatially constant within tolerance.
Vec lUcont
Definition variables.h:1169
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-setup PETSc test binary.

Definition at line 1107 of file test_setup_lifecycle.c.

1108{
1109 PetscErrorCode ierr;
1110 const PicurvTestCase cases[] = {
1111 {"setup-lifecycle-core-solver-setup", TestSetupLifecycleCoreSolverSetup},
1112 {"setup-lifecycle-particle-initialization", TestSetupLifecycleParticleInitialization},
1113 {"setup-lifecycle-scatter-metrics-step-zero", TestSetupLifecycleScatterMetricsAtStepZero},
1114 {"setup-lifecycle-random-generators-and-cleanup", TestSetupLifecycleRandomGeneratorsAndCleanup},
1115 {"setup-lifecycle-cleanup-across-initialization-states", TestSetupLifecycleCleanupAcrossInitializationStates},
1116 {"setup-rejects-unimplemented-feature-flags", TestSetupRejectsUnimplementedFeatureFlags},
1117 {"iem-constant-is-configurable", TestIEMConstantIsConfigurable},
1118 {"unsolved-flow-uses-one-grid-level", TestUnsolvedFlowUsesOneGridLevel},
1119 {"particle-count-must-fit-petscint", TestParticleCountMustFitPetscInt},
1120 {"setup-rejects-nonpositive-post-interval", TestSetupRejectsNonpositivePostInterval},
1121 {"configured-iem-updates-swarm", TestConfiguredIEMUpdatesSwarm},
1122 {"configured-particle-initial-value", TestConfiguredParticleInitialValue},
1123 {"iem-relaxes-toward-own-cell-mean", TestIEMRelaxesTowardOwnCellMean},
1124 {"postprocessor-loads-saved-particle-averages", TestPostprocessorLoadsSavedParticleAverages},
1125 {"shared-runtime-fixture-contracts", TestSharedRuntimeFixtureContracts},
1126 {"field-catalog-metadata-and-views", TestFieldCatalogMetadataAndViews},
1127 {"particle-field-catalog-metadata", TestParticleFieldCatalogMetadata},
1128 {"field-catalog-typed-ghost-updates", TestFieldCatalogTypedGhostUpdates},
1129 };
1130
1131 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv setup lifecycle tests");
1132 if (ierr) {
1133 return (int)ierr;
1134 }
1135
1136 ierr = PicurvRunTests("unit-setup", cases, sizeof(cases) / sizeof(cases[0]));
1137 if (ierr) {
1138 PetscFinalize();
1139 return (int)ierr;
1140 }
1141
1142 ierr = PetscFinalize();
1143 return (int)ierr;
1144}
static PetscErrorCode TestParticleFieldCatalogMetadata(void)
Verifies the separate DMSwarm field catalog and its Eulerian bridge metadata.
static PetscErrorCode TestConfiguredIEMUpdatesSwarm(void)
Checks configured IEM relaxation through the production swarm update.
static PetscErrorCode TestSetupRejectsNonpositivePostInterval(void)
Ensures setup propagates invalid post intervals before either executable can loop.
static PetscErrorCode TestUnsolvedFlowUsesOneGridLevel(void)
Ensures a run that solves no pressure builds one grid level whatever -mg_level asks,...
static PetscErrorCode TestIEMRelaxesTowardOwnCellMean(void)
Checks that IEM relaxes each particle toward its own cell's scattered mean.
static PetscErrorCode TestIEMConstantIsConfigurable(void)
Tests that the IEM mixing constant defaults to 2.0, follows -iem_constant, accepts zero (no micromixi...
static PetscErrorCode TestParticleCountMustFitPetscInt(void)
Ensures setup refuses a particle count whose widest swarm field PetscInt cannot index.
static PetscErrorCode TestSetupLifecycleScatterMetricsAtStepZero(void)
Tests that step-zero scalar verification emits scatter_metrics.csv during initialized setup.
static PetscErrorCode TestFieldCatalogMetadataAndViews(void)
Verifies catalog completeness, stable name resolution, and runtime view binding.
static PetscErrorCode TestSetupLifecycleRandomGeneratorsAndCleanup(void)
Tests standalone RNG initialization helpers and minimal-context cleanup.
static PetscErrorCode TestPostprocessorLoadsSavedParticleAverages(void)
Checks that post-processing loads the particle averages a checkpoint holds.
static PetscErrorCode TestSetupLifecycleParticleInitialization(void)
Tests particle-swarm initialization and deterministic settlement on a tiny fully initialized case.
static PetscErrorCode TestSetupLifecycleCoreSolverSetup(void)
Tests the core setup lifecycle through environment, grid, BC, rank-info, and Eulerian-state initializ...
static PetscErrorCode TestSharedRuntimeFixtureContracts(void)
Tests that the shared richer runtime fixture mirrors normalized production setup contracts.
static PetscErrorCode TestSetupRejectsUnimplementedFeatureFlags(void)
Tests that setup refuses every flag whose feature is planned but not implemented.
static PetscErrorCode TestConfiguredParticleInitialValue(void)
Checks a configured particle initial value through the production setup path.
static PetscErrorCode TestFieldCatalogTypedGhostUpdates(void)
Verifies typed ghost updates preserve scalar, vector, face, and staggered behavior.
static PetscErrorCode TestSetupLifecycleCleanupAcrossInitializationStates(void)
Tests cleanup after partial and fuller setup states without requiring unsupported double-finalization...
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: