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

C unit tests for I/O helpers, parsers, and startup-banner output. More...

#include "test_support.h"
#include "checksum.h"
#include "io.h"
#include "statistics_accumulator.h"
#include "statistics_window.h"
#include "field_catalog.h"
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
Include dependency graph for test_io.c:

Go to the source code of this file.

Functions

static PetscErrorCode TestShouldWriteDataOutput (void)
 Tests cadence-based Eulerian output triggering.
 
static PetscErrorCode TestVerifyPathExistence (void)
 Tests filesystem existence checks for files and directories.
 
static PetscErrorCode TestWriteAndReadSimulationFields (void)
 Tests writing and reloading core Eulerian field vectors.
 
static PicurvWindowDefinition StatisticsFixtureDefinition (void)
 Builds the statistics fixture: one Ucat/P window with a second moment.
 
static PetscErrorCode AttachStatisticsFixture (SimCtx *simCtx, UserCtx *user, PicurvWindow *window, PicurvWindowStorage *storage, const PicurvWindowDefinition *definition)
 Attaches one accumulating window to a fixture context and primes it with samples.
 
static PetscErrorCode DetachStatisticsFixture (SimCtx *simCtx, UserCtx *user, PicurvWindowStorage *storage)
 Detaches the statistics fixture without disturbing the shared teardown.
 
static PetscErrorCode WriteCompletedStatisticsWindow (SimCtx *simCtx, UserCtx *user, PicurvWindow *window, PicurvWindowStorage *storage, const PicurvWindowDefinition *definition)
 Rewrites the bundle holding a window that closed well before the checkpoint time.
 
static PetscErrorCode TestCheckpointStatisticsRoundTrip (void)
 Verifies accumulated statistics survive a checkpoint round trip unchanged.
 
static PetscErrorCode TestCheckpointStatisticsContinuationGuards (void)
 Verifies continuation refuses every state that would corrupt an average.
 
static PetscErrorCode TestCheckpointStatisticsPayloadIsValidated (void)
 A damaged statistics payload must fail bundle validation, not load silently.
 
static PetscErrorCode TestCheckpointStatisticsAbsentWhenDisabled (void)
 A run without statistics writes no statistics subtree and refuses to fake one.
 
static PetscErrorCode TestCheckpointSameStepRewriteIsRejected (void)
 Verifies a committed checkpoint step is rewritten neither silently nor inconsistently.
 
static PetscErrorCode TestCheckpointSHA256KnownVector (void)
 Verifies the dependency-free SHA-256 implementation against a standard vector.
 
static PetscErrorCode TestParsePostProcessingSettings (void)
 Tests parsing of post-processing control settings from a file.
 
static PetscErrorCode TestTrimWhitespace (void)
 Tests trimming of leading and trailing whitespace.
 
static PetscErrorCode TestBoundaryConditionStringParsers (void)
 Tests boundary-condition string parsers for face, type, and handler names.
 
static PetscErrorCode TestValidateBCHandlerForBCType (void)
 Tests validation of boundary-type and handler compatibility.
 
static PetscErrorCode TestParseScalingInformation (void)
 Tests scaling-reference parsing and derived pressure scaling.
 
static PetscErrorCode CaptureBannerOutput (SimCtx *simCtx, char *captured, size_t captured_len)
 Captures the startup banner into a temporary file-backed buffer.
 
static PetscErrorCode AssertCapturedContains (const char *captured, const char *needle, const char *message)
 Asserts that captured banner output contains one expected substring.
 
static PetscErrorCode AssertCapturedOmits (const char *captured, const char *needle, const char *message)
 Asserts that captured banner output omits one forbidden substring.
 
static PetscErrorCode TestDisplayBannerReportsStatisticsCadence (void)
 Tests that the startup banner reports statistics monitoring in every state.
 
static PetscErrorCode TestDisplayBannerTracksConditionalStartupFields (void)
 Tests conditional startup-banner fields across particle and analytical cases.
 
int main (int argc, char **argv)
 Runs the unit-io PETSc test binary.
 

Detailed Description

C unit tests for I/O helpers, parsers, and startup-banner output.

Definition in file test_io.c.

Function Documentation

◆ TestShouldWriteDataOutput()

static PetscErrorCode TestShouldWriteDataOutput ( void  )
static

Tests cadence-based Eulerian output triggering.

Definition at line 23 of file test_io.c.

24{
25 SimCtx simCtx;
26
27 PetscFunctionBeginUser;
28 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
29 simCtx.tiout = 5;
30
31 PetscCall(PicurvAssertBool((PetscBool)!ShouldWriteDataOutput(NULL, 5), "NULL SimCtx should never request output"));
32 PetscCall(PicurvAssertBool((PetscBool)!ShouldWriteDataOutput(&simCtx, 4), "non-cadence step should not trigger output"));
33 PetscCall(PicurvAssertBool(ShouldWriteDataOutput(&simCtx, 10), "cadence-aligned step should trigger output"));
34 PetscFunctionReturn(0);
35}
PetscBool ShouldWriteDataOutput(const SimCtx *simCtx, PetscInt completed_step)
Returns whether full field/restart output should be written for the.
Definition io.c:432
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
PetscInt tiout
Definition variables.h:707
The master context for the entire simulation.
Definition variables.h:695
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestVerifyPathExistence()

static PetscErrorCode TestVerifyPathExistence ( void  )
static

Tests filesystem existence checks for files and directories.

Definition at line 40 of file test_io.c.

41{
42 char tmpdir[PETSC_MAX_PATH_LEN];
43 char filepath[PETSC_MAX_PATH_LEN];
44 FILE *file = NULL;
45 PetscBool exists = PETSC_FALSE;
46
47 PetscFunctionBeginUser;
48 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
49 PetscCall(PetscSNPrintf(filepath, sizeof(filepath), "%s/sample.txt", tmpdir));
50
51 file = fopen(filepath, "w");
52 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to create temp file '%s'.", filepath);
53 fputs("picurv\n", file);
54 fclose(file);
55
56 PetscCall(VerifyPathExistence(tmpdir, PETSC_TRUE, PETSC_FALSE, "temp directory", &exists));
57 PetscCall(PicurvAssertBool(exists, "VerifyPathExistence should find the temp directory"));
58
59 PetscCall(VerifyPathExistence(filepath, PETSC_FALSE, PETSC_FALSE, "temp file", &exists));
60 PetscCall(PicurvAssertBool(exists, "VerifyPathExistence should find the temp file"));
61 PetscCall(PicurvRemoveTempDir(tmpdir));
62 PetscFunctionReturn(0);
63}
PetscErrorCode VerifyPathExistence(const char *path, PetscBool is_dir, PetscBool is_optional, const char *description, PetscBool *exists)
A parallel-safe helper to verify the existence of a generic file or directory path.
Definition io.c:1128
PetscErrorCode PicurvMakeTempDir(char *path, size_t path_len)
Creates a unique temporary directory for one test case.
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:

◆ TestWriteAndReadSimulationFields()

static PetscErrorCode TestWriteAndReadSimulationFields ( void  )
static

Tests writing and reloading core Eulerian field vectors.

Definition at line 68 of file test_io.c.

69{
70 SimCtx *simCtx = NULL;
71 UserCtx *user = NULL;
72 char tmpdir[PETSC_MAX_PATH_LEN];
73 char path[PETSC_MAX_PATH_LEN];
74 PetscBool exists = PETSC_FALSE;
75
76 PetscFunctionBeginUser;
77 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
78 tmpdir[0] = '\0';
79 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
80 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
81
82 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
83 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
84 PetscCall(VecSet(user->P, 4.5));
85 PetscCall(VecSet(user->Nvert, 0.0));
86 PetscCall(VecSet(user->Ucat, 2.0));
87 PetscCall(VecSet(user->Ucont, 3.0));
88 PetscCall(VecSet(user->Ucont_rm1, 1.25));
89 simCtx->ti = 0.35;
90 PetscCall(PicurvPopulateIdentityMetrics(user));
91
92 PetscCall(WriteCheckpointBundle(simCtx, "test"));
93 PetscCall(PetscSNPrintf(path, sizeof(path),
94 "%s/checkpoints/step_000000000001/checkpoint.meta", tmpdir));
95 PetscCall(PetscTestFile(path, 'r', &exists));
96 PetscCall(PicurvAssertBool(exists, "checkpoint coordinator should write checkpoint.meta"));
97 PetscCall(PetscSNPrintf(path, sizeof(path),
98 "%s/checkpoints/step_000000000001/COMMITTED", tmpdir));
99 PetscCall(PetscTestFile(path, 'r', &exists));
100 PetscCall(PicurvAssertBool(exists, "checkpoint coordinator should write COMMITTED last"));
101 PetscCall(PetscSNPrintf(path, sizeof(path),
102 "%s/checkpoints/step_000000000001/eulerian/block_0000/Ucat.dat", tmpdir));
103 PetscCall(PetscTestFile(path, 'r', &exists));
104 PetscCall(PicurvAssertBool(exists, "checkpoint should use catalogued canonical field names"));
105 PetscCall(VecZeroEntries(user->P));
106 PetscCall(VecZeroEntries(user->Ucat));
107 PetscCall(VecZeroEntries(user->Ucont));
108 PetscCall(VecZeroEntries(user->Ucont_rm1));
109 simCtx->ti = 0.0;
110
111 PetscCall(ReadSimulationFields(user, simCtx->step));
112 PetscCall(PicurvAssertVecConstant(user->P, 4.5, 1.0e-12, "ReadSimulationFields should restore P"));
113 PetscCall(PicurvAssertVecConstant(user->Ucat, 2.0, 1.0e-12, "ReadSimulationFields should restore Ucat"));
114 PetscCall(PicurvAssertVecConstant(user->Ucont, 3.0, 1.0e-12, "ReadSimulationFields should restore Ucont"));
115 PetscCall(PicurvAssertVecConstant(user->Ucont_rm1, 1.25, 1.0e-12,
116 "ReadSimulationFields should restore BDF2 history"));
117 PetscCall(PicurvAssertRealNear(0.35, simCtx->ti, 1.0e-12,
118 "checkpoint physical time should be authoritative"));
119
120 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
121 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
122 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
123 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
124 PetscFunctionReturn(0);
125}
PetscErrorCode ReadSimulationFields(UserCtx *user, PetscInt ti)
Reads binary field data for velocity, pressure, and other required vectors.
Definition io.c:1463
PetscErrorCode WriteCheckpointBundle(SimCtx *simCtx, const char *reason)
Write and atomically publish one complete checkpoint bundle.
Definition io.c:2530
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvAssertVecConstant(Vec vec, PetscScalar expected, PetscReal tol, const char *context)
Asserts that a PETSc vector is spatially constant within tolerance.
PetscErrorCode PicurvPopulateIdentityMetrics(UserCtx *user)
Populates identity metric vectors on the minimal grid fixture.
PetscMPIInt rank
Definition variables.h:698
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:717
Vec Ucont
Definition variables.h:939
Vec Ucat
Definition variables.h:939
Vec Ucont_rm1
Definition variables.h:947
PetscInt step
Definition variables.h:703
Vec Nvert
Definition variables.h:939
PetscReal ti
Definition variables.h:704
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:716
User-defined context containing data specific to a single computational grid level.
Definition variables.h:906
Here is the call graph for this function:
Here is the caller graph for this function:

◆ StatisticsFixtureDefinition()

static PicurvWindowDefinition StatisticsFixtureDefinition ( void  )
static

Builds the statistics fixture: one Ucat/P window with a second moment.

Definition at line 128 of file test_io.c.

129{
131
132 memset(&d, 0, sizeof(d));
133 strncpy(d.name, "production", PICURV_WINDOW_NAME_LENGTH - 1);
136 d.step_cadence = 1;
137 d.field_count = 2;
138 d.fields[0].field_id = FIELD_ID_UCAT; d.fields[0].want_second = PETSC_TRUE;
139 d.fields[1].field_id = FIELD_ID_P; d.fields[1].want_second = PETSC_TRUE;
140 return d;
141}
@ FIELD_ID_UCAT
@ FIELD_ID_P
PicurvWindowFieldRequest fields[16]
PicurvCadenceKind cadence_kind
PetscInt step_cadence
Used when cadence_kind is step; must be positive.
#define PICURV_WINDOW_NAME_LENGTH
Maximum stored length of a window name, including the terminator.
PetscBool want_second
Also keep the centered second moment.
PetscInt field_id
Catalogued Eulerian field identity.
@ PICURV_WEIGHTING_SAMPLE
Equal weight per accepted state.
@ PICURV_CADENCE_STEP
Every n completed steps from activation.
The scientifically immutable definition of one window.
Here is the caller graph for this function:

◆ AttachStatisticsFixture()

static PetscErrorCode AttachStatisticsFixture ( SimCtx simCtx,
UserCtx user,
PicurvWindow window,
PicurvWindowStorage storage,
const PicurvWindowDefinition definition 
)
static

Attaches one accumulating window to a fixture context and primes it with samples.

Definition at line 144 of file test_io.c.

147{
148 PetscFunctionBeginUser;
149 PetscCall(PicurvWindowInit(window, definition));
150 PetscCall(PicurvWindowStorageCreate(user, definition, storage));
151 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
152 simCtx->fieldStatisticsWindowCount = 1;
153 simCtx->fieldStatisticsWindows = window;
154 user->fieldStatisticsStorage = storage;
155 PetscFunctionReturn(0);
156}
PetscErrorCode PicurvWindowStorageCreate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage)
Allocates the accumulator state one window owns on one block.
PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
Validates a definition and initializes a window to the pending state.
PetscInt fieldStatisticsWindowCount
Definition variables.h:770
PetscBool fieldStatisticsEnabled
Definition variables.h:769
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:771
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:962
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DetachStatisticsFixture()

static PetscErrorCode DetachStatisticsFixture ( SimCtx simCtx,
UserCtx user,
PicurvWindowStorage storage 
)
static

Detaches the statistics fixture without disturbing the shared teardown.

Definition at line 159 of file test_io.c.

161{
162 PetscFunctionBeginUser;
163 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
164 simCtx->fieldStatisticsWindowCount = 0;
165 simCtx->fieldStatisticsWindows = NULL;
166 user->fieldStatisticsStorage = NULL;
167 PetscCall(PicurvWindowStorageDestroy(storage));
168 PetscFunctionReturn(0);
169}
PetscErrorCode PicurvWindowStorageDestroy(PicurvWindowStorage *storage)
Releases accumulator state previously created for one window.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteCompletedStatisticsWindow()

static PetscErrorCode WriteCompletedStatisticsWindow ( SimCtx simCtx,
UserCtx user,
PicurvWindow window,
PicurvWindowStorage storage,
const PicurvWindowDefinition definition 
)
static

Rewrites the bundle holding a window that closed well before the checkpoint time.

Reproduces the shape a real run reaches when a bounded window finished and the simulation kept going: the saved state is complete, and its end sits behind the checkpoint by far more than one step.

Definition at line 178 of file test_io.c.

182{
183 PicurvWindowDefinition bounded = *definition;
184 PetscBool accepted = PETSC_FALSE;
185 PetscReal weight = 0.0;
186 char step_directory[PETSC_MAX_PATH_LEN];
187
188 PetscFunctionBeginUser;
189 bounded.bounded = PETSC_TRUE;
190 bounded.end_time = 1.0;
191 PetscCall(PicurvWindowInit(window, &bounded));
192 PetscCall(PicurvWindowOfferState(window, 0, 0.0, &accepted, &weight));
193 PetscCall(PicurvWindowOfferState(window, 1, 1.0, &accepted, &weight));
194 if (accepted) PetscCall(PicurvWindowAccumulate(user, &bounded, storage, weight));
195 PetscCall(PicurvAssertBool((PetscBool)(window->state == PICURV_WINDOW_COMPLETE),
196 "the fixture window reaches its bounded end"));
197
198 /* The run continued well past the window's end before this checkpoint. */
199 simCtx->ti = 5.0;
200 PetscCall(PetscSNPrintf(step_directory, sizeof(step_directory),
201 "%s/checkpoints/step_000000000001", simCtx->output_dir));
202 if (simCtx->rank == 0) PetscCall(PetscRMTree(step_directory));
203 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
204 PetscCall(WriteCheckpointBundle(simCtx, "test"));
205 PetscFunctionReturn(0);
206}
PetscErrorCode PicurvWindowAccumulate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage, PetscReal weight)
Applies one accepted completed state to a window's accumulators.
PicurvWindowState state
PetscReal end_time
Requested end; ignored when bounded is false.
@ PICURV_WINDOW_COMPLETE
Bounded end reached; accepts nothing further.
PetscErrorCode PicurvWindowOfferState(PicurvWindow *window, PetscInt step, PetscReal time, PetscBool *accepted, PetscReal *weight)
Offers one completed state to a window and reports the decision.
PetscBool bounded
False for an open-ended window.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestCheckpointStatisticsRoundTrip()

static PetscErrorCode TestCheckpointStatisticsRoundTrip ( void  )
static

Verifies accumulated statistics survive a checkpoint round trip unchanged.

Both halves of the state matter and are checked separately: the per-point accumulator vectors, and the window's scalar bookkeeping. Restoring only the vectors would silently resume with a broken schedule, and restoring only the scalars would report a sample count the fields do not support.

Definition at line 216 of file test_io.c.

217{
218 SimCtx *simCtx = NULL;
219 UserCtx *user = NULL;
220 PicurvWindow window;
221 PicurvWindowStorage storage;
223 char tmpdir[PETSC_MAX_PATH_LEN];
224 char path[PETSC_MAX_PATH_LEN];
225 PetscBool exists = PETSC_FALSE;
226 PetscInt payload_count = 0;
227 Vec *reference = NULL;
228
229 PetscFunctionBeginUser;
230 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
231 tmpdir[0] = '\0';
232 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
233 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
234 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
235 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
236 PetscCall(PicurvPopulateIdentityMetrics(user));
237 PetscCall(VecSet(user->Nvert, 0.0));
238 PetscCall(AttachStatisticsFixture(simCtx, user, &window, &storage, &definition));
239
240 /* Three accepted states at unit weight: P takes 1, 2 and 6, so its per-point
241 * mean is 3 and its centered second moment is 14. */
242 {
243 const PetscReal scalars[3] = {1.0, 2.0, 6.0};
244
245 for (PetscInt s = 0; s < 3; ++s) {
246 PetscBool accepted = PETSC_FALSE;
247 PetscReal weight = 0.0;
248
249 PetscCall(VecSet(user->P, scalars[s]));
250 PetscCall(VecSet(user->Ucat, scalars[s]));
251 PetscCall(PicurvWindowOfferState(&window, s, (PetscReal)s, &accepted, &weight));
252 if (accepted) PetscCall(PicurvWindowAccumulate(user, &definition, &storage, weight));
253 }
254 }
255 PetscCall(PicurvAssertIntEqual(2, window.sample_count, "the anchoring state is not itself a sample"));
256
257 PetscCall(WriteCheckpointBundle(simCtx, "test"));
258 PetscCall(PetscSNPrintf(path, sizeof(path),
259 "%s/checkpoints/step_000000000001/statistics/window_0000/block_0000/P_mean.dat",
260 tmpdir));
261 PetscCall(PetscTestFile(path, 'r', &exists));
262 PetscCall(PicurvAssertBool(exists, "statistics payloads use their enumerated names"));
263 PetscCall(PetscSNPrintf(path, sizeof(path),
264 "%s/checkpoints/step_000000000001/statistics/window_0000/block_0000/Ucat_m2.dat",
265 tmpdir));
266 PetscCall(PetscTestFile(path, 'r', &exists));
267 PetscCall(PicurvAssertBool(exists, "the symmetric product is one payload, not six"));
268
269 /* Keep a reference copy of every payload, then discard the in-memory state so a
270 * restore that did nothing cannot pass. */
271 PetscCall(PicurvWindowStoragePayloadCount(&storage, &payload_count));
272 PetscCall(PetscCalloc1((size_t)payload_count, &reference));
273 for (PetscInt index = 0; index < payload_count; ++index) {
275
276 PetscCall(PicurvWindowStoragePayload(user, &definition, &storage, index, &payload));
277 PetscCall(VecDuplicate(payload.vec, &reference[index]));
278 PetscCall(VecCopy(payload.vec, reference[index]));
279 PetscCall(VecZeroEntries(payload.vec));
280 }
281 PetscCall(PicurvWindowInit(&window, &definition));
282 PetscCall(PicurvAssertIntEqual(0, window.sample_count, "the fixture is reset before restoring"));
283
284 simCtx->fieldStatisticsContinue = PETSC_TRUE;
285 PetscCall(RestoreFieldStatisticsState(simCtx, simCtx->step));
286
287 PetscCall(PicurvAssertIntEqual(2, window.sample_count, "the sample count is restored"));
288 PetscCall(PicurvAssertRealNear(2.0, window.total_weight, 1.0e-12, "the total weight is restored"));
289 PetscCall(PicurvAssertRealNear(2.0, window.represented_time, 1.0e-12,
290 "the represented time is restored"));
291 PetscCall(PicurvAssertRealNear(2.0, window.last_accepted_time, 1.0e-12,
292 "the quadrature origin is restored"));
293 PetscCall(PicurvAssertIntEqual(0, window.activation_step, "the schedule anchor is restored"));
294 PetscCall(PicurvAssertIntEqual(2, window.last_event_step,
295 "the duplicate-event guard survives the restart"));
296 PetscCall(PicurvAssertIntEqual(1, window.restart_count, "the restart lineage advances on resume"));
297 PetscCall(PicurvAssertBool((PetscBool)(window.state == PICURV_WINDOW_ACTIVE),
298 "an open window resumes active"));
299
300 /* Every payload must come back bit for bit. The binary format stores IEEE
301 * doubles and the natural ordering is decomposition independent, so anything
302 * short of an exact match is a defect rather than rounding. */
303 for (PetscInt index = 0; index < payload_count; ++index) {
305 PetscReal difference = 0.0;
306 char context[192];
307
308 PetscCall(PicurvWindowStoragePayload(user, &definition, &storage, index, &payload));
309 PetscCall(VecAXPY(reference[index], -1.0, payload.vec));
310 PetscCall(VecNorm(reference[index], NORM_INFINITY, &difference));
311 PetscCall(PetscSNPrintf(context, sizeof(context),
312 "payload '%s' is restored bit for bit", payload.name));
313 PetscCall(PicurvAssertBool((PetscBool)(difference == 0.0), context));
314 PetscCall(VecDestroy(&reference[index]));
315 }
316 PetscCall(PetscFree(reference));
317
318 /* Spot-check one interior point against the analytically known value, so the
319 * comparison above cannot pass by restoring two identically wrong vectors. */
320 {
321 PetscReal ***mean = NULL;
322
323 PetscCall(DMDAVecGetArrayRead(user->da, storage.mean[1], &mean));
324 if (user->info.xs <= 2 && 2 < user->info.xs + user->info.xm &&
325 user->info.ys <= 2 && 2 < user->info.ys + user->info.ym &&
326 user->info.zs <= 2 && 2 < user->info.zs + user->info.zm) {
327 PetscCall(PicurvAssertRealNear(4.0, mean[2][2][2], 1.0e-12,
328 "the restored scalar mean holds the accumulated value"));
329 }
330 PetscCall(DMDAVecRestoreArrayRead(user->da, storage.mean[1], &mean));
331 }
332
333 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
334 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
335 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
336 PetscCall(DetachStatisticsFixture(simCtx, user, &storage));
337 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
338 PetscFunctionReturn(0);
339}
PetscErrorCode RestoreFieldStatisticsState(SimCtx *simCtx, PetscInt ti)
Restores field-statistics window state and accumulators from a checkpoint.
Definition io.c:1667
Vec * mean
One per field, matching that field's layout.
Vec vec
Borrowed accumulator vector; never owned by the caller.
PetscErrorCode PicurvWindowStoragePayload(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt index, PicurvStatisticsPayload *payload)
Resolves one enumerated payload of a window's storage.
char name[96]
File basename, no extension.
PetscErrorCode PicurvWindowStoragePayloadCount(const PicurvWindowStorage *storage, PetscInt *count)
Reports how many checkpointable vectors one window's storage holds.
One checkpointable accumulator vector, resolved by enumeration index.
Independent accumulator state for one window on one block.
PetscInt last_event_step
Guards against a step being offered twice.
PetscInt sample_count
PetscReal last_accepted_time
Right edge of the last represented interval.
PetscInt restart_count
Restart segments this state descends from.
PetscReal total_weight
@ PICURV_WINDOW_ACTIVE
Accepting due states.
PetscInt activation_step
Step at which the window became active.
PetscReal represented_time
Physical time the window covers.
Runtime state of one window.
static PetscErrorCode DetachStatisticsFixture(SimCtx *simCtx, UserCtx *user, PicurvWindowStorage *storage)
Detaches the statistics fixture without disturbing the shared teardown.
Definition test_io.c:159
static PicurvWindowDefinition StatisticsFixtureDefinition(void)
Builds the statistics fixture: one Ucat/P window with a second moment.
Definition test_io.c:128
static PetscErrorCode AttachStatisticsFixture(SimCtx *simCtx, UserCtx *user, PicurvWindow *window, PicurvWindowStorage *storage, const PicurvWindowDefinition *definition)
Attaches one accumulating window to a fixture context and primes it with samples.
Definition test_io.c:144
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
DMDALocalInfo info
Definition variables.h:918
PetscBool fieldStatisticsContinue
Definition variables.h:776
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestCheckpointStatisticsContinuationGuards()

static PetscErrorCode TestCheckpointStatisticsContinuationGuards ( void  )
static

Verifies continuation refuses every state that would corrupt an average.

A silent reset is the failure mode this guards: resuming from zero, or merging samples taken under a different definition, both produce a window whose reported sample count no longer describes the numbers it carries.

Definition at line 348 of file test_io.c.

349{
350 SimCtx *simCtx = NULL;
351 UserCtx *user = NULL;
352 PicurvWindow window;
353 PicurvWindowStorage storage;
356 char tmpdir[PETSC_MAX_PATH_LEN];
357 PetscErrorCode bad = 0;
358
359 PetscFunctionBeginUser;
360 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
361 tmpdir[0] = '\0';
362 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
363 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
364 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
365 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
366 PetscCall(PicurvPopulateIdentityMetrics(user));
367 PetscCall(VecSet(user->Nvert, 0.0));
368 PetscCall(AttachStatisticsFixture(simCtx, user, &window, &storage, &definition));
369 {
370 PetscBool accepted = PETSC_FALSE;
371 PetscReal weight = 0.0;
372
373 PetscCall(PicurvWindowOfferState(&window, 0, 0.0, &accepted, &weight));
374 PetscCall(PicurvWindowOfferState(&window, 1, 1.0, &accepted, &weight));
375 if (accepted) PetscCall(PicurvWindowAccumulate(user, &definition, &storage, weight));
376 }
377 PetscCall(WriteCheckpointBundle(simCtx, "test"));
378
379 /* A hashed property changed: the saved samples describe a different average. */
380 changed = definition;
382 PetscCall(PicurvWindowInit(&window, &changed));
383 simCtx->fieldStatisticsContinue = PETSC_TRUE;
384 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
385 bad = RestoreFieldStatisticsState(simCtx, simCtx->step);
386 PetscCall(PetscPopErrorHandler());
387 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_INCOMP, bad,
388 "a changed definition is refused rather than merged"));
389
390 /* A window renamed under the same index is a different window. */
391 changed = definition;
392 strncpy(changed.name, "other", PICURV_WINDOW_NAME_LENGTH - 1);
393 PetscCall(PicurvWindowInit(&window, &changed));
394 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
395 bad = RestoreFieldStatisticsState(simCtx, simCtx->step);
396 PetscCall(PetscPopErrorHandler());
397 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_INCOMP, bad, "a renamed window is refused"));
398
399 /* Shortening a window would discard represented time it already claims. */
400 changed = definition;
401 changed.bounded = PETSC_TRUE;
402 changed.end_time = 0.5;
403 PetscCall(PicurvWindowInit(&window, &changed));
404 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
405 bad = RestoreFieldStatisticsState(simCtx, simCtx->step);
406 PetscCall(PetscPopErrorHandler());
407 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_INCOMP, bad, "a shortened window is refused"));
408
409 /* Extending it forward is permitted, because end_time is outside the hash. The
410 * saved window is still open here, so there is no former end to leave a gap
411 * after and the extension is accepted. */
412 changed = definition;
413 changed.bounded = PETSC_TRUE;
414 changed.end_time = 40.0;
415 PetscCall(PicurvWindowInit(&window, &changed));
416 PetscCall(RestoreFieldStatisticsState(simCtx, simCtx->step));
417 PetscCall(PicurvAssertIntEqual(1, window.sample_count, "an extended window keeps its samples"));
418 PetscCall(PicurvAssertBool((PetscBool)(window.state == PICURV_WINDOW_ACTIVE),
419 "an extended window resumes active"));
420
421 /* Reopening a window that already closed, across time it never sampled, would
422 * weight that gap into the first new interval. */
423 simCtx->dt = 0.1;
424 PetscCall(WriteCompletedStatisticsWindow(simCtx, user, &window, &storage, &definition));
425 changed = definition;
426 changed.bounded = PETSC_TRUE;
427 changed.end_time = 40.0;
428 PetscCall(PicurvWindowInit(&window, &changed));
429 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
430 bad = RestoreFieldStatisticsState(simCtx, simCtx->step);
431 PetscCall(PetscPopErrorHandler());
432 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_INCOMP, bad,
433 "reopening a closed window across an unsampled gap is refused"));
434
435 /* Without an explicit request, a restart starts from zero and says so. */
436 PetscCall(PicurvWindowInit(&window, &definition));
437 simCtx->fieldStatisticsContinue = PETSC_FALSE;
438 PetscCall(RestoreFieldStatisticsState(simCtx, simCtx->step));
439 PetscCall(PicurvAssertIntEqual(0, window.sample_count,
440 "statistics start fresh when continuation is not requested"));
441
442 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
443 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
444 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
445 PetscCall(DetachStatisticsFixture(simCtx, user, &storage));
446 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
447 PetscFunctionReturn(0);
448}
@ PICURV_WEIGHTING_PHYSICAL_TIME
Weight is the represented interval.
static PetscErrorCode WriteCompletedStatisticsWindow(SimCtx *simCtx, UserCtx *user, PicurvWindow *window, PicurvWindowStorage *storage, const PicurvWindowDefinition *definition)
Rewrites the bundle holding a window that closed well before the checkpoint time.
Definition test_io.c:178
PetscReal dt
Definition variables.h:710
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestCheckpointStatisticsPayloadIsValidated()

static PetscErrorCode TestCheckpointStatisticsPayloadIsValidated ( void  )
static

A damaged statistics payload must fail bundle validation, not load silently.

Statistics payloads are validated because they enter the manifest inventory the existing validator already walks. That is an easy property to believe and an easy one to lose, so it is checked by damaging a payload rather than by inspection.

Definition at line 457 of file test_io.c.

458{
459 SimCtx *simCtx = NULL;
460 UserCtx *user = NULL;
461 PicurvWindow window;
462 PicurvWindowStorage storage;
464 char tmpdir[PETSC_MAX_PATH_LEN];
465 char payload_path[PETSC_MAX_PATH_LEN];
466 PetscErrorCode bad = 0;
467
468 PetscFunctionBeginUser;
469 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
470 tmpdir[0] = '\0';
471 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
472 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
473 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
474 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
475 PetscCall(PicurvPopulateIdentityMetrics(user));
476 PetscCall(VecSet(user->Nvert, 0.0));
477 PetscCall(AttachStatisticsFixture(simCtx, user, &window, &storage, &definition));
478 {
479 PetscBool accepted = PETSC_FALSE;
480 PetscReal weight = 0.0;
481
482 PetscCall(PicurvWindowOfferState(&window, 0, 0.0, &accepted, &weight));
483 PetscCall(PicurvWindowOfferState(&window, 1, 1.0, &accepted, &weight));
484 if (accepted) PetscCall(PicurvWindowAccumulate(user, &definition, &storage, weight));
485 }
486 PetscCall(WriteCheckpointBundle(simCtx, "test"));
487
488 /* Truncating one payload leaves the manifest and its commit marker intact, so
489 * only the inventory's recorded byte size can catch it. */
490 PetscCall(PetscSNPrintf(payload_path, sizeof(payload_path),
491 "%s/checkpoints/step_000000000001/statistics/window_0000/block_0000/P_mean.dat",
492 tmpdir));
493 if (simCtx->rank == 0) {
494 FILE *damaged = fopen(payload_path, "w");
495
496 PetscCheck(damaged != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
497 "Unable to truncate '%s'.", payload_path);
498 PetscCheck(fclose(damaged) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
499 "Unable to close '%s'.", payload_path);
500 }
501 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
502
503 simCtx->fieldStatisticsContinue = PETSC_TRUE;
504 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
505 bad = RestoreFieldStatisticsState(simCtx, simCtx->step);
506 PetscCall(PetscPopErrorHandler());
507 PetscCall(PicurvAssertIntEqual(PETSC_ERR_FILE_UNEXPECTED, bad,
508 "a truncated statistics payload fails bundle validation"));
509
510 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
511 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
512 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
513 PetscCall(DetachStatisticsFixture(simCtx, user, &storage));
514 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
515 PetscFunctionReturn(0);
516}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestCheckpointStatisticsAbsentWhenDisabled()

static PetscErrorCode TestCheckpointStatisticsAbsentWhenDisabled ( void  )
static

A run without statistics writes no statistics subtree and refuses to fake one.

Definition at line 519 of file test_io.c.

520{
521 SimCtx *simCtx = NULL;
522 UserCtx *user = NULL;
523 PicurvWindow window;
524 PicurvWindowStorage storage;
526 char tmpdir[PETSC_MAX_PATH_LEN];
527 char path[PETSC_MAX_PATH_LEN];
528 PetscBool exists = PETSC_TRUE;
529 PetscErrorCode bad = 0;
530
531 PetscFunctionBeginUser;
532 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
533 tmpdir[0] = '\0';
534 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
535 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
536 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
537 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
538 PetscCall(PicurvPopulateIdentityMetrics(user));
539
540 PetscCall(WriteCheckpointBundle(simCtx, "test"));
541 PetscCall(PetscSNPrintf(path, sizeof(path), "%s/checkpoints/step_000000000001/statistics", tmpdir));
542 PetscCall(PetscTestDirectory(path, 'r', &exists));
543 PetscCall(PicurvAssertBool((PetscBool)!exists,
544 "a run without statistics writes no statistics subtree"));
545
546 /* Continuing from that bundle must fail loudly rather than resume from zero. */
547 PetscCall(AttachStatisticsFixture(simCtx, user, &window, &storage, &definition));
548 simCtx->fieldStatisticsContinue = PETSC_TRUE;
549 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
550 bad = RestoreFieldStatisticsState(simCtx, simCtx->step);
551 PetscCall(PetscPopErrorHandler());
552 PetscCall(PicurvAssertIntEqual(PETSC_ERR_ARG_INCOMP, bad,
553 "missing statistics state is fatal, never silently zeroed"));
554
555 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
556 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
557 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
558 PetscCall(DetachStatisticsFixture(simCtx, user, &storage));
559 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
560 PetscFunctionReturn(0);
561}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestCheckpointSameStepRewriteIsRejected()

static PetscErrorCode TestCheckpointSameStepRewriteIsRejected ( void  )
static

Verifies a committed checkpoint step is rewritten neither silently nor inconsistently.

WriteCheckpointBundle revalidates an already-committed step instead of rewriting it, so a repeated call at the same step must leave the payloads byte-identical even when the in-memory state has since diverged. The same guard must reject a repeat call whose physical time disagrees with the committed bundle, because that means the step number no longer identifies the same solver state.

Definition at line 572 of file test_io.c.

573{
574 SimCtx *simCtx = NULL;
575 UserCtx *user = NULL;
576 char tmpdir[PETSC_MAX_PATH_LEN];
577 char payload_path[PETSC_MAX_PATH_LEN];
578 struct stat first_stat;
579 struct stat second_stat;
580 PetscErrorCode mismatch_ierr = 0;
581
582 PetscFunctionBeginUser;
583 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
584 tmpdir[0] = '\0';
585 if (simCtx->rank == 0) PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
586 PetscCallMPI(MPI_Bcast(tmpdir, sizeof(tmpdir), MPI_CHAR, 0, PETSC_COMM_WORLD));
587
588 PetscCall(PetscStrncpy(simCtx->output_dir, tmpdir, sizeof(simCtx->output_dir)));
589 PetscCall(PetscStrncpy(simCtx->restart_dir, tmpdir, sizeof(simCtx->restart_dir)));
590 PetscCall(VecSet(user->P, 4.5));
591 PetscCall(VecSet(user->Nvert, 0.0));
592 PetscCall(VecSet(user->Ucat, 2.0));
593 PetscCall(VecSet(user->Ucont, 3.0));
594 PetscCall(VecSet(user->Ucont_rm1, 1.25));
595 simCtx->ti = 0.35;
596 PetscCall(PicurvPopulateIdentityMetrics(user));
597
598 PetscCall(WriteCheckpointBundle(simCtx, "cadence"));
599 PetscCall(PetscSNPrintf(payload_path, sizeof(payload_path),
600 "%s/checkpoints/step_000000000001/eulerian/block_0000/Ucat.dat", tmpdir));
601 PetscCall(PicurvAssertBool((PetscBool)(stat(payload_path, &first_stat) == 0),
602 "first checkpoint write should produce a Ucat payload"));
603
604 /* Diverge the in-memory state so a rewrite would be observable in the payload bytes. */
605 PetscCall(VecSet(user->Ucat, 99.0));
606 PetscCall(WriteCheckpointBundle(simCtx, "cadence"));
607
608 PetscCall(PicurvAssertBool((PetscBool)(stat(payload_path, &second_stat) == 0),
609 "repeated checkpoint write should leave the Ucat payload in place"));
610 /* Nanosecond resolution: a same-second rewrite would still move this. */
611 PetscCall(PicurvAssertBool((PetscBool)(first_stat.st_mtim.tv_sec == second_stat.st_mtim.tv_sec &&
612 first_stat.st_mtim.tv_nsec == second_stat.st_mtim.tv_nsec),
613 "repeated checkpoint write at a committed step should not touch payload mtime"));
614 PetscCall(PicurvAssertBool((PetscBool)(first_stat.st_size == second_stat.st_size),
615 "repeated checkpoint write at a committed step should not resize payloads"));
616
617 PetscCall(VecZeroEntries(user->Ucat));
618 PetscCall(ReadSimulationFields(user, simCtx->step));
619 PetscCall(PicurvAssertVecConstant(user->Ucat, 2.0, 1.0e-12,
620 "repeated checkpoint write must not overwrite committed payload contents"));
621
622 /* A same-step call whose physical time disagrees is a state-identity error, not a no-op. */
623 simCtx->ti = 0.75;
624 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
625 mismatch_ierr = WriteCheckpointBundle(simCtx, "cadence");
626 PetscCall(PetscPopErrorHandler());
627 PetscCall(PicurvAssertIntEqual(PETSC_ERR_FILE_UNEXPECTED, mismatch_ierr,
628 "same-step checkpoint write with a different physical time should fail"));
629
630 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
631 if (simCtx->rank == 0) PetscCall(PicurvRemoveTempDir(tmpdir));
632 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
633 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
634 PetscFunctionReturn(0);
635}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestCheckpointSHA256KnownVector()

static PetscErrorCode TestCheckpointSHA256KnownVector ( void  )
static

Verifies the dependency-free SHA-256 implementation against a standard vector.

Definition at line 638 of file test_io.c.

639{
640 PicurvSHA256Context context;
641 char digest[65];
642
643 PetscFunctionBeginUser;
644 PicurvSHA256Init(&context);
645 PicurvSHA256Update(&context, "abc", 3);
646 PicurvSHA256FinalHex(&context, digest);
647 PetscCall(PicurvAssertBool(
648 (PetscBool)!strcmp(digest, "ba7816bf8f01cfea414140de5dae2223"
649 "b00361a396177a9cb410ff61f20015ad"),
650 "SHA-256 implementation should match the standard abc test vector"));
651 PetscFunctionReturn(0);
652}
void PicurvSHA256Init(PicurvSHA256Context *context)
Initialize an incremental SHA-256 calculation.
Definition checksum.c:62
void PicurvSHA256Update(PicurvSHA256Context *context, const void *data, size_t length)
Add bytes to an incremental SHA-256 calculation.
Definition checksum.c:74
void PicurvSHA256FinalHex(PicurvSHA256Context *context, char digest_hex[65])
Finish a SHA-256 calculation and return a lowercase hexadecimal digest.
Definition checksum.c:98
Incremental SHA-256 state.
Definition checksum.h:14
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParsePostProcessingSettings()

static PetscErrorCode TestParsePostProcessingSettings ( void  )
static

Tests parsing of post-processing control settings from a file.

Definition at line 657 of file test_io.c.

658{
659 SimCtx *simCtx = NULL;
660 UserCtx *user = NULL;
661 char tmpdir[PETSC_MAX_PATH_LEN];
662 char cfg_path[PETSC_MAX_PATH_LEN];
663 FILE *file = NULL;
664
665 PetscFunctionBeginUser;
666 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
667 PetscCall(PetscCalloc1(1, &simCtx->pps));
668 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
669 PetscCall(PetscSNPrintf(cfg_path, sizeof(cfg_path), "%s/post.run", tmpdir));
670 PetscCall(PetscStrncpy(simCtx->PostprocessingControlFile, cfg_path, sizeof(simCtx->PostprocessingControlFile)));
671
672 file = fopen(cfg_path, "w");
673 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to create temp config file '%s'.", cfg_path);
674 fputs("startTime = 2\n", file);
675 fputs("endTime = 6\n", file);
676 fputs("timeStep = 2\n", file);
677 fputs("output_particles = true\n", file);
678 fputs("output_prefix = SmokeField\n", file);
679 fclose(file);
680
681 PetscCall(ParsePostProcessingSettings(simCtx));
682 PetscCall(PicurvAssertIntEqual(2, simCtx->pps->startTime, "ParsePostProcessingSettings should parse startTime"));
683 PetscCall(PicurvAssertIntEqual(6, simCtx->pps->endTime, "ParsePostProcessingSettings should parse endTime"));
684 PetscCall(PicurvAssertIntEqual(2, simCtx->pps->timeStep, "ParsePostProcessingSettings should parse timeStep"));
685 PetscCall(PicurvAssertBool(simCtx->pps->outputParticles, "ParsePostProcessingSettings should parse output_particles"));
686 PetscCall(PicurvAssertBool((PetscBool)(strcmp(simCtx->pps->output_prefix, "SmokeField") == 0),
687 "ParsePostProcessingSettings should parse output_prefix"));
688
689 PetscCall(PicurvRemoveTempDir(tmpdir));
690 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
691 PetscFunctionReturn(0);
692}
PetscErrorCode ParsePostProcessingSettings(SimCtx *simCtx)
Initializes post-processing settings from a config file and command-line overrides.
Definition io.c:3076
char output_prefix[256]
Definition variables.h:609
PetscInt timeStep
Definition variables.h:603
PetscBool outputParticles
Definition variables.h:604
PostProcessParams * pps
Definition variables.h:890
PetscInt startTime
Definition variables.h:601
char PostprocessingControlFile[PETSC_MAX_PATH_LEN]
Definition variables.h:889
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestTrimWhitespace()

static PetscErrorCode TestTrimWhitespace ( void  )
static

Tests trimming of leading and trailing whitespace.

Definition at line 698 of file test_io.c.

699{
700 char value_a[] = " inlet_value ";
701 char value_b[] = " ";
702
703 PetscFunctionBeginUser;
704 TrimWhitespace(value_a);
705 PetscCall(PicurvAssertBool((PetscBool)(strcmp(value_a, "inlet_value") == 0),
706 "TrimWhitespace should remove leading and trailing whitespace"));
707
708 TrimWhitespace(value_b);
709 PetscCall(PicurvAssertBool((PetscBool)(strcmp(value_b, "") == 0),
710 "TrimWhitespace should reduce all-whitespace strings to empty"));
711 PetscFunctionReturn(0);
712}
void TrimWhitespace(char *str)
Removes leading and trailing ASCII whitespace from a mutable string.
Definition io.c:399
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestBoundaryConditionStringParsers()

static PetscErrorCode TestBoundaryConditionStringParsers ( void  )
static

Tests boundary-condition string parsers for face, type, and handler names.

Definition at line 717 of file test_io.c.

718{
719 BCFace face = BC_FACE_NEG_X;
720 BCType type = WALL;
722
723 PetscFunctionBeginUser;
724 PetscCall(StringToBCFace("+Zeta", &face));
725 PetscCall(PicurvAssertIntEqual(BC_FACE_POS_Z, face, "StringToBCFace should parse +Zeta"));
726
727 PetscCall(StringToBCType("periodic", &type));
728 PetscCall(PicurvAssertIntEqual(PERIODIC, type, "StringToBCType should parse PERIODIC case-insensitively"));
729
730 PetscCall(StringToBCHandlerType("constant_flux", &handler));
732 "StringToBCHandlerType should parse constant_flux"));
733 PetscCall(StringToBCHandlerType("prescribed_flow", &handler));
735 "StringToBCHandlerType should parse prescribed_flow"));
736 PetscFunctionReturn(0);
737}
PetscErrorCode StringToBCHandlerType(const char *str, BCHandlerType *handler_out)
Converts a BC handler token (implementation strategy) to BCHandlerType.
Definition io.c:709
PetscErrorCode StringToBCFace(const char *str, BCFace *face_out)
Converts a face-token string (e.g., "-Xi", "+Eta") to the internal BCFace enum.
Definition io.c:679
PetscErrorCode StringToBCType(const char *str, BCType *type_out)
Converts a mathematical BC type string (e.g., "PERIODIC", "WALL") to BCType.
Definition io.c:694
BCType
Defines the general mathematical/physical Category of a boundary.
Definition variables.h:283
@ PERIODIC
Definition variables.h:292
@ WALL
Definition variables.h:286
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:303
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:318
@ BC_HANDLER_INLET_PROFILE_FROM_FILE
Definition variables.h:310
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:305
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:261
@ BC_FACE_NEG_X
Definition variables.h:262
@ BC_FACE_POS_Z
Definition variables.h:264
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestValidateBCHandlerForBCType()

static PetscErrorCode TestValidateBCHandlerForBCType ( void  )
static

Tests validation of boundary-type and handler compatibility.

Definition at line 742 of file test_io.c.

743{
744 PetscFunctionBeginUser;
746 "WALL + noslip should be a valid combination"));
748 "PERIODIC + geometric should be a valid combination"));
750 "INLET + prescribed_flow should be a valid combination"));
752 "INLET + noslip should be rejected"));
753 PetscFunctionReturn(0);
754}
PetscErrorCode ValidateBCHandlerForBCType(BCType type, BCHandlerType handler)
Validates that a selected handler is compatible with a mathematical BC type.
Definition io.c:727
@ INLET
Definition variables.h:290
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:316
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParseScalingInformation()

static PetscErrorCode TestParseScalingInformation ( void  )
static

Tests scaling-reference parsing and derived pressure scaling.

Definition at line 759 of file test_io.c.

760{
761 SimCtx simCtx;
762
763 PetscFunctionBeginUser;
764 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
765
766 PetscCall(PetscOptionsClearValue(NULL, "-scaling_L_ref"));
767 PetscCall(PetscOptionsClearValue(NULL, "-scaling_U_ref"));
768 PetscCall(PetscOptionsClearValue(NULL, "-scaling_rho_ref"));
769
770 PetscCall(ParseScalingInformation(&simCtx));
771 PetscCall(PicurvAssertRealNear(1.0, simCtx.scaling.L_ref, 1.0e-12, "Default scaling_L_ref should be 1.0"));
772 PetscCall(PicurvAssertRealNear(1.0, simCtx.scaling.U_ref, 1.0e-12, "Default scaling_U_ref should be 1.0"));
773 PetscCall(PicurvAssertRealNear(1.0, simCtx.scaling.rho_ref, 1.0e-12, "Default scaling_rho_ref should be 1.0"));
774 PetscCall(PicurvAssertRealNear(1.0, simCtx.scaling.P_ref, 1.0e-12, "Default scaling_P_ref should be 1.0"));
775
776 PetscCall(PetscOptionsSetValue(NULL, "-scaling_L_ref", "2.5"));
777 PetscCall(PetscOptionsSetValue(NULL, "-scaling_U_ref", "4.0"));
778 PetscCall(PetscOptionsSetValue(NULL, "-scaling_rho_ref", "1.2"));
779
780 PetscCall(ParseScalingInformation(&simCtx));
781 PetscCall(PicurvAssertRealNear(2.5, simCtx.scaling.L_ref, 1.0e-12, "scaling_L_ref should honor options"));
782 PetscCall(PicurvAssertRealNear(4.0, simCtx.scaling.U_ref, 1.0e-12, "scaling_U_ref should honor options"));
783 PetscCall(PicurvAssertRealNear(1.2, simCtx.scaling.rho_ref, 1.0e-12, "scaling_rho_ref should honor options"));
784 PetscCall(PicurvAssertRealNear(19.2, simCtx.scaling.P_ref, 1.0e-12, "scaling_P_ref should be rho_ref*U_ref^2"));
785
786 PetscCall(PetscOptionsClearValue(NULL, "-scaling_L_ref"));
787 PetscCall(PetscOptionsClearValue(NULL, "-scaling_U_ref"));
788 PetscCall(PetscOptionsClearValue(NULL, "-scaling_rho_ref"));
789 PetscFunctionReturn(0);
790}
PetscErrorCode ParseScalingInformation(SimCtx *simCtx)
Parses physical scaling parameters from command-line options.
Definition io.c:3242
PetscReal L_ref
Definition variables.h:677
ScalingCtx scaling
Definition variables.h:785
PetscReal P_ref
Definition variables.h:680
PetscReal rho_ref
Definition variables.h:679
PetscReal U_ref
Definition variables.h:678
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CaptureBannerOutput()

static PetscErrorCode CaptureBannerOutput ( SimCtx simCtx,
char *  captured,
size_t  captured_len 
)
static

Captures the startup banner into a temporary file-backed buffer.

Definition at line 794 of file test_io.c.

795{
796 char tmpdir[PETSC_MAX_PATH_LEN];
797 char capture_path[PETSC_MAX_PATH_LEN];
798 FILE *capture_file = NULL;
799 int saved_stdout = -1;
800 int capture_fd = -1;
801 size_t bytes_read = 0;
802 PetscErrorCode ierr;
803
804 PetscFunctionBeginUser;
805 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL.");
806 PetscCheck(captured != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Capture buffer cannot be NULL.");
807 PetscCheck(captured_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Capture buffer must be non-empty.");
808
809 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
810 PetscCall(PetscSNPrintf(capture_path, sizeof(capture_path), "%s/banner.log", tmpdir));
811
812 fflush(stdout);
813 saved_stdout = dup(STDOUT_FILENO);
814 PetscCheck(saved_stdout >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "dup(STDOUT_FILENO) failed.");
815 capture_fd = open(capture_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
816 PetscCheck(capture_fd >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open capture file '%s'.", capture_path);
817 PetscCheck(dup2(capture_fd, STDOUT_FILENO) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "dup2() failed while redirecting stdout.");
818 close(capture_fd);
819 capture_fd = -1;
820
821 ierr = DisplayBanner(simCtx);
822 fflush(stdout);
823 PetscCheck(dup2(saved_stdout, STDOUT_FILENO) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "dup2() failed while restoring stdout.");
824 close(saved_stdout);
825 saved_stdout = -1;
826 PetscCall(ierr);
827
828 capture_file = fopen(capture_path, "r");
829 PetscCheck(capture_file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to read capture file '%s'.", capture_path);
830 bytes_read = fread(captured, 1, captured_len - 1, capture_file);
831 captured[bytes_read] = '\0';
832 fclose(capture_file);
833 PetscCall(PicurvRemoveTempDir(tmpdir));
834 PetscCallMPI(MPI_Bcast(captured, (PetscMPIInt)captured_len, MPI_CHAR, 0, PETSC_COMM_WORLD));
835 PetscFunctionReturn(0);
836}
PetscErrorCode DisplayBanner(SimCtx *simCtx)
Displays a structured banner summarizing the simulation configuration.
Definition io.c:2776
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AssertCapturedContains()

static PetscErrorCode AssertCapturedContains ( const char *  captured,
const char *  needle,
const char *  message 
)
static

Asserts that captured banner output contains one expected substring.

Definition at line 840 of file test_io.c.

841{
842 PetscFunctionBeginUser;
843 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, needle) != NULL), message));
844 PetscFunctionReturn(0);
845}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AssertCapturedOmits()

static PetscErrorCode AssertCapturedOmits ( const char *  captured,
const char *  needle,
const char *  message 
)
static

Asserts that captured banner output omits one forbidden substring.

Definition at line 849 of file test_io.c.

850{
851 PetscFunctionBeginUser;
852 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, needle) == NULL), message));
853 PetscFunctionReturn(0);
854}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestDisplayBannerReportsStatisticsCadence()

static PetscErrorCode TestDisplayBannerReportsStatisticsCadence ( void  )
static

Tests that the startup banner reports statistics monitoring in every state.

The banner is the one place a log records whether monitoring was active, so all three states must be distinguishable after the fact: a live cadence, a subsystem that is accumulating with the console silenced, and a run that configured no window at all. The banner reads only the window array and the console cadence, so this fixture sets those directly rather than allocating accumulator storage it would never touch.

Definition at line 865 of file test_io.c.

866{
867 SimCtx *simCtx = NULL;
868 UserCtx *user = NULL;
869 PicurvWindow window;
871 char captured[16384];
872
873 PetscFunctionBeginUser;
874 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
875 PetscCall(PicurvWindowInit(&window, &definition));
876 simCtx->OnlySetup = PETSC_FALSE;
877 simCtx->StepsToRun = 5;
878 PetscCall(PetscStrncpy(simCtx->eulerianSource, "solve", sizeof(simCtx->eulerianSource)));
879
880 /* A run with statistics accumulating and the console cadence live. */
881 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
882 simCtx->fieldStatisticsWindowCount = 1;
883 simCtx->fieldStatisticsWindows = &window;
884 simCtx->statisticsConsoleOutputFreq = 5;
885 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
886 PetscCall(AssertCapturedContains(captured, "Statistics Console Cadence : every 5 step(s), 1 window(s)",
887 "DisplayBanner should report the live statistics console cadence"));
888
889 /* Accumulating, but with console reporting switched off. */
890 simCtx->statisticsConsoleOutputFreq = 0;
891 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
892 PetscCall(AssertCapturedContains(captured, "Statistics Console Cadence : DISABLED (1 window(s) accumulating)",
893 "DisplayBanner should distinguish a silenced console from an inactive subsystem"));
894
895 /* No window configured: the row still appears, so its absence is never ambiguous. */
896 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
897 simCtx->fieldStatisticsWindowCount = 0;
898 simCtx->fieldStatisticsWindows = NULL;
899 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
900 PetscCall(AssertCapturedContains(captured, "Statistics Console Cadence : DISABLED (no window configured)",
901 "DisplayBanner should record that no statistics window was configured"));
902
903 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
904 PetscFunctionReturn(0);
905}
static PetscErrorCode AssertCapturedContains(const char *captured, const char *needle, const char *message)
Asserts that captured banner output contains one expected substring.
Definition test_io.c:840
static PetscErrorCode CaptureBannerOutput(SimCtx *simCtx, char *captured, size_t captured_len)
Captures the startup banner into a temporary file-backed buffer.
Definition test_io.c:794
PetscInt statisticsConsoleOutputFreq
Definition variables.h:772
PetscInt StepsToRun
Definition variables.h:706
PetscBool OnlySetup
Definition variables.h:711
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:715
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestDisplayBannerTracksConditionalStartupFields()

static PetscErrorCode TestDisplayBannerTracksConditionalStartupFields ( void  )
static

Tests conditional startup-banner fields across particle and analytical cases.

Definition at line 910 of file test_io.c.

911{
912 SimCtx *simCtx = NULL;
913 UserCtx *user = NULL;
914 char captured[16384];
915
916 PetscFunctionBeginUser;
917 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
918 simCtx->OnlySetup = PETSC_FALSE;
919 simCtx->StepsToRun = 5;
920 simCtx->immersed = PETSC_FALSE;
921 PetscCall(PetscStrncpy(simCtx->eulerianSource, "solve", sizeof(simCtx->eulerianSource)));
922 simCtx->particleConsoleOutputFreq = 7;
923 simCtx->LoggingFrequency = 4;
926
927 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
928 PetscCall(AssertCapturedContains(captured, "Run Mode : Full Simulation",
929 "DisplayBanner should include the run mode"));
930 PetscCall(AssertCapturedContains(captured, "Field/Restart Cadence : every 2 step(s)",
931 "DisplayBanner should include field/restart cadence"));
932 PetscCall(AssertCapturedContains(captured, "Immersed Boundary : DISABLED",
933 "DisplayBanner should include immersed-boundary state"));
934 PetscCall(AssertCapturedContains(captured, "Periodic Axes (BC-derived) : I=NO, J=NO, K=NO",
935 "DisplayBanner should include BC-derived periodic axes"));
936 PetscCall(AssertCapturedContains(captured, "Number of Particles : 0",
937 "DisplayBanner should include the total particle count"));
938 PetscCall(AssertCapturedContains(captured, "Eulerian State Source : initial condition (Zero)",
939 "DisplayBanner should identify a fresh solve IC as the Eulerian source"));
940 PetscCall(AssertCapturedOmits(captured, "Particle Console Cadence",
941 "DisplayBanner should omit particle console cadence when no particles are configured"));
942 PetscCall(AssertCapturedOmits(captured, "Particle Log Row Sampling",
943 "DisplayBanner should omit particle row sampling when no particles are configured"));
944 PetscCall(AssertCapturedOmits(captured, "Particle Restart Mode",
945 "DisplayBanner should omit particle restart mode when no particles are configured"));
946 PetscCall(AssertCapturedOmits(captured, "Particle Initialization Mode",
947 "DisplayBanner should omit particle initialization mode when no particles are configured"));
948 PetscCall(AssertCapturedOmits(captured, "Interpolation Method",
949 "DisplayBanner should omit interpolation method when no particles are configured"));
950 PetscCall(AssertCapturedContains(captured, "Initial Pseudo-CFL (Courant)",
951 "DisplayBanner should report pseudo-CFL for the dual-time momentum solver"));
952 PetscCall(AssertCapturedContains(captured, "Pseudo-CFL Adaptation",
953 "DisplayBanner should report the active dual-time controller"));
954 PetscCall(AssertCapturedContains(captured, "Console Log Level",
955 "DisplayBanner should report the effective console log level"));
956 PetscCall(AssertCapturedContains(captured, "Profiling Timestep Output",
957 "DisplayBanner should report profiling mode"));
958 PetscCall(AssertCapturedContains(captured, "Runtime Memory Log",
959 "DisplayBanner should report runtime-memory logging state"));
960
962 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
963 PetscCall(AssertCapturedContains(captured, "Momentum Equation Solver : Newton Krylov",
964 "DisplayBanner should identify the selected Newton-Krylov solver"));
965 PetscCall(AssertCapturedOmits(captured, "Initial Pseudo-CFL (Courant)",
966 "DisplayBanner must not report pseudo-CFL for Newton-Krylov"));
967 PetscCall(AssertCapturedContains(captured, "Newton-Krylov PETSc Controls",
968 "DisplayBanner should report the active Newton-Krylov control family"));
970
973 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
974 PetscCall(AssertCapturedContains(captured, "Solution Convergence Mode : PERIODIC_DETERMINISTIC",
975 "DisplayBanner should identify the active periodic convergence mode"));
976 PetscCall(AssertCapturedContains(captured, "Convergence Period : 11 step(s)",
977 "DisplayBanner should report the active periodic convergence period"));
979 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
980 PetscCall(AssertCapturedOmits(captured, "Convergence Period",
981 "DisplayBanner should omit periodic-only convergence fields when inactive"));
982
983 simCtx->StartStep = 3;
984 simCtx->np = 8;
985 simCtx->i_periodic = 1;
986 user->periodic_translation_valid[0] = PETSC_TRUE;
987 user->periodic_translation[0] = (Cmpnts){1.0, 0.0, 0.0};
988 simCtx->particleConsoleOutputFreq = 0;
989 simCtx->LoggingFrequency = 4;
990 PetscCall(PetscStrncpy(simCtx->particleRestartMode, "load", sizeof(simCtx->particleRestartMode)));
991 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
992 PetscCall(AssertCapturedContains(captured, "Eulerian State Source : restart step 3",
993 "DisplayBanner should identify restart authority"));
994 PetscCall(AssertCapturedOmits(captured, "initial condition (",
995 "DisplayBanner should not present an IC as active during restart"));
996 PetscCall(AssertCapturedContains(captured, "Number of Particles : 8",
997 "DisplayBanner should include the active particle count"));
998 PetscCall(AssertCapturedContains(captured, "Periodic I Translation",
999 "DisplayBanner should include validated periodic translation"));
1000 PetscCall(AssertCapturedContains(captured, "Particle Periodic Wrapping : UNSUPPORTED",
1001 "DisplayBanner should distinguish Eulerian periodicity from particle wrapping"));
1002 PetscCall(AssertCapturedContains(captured, "Particle Console Cadence : DISABLED",
1003 "DisplayBanner should show disabled particle console cadence when particles are configured"));
1004 PetscCall(AssertCapturedContains(captured, "Particle Log Row Sampling : every 4 particle(s)",
1005 "DisplayBanner should include particle row sampling when particles are configured"));
1006 PetscCall(AssertCapturedContains(captured, "Particle Restart Mode : load",
1007 "DisplayBanner should include particle restart mode for restarted particle runs"));
1008 PetscCall(AssertCapturedContains(captured, "Particle Initialization Mode: Point Source",
1009 "DisplayBanner should include particle initialization mode when particles are configured"));
1010 PetscCall(AssertCapturedContains(captured, "Interpolation Method : Trilinear (direct cell-center)",
1011 "DisplayBanner should include default interpolation method when particles are configured"));
1012 PetscCall(AssertCapturedOmits(captured, "Particles Initialized At",
1013 "DisplayBanner should omit inlet-face placement details for point-source particle initialization"));
1014
1015 simCtx->StartStep = 0;
1016 PetscCall(PetscStrncpy(simCtx->eulerianSource, "load", sizeof(simCtx->eulerianSource)));
1017 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
1018 PetscCall(AssertCapturedContains(captured, "Eulerian State Source : load",
1019 "DisplayBanner should identify load authority"));
1020 PetscCall(AssertCapturedOmits(captured, "initial condition (",
1021 "DisplayBanner should not present an IC as active in load mode"));
1022
1023 simCtx->StartStep = 0;
1024 simCtx->particleConsoleOutputFreq = 6;
1026 user->inletFaceDefined = PETSC_TRUE;
1027 user->identifiedInletBCFace = (BCFace)0;
1028 PetscCall(PetscStrncpy(simCtx->eulerianSource, "analytical", sizeof(simCtx->eulerianSource)));
1029 PetscCall(PetscStrncpy(simCtx->AnalyticalSolutionType, "ZERO_FLOW", sizeof(simCtx->AnalyticalSolutionType)));
1030 PetscCall(CaptureBannerOutput(simCtx, captured, sizeof(captured)));
1031 PetscCall(AssertCapturedContains(captured, "Analytical Solution Type : ZERO_FLOW",
1032 "DisplayBanner should include the analytical solution type for analytical runs"));
1033 PetscCall(AssertCapturedContains(captured, "Particle Console Cadence : every 6 step(s)",
1034 "DisplayBanner should include active particle console cadence when particles are configured"));
1035 PetscCall(AssertCapturedContains(captured, "Particle Initialization Mode: Surface: Random",
1036 "DisplayBanner should include particle initialization mode for analytical particle runs"));
1037 PetscCall(AssertCapturedContains(captured, "Particles Initialized At",
1038 "DisplayBanner should include inlet-face placement details for surface particle initialization"));
1039
1040 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1041 PetscFunctionReturn(0);
1042}
static PetscErrorCode AssertCapturedOmits(const char *captured, const char *needle, const char *message)
Asserts that captured banner output omits one forbidden substring.
Definition test_io.c:849
PetscBool inletFaceDefined
Definition variables.h:932
BCFace identifiedInletBCFace
Definition variables.h:933
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:552
@ PARTICLE_INIT_POINT_SOURCE
All particles at a fixed (psrc_x,psrc_y,psrc_z) — for validation.
Definition variables.h:554
PetscInt np
Definition variables.h:827
PetscInt StartStep
Definition variables.h:705
@ MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK
Definition variables.h:536
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:537
PetscInt solutionConvergencePeriodSteps
Definition variables.h:763
char particleRestartMode[16]
Definition variables.h:833
ParticleInitializationType ParticleInitialization
Definition variables.h:831
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:729
PetscInt particleConsoleOutputFreq
Definition variables.h:708
PetscInt i_periodic
Definition variables.h:791
Cmpnts periodic_translation[3]
Definition variables.h:927
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:545
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:544
PetscBool periodic_translation_valid[3]
Definition variables.h:928
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:762
MomentumSolverType mom_solver_type
Definition variables.h:736
PetscInt immersed
Definition variables.h:726
PetscInt LoggingFrequency
Definition variables.h:857
A 3D point or vector with PetscScalar components.
Definition variables.h:102
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Runs the unit-io PETSc test binary.

Definition at line 1047 of file test_io.c.

1048{
1049 PetscErrorCode ierr;
1050 const PicurvTestCase cases[] = {
1051 {"should-write-data-output", TestShouldWriteDataOutput},
1052 {"verify-path-existence", TestVerifyPathExistence},
1053 {"write-and-read-simulation-fields", TestWriteAndReadSimulationFields},
1054 {"checkpoint-same-step-rewrite-rejected", TestCheckpointSameStepRewriteIsRejected},
1055 {"display-banner-reports-statistics-cadence", TestDisplayBannerReportsStatisticsCadence},
1056 {"checkpoint-statistics-round-trip", TestCheckpointStatisticsRoundTrip},
1057 {"checkpoint-statistics-continuation-guards", TestCheckpointStatisticsContinuationGuards},
1058 {"checkpoint-statistics-payload-is-validated", TestCheckpointStatisticsPayloadIsValidated},
1059 {"checkpoint-statistics-absent-when-disabled", TestCheckpointStatisticsAbsentWhenDisabled},
1060 {"checkpoint-sha256-known-vector", TestCheckpointSHA256KnownVector},
1061 {"parse-post-processing-settings", TestParsePostProcessingSettings},
1062 {"trim-whitespace", TestTrimWhitespace},
1063 {"bc-string-parsers", TestBoundaryConditionStringParsers},
1064 {"validate-bc-handler-for-type", TestValidateBCHandlerForBCType},
1065 {"parse-scaling-information", TestParseScalingInformation},
1066 {"display-banner-startup-summary", TestDisplayBannerTracksConditionalStartupFields},
1067 };
1068
1069 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv I/O tests");
1070 if (ierr) {
1071 return (int)ierr;
1072 }
1073
1074 ierr = PicurvRunTests("unit-io", cases, sizeof(cases) / sizeof(cases[0]));
1075 if (ierr) {
1076 PetscFinalize();
1077 return (int)ierr;
1078 }
1079
1080 ierr = PetscFinalize();
1081 return (int)ierr;
1082}
static PetscErrorCode TestCheckpointSameStepRewriteIsRejected(void)
Verifies a committed checkpoint step is rewritten neither silently nor inconsistently.
Definition test_io.c:572
static PetscErrorCode TestParseScalingInformation(void)
Tests scaling-reference parsing and derived pressure scaling.
Definition test_io.c:759
static PetscErrorCode TestValidateBCHandlerForBCType(void)
Tests validation of boundary-type and handler compatibility.
Definition test_io.c:742
static PetscErrorCode TestCheckpointStatisticsContinuationGuards(void)
Verifies continuation refuses every state that would corrupt an average.
Definition test_io.c:348
static PetscErrorCode TestParsePostProcessingSettings(void)
Tests parsing of post-processing control settings from a file.
Definition test_io.c:657
static PetscErrorCode TestCheckpointStatisticsPayloadIsValidated(void)
A damaged statistics payload must fail bundle validation, not load silently.
Definition test_io.c:457
static PetscErrorCode TestCheckpointStatisticsAbsentWhenDisabled(void)
A run without statistics writes no statistics subtree and refuses to fake one.
Definition test_io.c:519
static PetscErrorCode TestCheckpointSHA256KnownVector(void)
Verifies the dependency-free SHA-256 implementation against a standard vector.
Definition test_io.c:638
static PetscErrorCode TestDisplayBannerTracksConditionalStartupFields(void)
Tests conditional startup-banner fields across particle and analytical cases.
Definition test_io.c:910
static PetscErrorCode TestDisplayBannerReportsStatisticsCadence(void)
Tests that the startup banner reports statistics monitoring in every state.
Definition test_io.c:865
static PetscErrorCode TestVerifyPathExistence(void)
Tests filesystem existence checks for files and directories.
Definition test_io.c:40
static PetscErrorCode TestTrimWhitespace(void)
Tests trimming of leading and trailing whitespace.
Definition test_io.c:698
static PetscErrorCode TestShouldWriteDataOutput(void)
Tests cadence-based Eulerian output triggering.
Definition test_io.c:23
static PetscErrorCode TestCheckpointStatisticsRoundTrip(void)
Verifies accumulated statistics survive a checkpoint round trip unchanged.
Definition test_io.c:216
static PetscErrorCode TestBoundaryConditionStringParsers(void)
Tests boundary-condition string parsers for face, type, and handler names.
Definition test_io.c:717
static PetscErrorCode TestWriteAndReadSimulationFields(void)
Tests writing and reloading core Eulerian field vectors.
Definition test_io.c:68
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: