PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Data Structures | Typedefs | Functions
test_logging.c File Reference

C unit tests for runtime log-level, allow-list, conversion, and profiling helpers. More...

#include "test_support.h"
#include "logging.h"
#include "interpolation.h"
#include "setup.h"
#include "statistics_accumulator.h"
#include "statistics_window.h"
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
Include dependency graph for test_logging.c:

Go to the source code of this file.

Data Structures

struct  AnatomyCaptureCtx
 

Typedefs

typedef PetscErrorCode(* CapturedLoggingFn) (UserCtx *user, SimCtx *simCtx, void *ctx)
 
typedef struct AnatomyCaptureCtx AnatomyCaptureCtx
 

Functions

static PetscErrorCode AssertFileContains (const char *path, const char *needle, const char *context)
 Asserts that one text file contains a required substring.
 
static PetscErrorCode AssertFileNotContains (const char *path, const char *needle, const char *context)
 Asserts that one text file does not contain an excluded substring.
 
static PetscErrorCode ReadCsvHeaderAndRow (const char *path, PetscInt row_index, char *header, size_t header_len, char *row, size_t row_len)
 Reads the CSV header and the requested 1-based data row from a text file.
 
static PetscErrorCode CsvFindColumnIndex (const char *header, const char *column_name, PetscInt *index_out)
 Returns the zero-based column index for one CSV header field.
 
static PetscErrorCode CsvGetColumnText (const char *header, const char *row, const char *column_name, char *value, size_t value_len)
 Extracts one CSV cell as text by header name.
 
static PetscErrorCode CsvGetColumnInt (const char *header, const char *row, const char *column_name, PetscInt *value_out)
 Extracts one CSV cell as an integer by header name.
 
static PetscErrorCode CsvGetColumnReal (const char *header, const char *row, const char *column_name, PetscReal *value_out)
 Extracts one CSV cell as a real by header name.
 
static PetscErrorCode ReadLogHeaderAndRow (const char *path, PetscInt row_index, char *header, size_t header_len, char *row, size_t row_len)
 Reads the column header and the requested 1-based data row from a pipe-delimited solution-convergence log file.
 
static PetscErrorCode LogFindColumnIndex (const char *header, const char *column_name, PetscInt *index_out)
 Returns the zero-based column index for one pipe-delimited header field.
 
static PetscErrorCode LogGetColumnText (const char *header, const char *row, const char *column_name, char *value, size_t value_len)
 Extracts one pipe-delimited log cell as text by header name.
 
static PetscErrorCode LogGetColumnInt (const char *header, const char *row, const char *column_name, PetscInt *value_out)
 Extracts one pipe-delimited log cell as an integer by header name.
 
static PetscErrorCode LogGetColumnReal (const char *header, const char *row, const char *column_name, PetscReal *value_out)
 Extracts one pipe-delimited log cell as a real by header name.
 
static PetscErrorCode CaptureLoggingOutput (UserCtx *user, SimCtx *simCtx, CapturedLoggingFn fn, void *ctx, char *captured, size_t captured_len)
 Captures stdout emitted by one logging helper into a temporary file-backed buffer.
 
static PetscErrorCode InvokeParticleFieldLog (UserCtx *user, SimCtx *simCtx, void *ctx)
 Adapts LOG_PARTICLE_FIELDS() to the generic stdout-capture callback shape.
 
static PetscErrorCode InvokeParticleConsoleSnapshot (UserCtx *user, SimCtx *simCtx, void *ctx)
 Adapts EmitParticleConsoleSnapshot() to the generic stdout-capture callback shape.
 
static PetscErrorCode InvokeStatisticsConsoleSnapshot (UserCtx *user, SimCtx *simCtx, void *ctx)
 Adapts EmitStatisticsConsoleSnapshot() to the generic stdout-capture callback shape.
 
static PetscErrorCode InvokeFieldAnatomyLog (UserCtx *user, SimCtx *simCtx, void *ctx)
 Adapts LOG_FIELD_ANATOMY() to the generic stdout-capture callback shape.
 
static PetscErrorCode SeedLoggingParticleFixture (SimCtx **simCtx_out, UserCtx **user_out)
 Creates a small particle-bearing runtime fixture used by logging tests.
 
static PetscErrorCode SetUniformVelocityField (UserCtx *user, Vec field, PetscReal ux, PetscReal uy, PetscReal uz)
 Fills one Cartesian velocity field with a uniform constant state.
 
static PetscErrorCode SetUniformScalarField (UserCtx *user, Vec field, PetscReal value)
 Fills one scalar field with a uniform constant state.
 
static PetscErrorCode SetSinusoidalVZField (UserCtx *user, Vec field, PetscReal v_amp, PetscReal w_const)
 Fills one Cartesian velocity field with u=0, v=v_amp*sin(2π*k/km), w=w_const.
 
static PetscErrorCode TestStringConversionHelpers (void)
 Tests string-conversion helpers for configured enums and unknown values.
 
static PetscErrorCode TestGetLogLevelFromEnvironment (void)
 Tests that log level selection honors the environment variable.
 
static PetscErrorCode TestAllowedFunctionsFilter (void)
 Tests the function allow-list filter used by the logging layer.
 
static PetscErrorCode TestParticleConsoleSnapshotCadence (void)
 Tests periodic particle console snapshot enablement and cadence.
 
static PicurvWindowDefinition LoggingStatisticsDefinition (void)
 Builds the window definition backing this suite's statistics console fixture.
 
static PetscErrorCode TestStatisticsConsoleSnapshotCadence (void)
 Tests periodic statistics console snapshot enablement and cadence.
 
static PetscErrorCode TestLoggingFileParsingAndFormattingHelpers (void)
 Tests logging-side file parsing, helper formatting, and progress utilities.
 
static PetscErrorCode TestLoggingContinuityAndFieldDiagnostics (void)
 Tests continuity, min/max, and anatomy logging helpers on minimal runtime fixtures.
 
static PetscErrorCode TestInterpolationErrorLogging (void)
 Tests interpolation-error logging against an analytically matched particle field.
 
static PetscErrorCode TestScatterMetricsLogging (void)
 Tests file-backed scatter metrics logging against a fully occupied constant field.
 
static PetscErrorCode TestParticleFieldTableLogging (void)
 Tests stdout particle-table logging on a production-like swarm fixture.
 
static PetscErrorCode TestParticleConsoleSnapshotLogging (void)
 Tests console snapshot logging against the public periodic-snapshot helper.
 
static PetscErrorCode TestStatisticsConsoleSnapshotLogging (void)
 Tests statistics console snapshot content, and its silence when disabled.
 
static PetscErrorCode SetUniformPressure (UserCtx *user, PetscReal value)
 Sets the pressure field to a uniform value across the owned range.
 
static PetscErrorCode AccumulateAtConsoleCadence (SimCtx *simCtx, UserCtx *user, PicurvWindow *window, PicurvWindowStorage *storage, const PicurvWindowDefinition *definition, PetscInt console_frequency)
 Drives one accumulation run at a given console cadence, in the runloop's order.
 
static PetscErrorCode AssertVecsIdentical (Vec expected, Vec actual, const char *context)
 Asserts two accumulator vectors are bit-identical.
 
static PetscErrorCode TestConsoleCadenceDoesNotChangeAccumulation (void)
 Tests that the console cadence has no effect on any accumulated result.
 
static PetscErrorCode TestParticleMetricsLogging (void)
 Tests file-backed particle metrics logging after derived metrics are computed.
 
static PetscErrorCode TestSearchMetricsLogging (void)
 Tests file-backed search metrics logging with the compact CSV contract.
 
static PetscErrorCode TestFieldAnatomyLogging (void)
 Tests stdout field-anatomy logging on the corrected production-like DM fixture.
 
static PetscErrorCode TestProfilingLifecycleHelpers (void)
 Tests profiling helper lifecycle logging for timestep and final-summary outputs.
 
static PetscErrorCode TestRuntimeMemoryLogHelpers (void)
 Tests runtime memory log header, step rows, final rows, and disabled mode.
 
static PetscErrorCode TestSolutionConvergenceDisabled (void)
 Verifies -solution_convergence_enabled=false suppresses the convergence writer.
 
static PetscErrorCode TestSolutionConvergenceSteadyLogging (void)
 Tests steady solution-convergence log output, IBM masking, and gauge-invariant pressure drift.
 
static PetscErrorCode TestSolutionConvergencePeriodicLogging (void)
 Tests periodic solution-convergence warmup and phase-aligned reference reuse.
 
static PetscErrorCode TestSolutionConvergenceStatisticalLogging (void)
 Tests statistical solution-convergence sliding-window metrics.
 
static PetscErrorCode TestSolutionConvergenceMeansExcludeGhostLayers (void)
 Regression test: convergence observables ignore the ghost layers of a walled box.
 
static PetscErrorCode TestPeriodicSinusoidalMeanKE (void)
 Regression test: volume-averaged mean KE of a sinusoidal field in a fully periodic domain.
 
int main (int argc, char **argv)
 Runs the unit-logging PETSc test binary.
 

Detailed Description

C unit tests for runtime log-level, allow-list, conversion, and profiling helpers.

Definition in file test_logging.c.


Data Structure Documentation

◆ AnatomyCaptureCtx

struct AnatomyCaptureCtx

Definition at line 405 of file test_logging.c.

Data Fields
FieldId field_id
const char * stage_name

Typedef Documentation

◆ CapturedLoggingFn

typedef PetscErrorCode(* CapturedLoggingFn) (UserCtx *user, SimCtx *simCtx, void *ctx)

Definition at line 403 of file test_logging.c.

◆ AnatomyCaptureCtx

Function Documentation

◆ AssertFileContains()

static PetscErrorCode AssertFileContains ( const char *  path,
const char *  needle,
const char *  context 
)
static

Asserts that one text file contains a required substring.

Definition at line 24 of file test_logging.c.

25{
26 FILE *fp = NULL;
27 long file_size = 0;
28 char *buffer = NULL;
29
30 PetscFunctionBeginUser;
31 fp = fopen(path, "rb");
32 if (!fp) {
33 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open '%s' for assertion.", path);
34 }
35 if (fseek(fp, 0, SEEK_END) != 0) {
36 fclose(fp);
37 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to seek '%s'.", path);
38 }
39 file_size = ftell(fp);
40 if (file_size < 0) {
41 fclose(fp);
42 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to measure '%s'.", path);
43 }
44 if (fseek(fp, 0, SEEK_SET) != 0) {
45 fclose(fp);
46 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to rewind '%s'.", path);
47 }
48
49 PetscCall(PetscMalloc1((size_t)file_size + 1, &buffer));
50 if (file_size > 0) {
51 size_t bytes_read = fread(buffer, 1, (size_t)file_size, fp);
52 if (bytes_read != (size_t)file_size) {
53 fclose(fp);
54 PetscCall(PetscFree(buffer));
55 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to read '%s'.", path);
56 }
57 }
58 buffer[file_size] = '\0';
59 fclose(fp);
60
61 PetscCall(PicurvAssertBool((PetscBool)(strstr(buffer, needle) != NULL), context));
62 PetscCall(PetscFree(buffer));
63 PetscFunctionReturn(0);
64}
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:

◆ AssertFileNotContains()

static PetscErrorCode AssertFileNotContains ( const char *  path,
const char *  needle,
const char *  context 
)
static

Asserts that one text file does not contain an excluded substring.

Definition at line 69 of file test_logging.c.

70{
71 FILE *fp = NULL;
72 long file_size = 0;
73 char *buffer = NULL;
74
75 PetscFunctionBeginUser;
76 fp = fopen(path, "rb");
77 if (!fp) {
78 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open '%s' for assertion.", path);
79 }
80 if (fseek(fp, 0, SEEK_END) != 0) {
81 fclose(fp);
82 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to seek '%s'.", path);
83 }
84 file_size = ftell(fp);
85 if (file_size < 0) {
86 fclose(fp);
87 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to measure '%s'.", path);
88 }
89 if (fseek(fp, 0, SEEK_SET) != 0) {
90 fclose(fp);
91 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to rewind '%s'.", path);
92 }
93
94 PetscCall(PetscMalloc1((size_t)file_size + 1, &buffer));
95 if (file_size > 0) {
96 size_t bytes_read = fread(buffer, 1, (size_t)file_size, fp);
97 if (bytes_read != (size_t)file_size) {
98 fclose(fp);
99 PetscCall(PetscFree(buffer));
100 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to read '%s'.", path);
101 }
102 }
103 buffer[file_size] = '\0';
104 fclose(fp);
105
106 PetscCall(PicurvAssertBool((PetscBool)(strstr(buffer, needle) == NULL), context));
107 PetscCall(PetscFree(buffer));
108 PetscFunctionReturn(0);
109}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadCsvHeaderAndRow()

static PetscErrorCode ReadCsvHeaderAndRow ( const char *  path,
PetscInt  row_index,
char *  header,
size_t  header_len,
char *  row,
size_t  row_len 
)
static

Reads the CSV header and the requested 1-based data row from a text file.

Definition at line 114 of file test_logging.c.

120{
121 FILE *fp = NULL;
122 PetscInt current_row = 0;
123
124 PetscFunctionBeginUser;
125 PetscCheck(path != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV path cannot be NULL.");
126 PetscCheck(header != NULL && header_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV header buffer cannot be NULL or empty.");
127 PetscCheck(row != NULL && row_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV row buffer cannot be NULL or empty.");
128 PetscCheck(row_index >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "CSV row index must be >= 1.");
129
130 fp = fopen(path, "r");
131 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open CSV '%s'.", path);
132 PetscCheck(fgets(header, (int)header_len, fp) != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "CSV header missing in '%s'.", path);
133
134 while (fgets(row, (int)row_len, fp) != NULL) {
135 current_row++;
136 if (current_row == row_index) {
137 fclose(fp);
138 PetscFunctionReturn(0);
139 }
140 }
141
142 fclose(fp);
143 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "CSV '%s' does not contain data row %d.", path, (int)row_index);
144}

◆ CsvFindColumnIndex()

static PetscErrorCode CsvFindColumnIndex ( const char *  header,
const char *  column_name,
PetscInt *  index_out 
)
static

Returns the zero-based column index for one CSV header field.

Definition at line 149 of file test_logging.c.

150{
151 char local_header[4096];
152 char *saveptr = NULL;
153 char *token = NULL;
154 PetscInt index = 0;
155
156 PetscFunctionBeginUser;
157 PetscCheck(header != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV header cannot be NULL.");
158 PetscCheck(column_name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV column name cannot be NULL.");
159 PetscCheck(index_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV column index output cannot be NULL.");
160 PetscCheck(strlen(header) < sizeof(local_header), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "CSV header is too long for the local parser buffer.");
161
162 PetscCall(PetscStrncpy(local_header, header, sizeof(local_header)));
163 token = strtok_r(local_header, ",\r\n", &saveptr);
164 while (token != NULL) {
165 if (strcmp(token, column_name) == 0) {
166 *index_out = index;
167 PetscFunctionReturn(0);
168 }
169 token = strtok_r(NULL, ",\r\n", &saveptr);
170 index++;
171 }
172
173 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "CSV column '%s' was not found.", column_name);
174}
Here is the caller graph for this function:

◆ CsvGetColumnText()

static PetscErrorCode CsvGetColumnText ( const char *  header,
const char *  row,
const char *  column_name,
char *  value,
size_t  value_len 
)
static

Extracts one CSV cell as text by header name.

Definition at line 179 of file test_logging.c.

184{
185 char local_row[4096];
186 char *saveptr = NULL;
187 char *token = NULL;
188 PetscInt target_index = -1;
189 PetscInt index = 0;
190
191 PetscFunctionBeginUser;
192 PetscCheck(row != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV row cannot be NULL.");
193 PetscCheck(value != NULL && value_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV value buffer cannot be NULL or empty.");
194 PetscCheck(strlen(row) < sizeof(local_row), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "CSV row is too long for the local parser buffer.");
195
196 PetscCall(CsvFindColumnIndex(header, column_name, &target_index));
197 PetscCall(PetscStrncpy(local_row, row, sizeof(local_row)));
198
199 token = strtok_r(local_row, ",\r\n", &saveptr);
200 while (token != NULL) {
201 if (index == target_index) {
202 PetscCall(PetscStrncpy(value, token, value_len));
203 PetscFunctionReturn(0);
204 }
205 token = strtok_r(NULL, ",\r\n", &saveptr);
206 index++;
207 }
208
209 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "CSV row is missing column '%s'.", column_name);
210}
static PetscErrorCode CsvFindColumnIndex(const char *header, const char *column_name, PetscInt *index_out)
Returns the zero-based column index for one CSV header field.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CsvGetColumnInt()

static PetscErrorCode CsvGetColumnInt ( const char *  header,
const char *  row,
const char *  column_name,
PetscInt *  value_out 
)
static

Extracts one CSV cell as an integer by header name.

Definition at line 215 of file test_logging.c.

216{
217 char text[256];
218 char *endptr = NULL;
219 long parsed = 0;
220
221 PetscFunctionBeginUser;
222 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV integer output cannot be NULL.");
223 PetscCall(CsvGetColumnText(header, row, column_name, text, sizeof(text)));
224 parsed = strtol(text, &endptr, 10);
225 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "CSV column '%s' did not contain an integer.", column_name);
226 *value_out = (PetscInt)parsed;
227 PetscFunctionReturn(0);
228}
static PetscErrorCode CsvGetColumnText(const char *header, const char *row, const char *column_name, char *value, size_t value_len)
Extracts one CSV cell as text by header name.
Here is the call graph for this function:

◆ CsvGetColumnReal()

static PetscErrorCode CsvGetColumnReal ( const char *  header,
const char *  row,
const char *  column_name,
PetscReal *  value_out 
)
static

Extracts one CSV cell as a real by header name.

Definition at line 233 of file test_logging.c.

234{
235 char text[256];
236 char *endptr = NULL;
237 double parsed = 0.0;
238
239 PetscFunctionBeginUser;
240 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "CSV real output cannot be NULL.");
241 PetscCall(CsvGetColumnText(header, row, column_name, text, sizeof(text)));
242 parsed = strtod(text, &endptr);
243 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "CSV column '%s' did not contain a real value.", column_name);
244 *value_out = (PetscReal)parsed;
245 PetscFunctionReturn(0);
246}
Here is the call graph for this function:

◆ ReadLogHeaderAndRow()

static PetscErrorCode ReadLogHeaderAndRow ( const char *  path,
PetscInt  row_index,
char *  header,
size_t  header_len,
char *  row,
size_t  row_len 
)
static

Reads the column header and the requested 1-based data row from a pipe-delimited solution-convergence log file.

Lines starting with '=' (banner) or '-' (separator) are skipped. The first non-skipped line is treated as the column header; subsequent non-skipped lines are data rows numbered from 1.

Definition at line 256 of file test_logging.c.

262{
263 FILE *fp = NULL;
264 PetscInt current_row = 0;
265 char line[8192];
266 PetscBool header_found = PETSC_FALSE;
267
268 PetscFunctionBeginUser;
269 PetscCheck(path != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log path cannot be NULL.");
270 PetscCheck(header != NULL && header_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log header buffer cannot be NULL.");
271 PetscCheck(row != NULL && row_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log row buffer cannot be NULL.");
272 PetscCheck(row_index >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Log row index must be >= 1.");
273
274 fp = fopen(path, "r");
275 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open log '%s'.", path);
276
277 while (fgets(line, sizeof(line), fp) != NULL) {
278 if (line[0] == '=' || line[0] == '-' || line[0] == '\n' || line[0] == '\r') continue;
279 if (!header_found) {
280 PetscCall(PetscStrncpy(header, line, header_len));
281 header_found = PETSC_TRUE;
282 continue;
283 }
284 current_row++;
285 if (current_row == row_index) {
286 PetscCall(PetscStrncpy(row, line, row_len));
287 fclose(fp);
288 PetscFunctionReturn(0);
289 }
290 }
291
292 fclose(fp);
293 if (!header_found) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Log '%s' has no column header.", path);
294 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Log '%s' does not contain data row %d.", path, (int)row_index);
295}
Here is the caller graph for this function:

◆ LogFindColumnIndex()

static PetscErrorCode LogFindColumnIndex ( const char *  header,
const char *  column_name,
PetscInt *  index_out 
)
static

Returns the zero-based column index for one pipe-delimited header field.

Definition at line 300 of file test_logging.c.

301{
302 char local_header[8192];
303 char *saveptr = NULL;
304 char *token = NULL;
305 PetscInt index = 0;
306
307 PetscFunctionBeginUser;
308 PetscCheck(header != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log header cannot be NULL.");
309 PetscCheck(column_name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log column name cannot be NULL.");
310 PetscCheck(index_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log column index output cannot be NULL.");
311
312 PetscCall(PetscStrncpy(local_header, header, sizeof(local_header)));
313 token = strtok_r(local_header, "|\r\n", &saveptr);
314 while (token != NULL) {
315 while (*token == ' ') token++;
316 char *end = token + strlen(token) - 1;
317 while (end > token && (*end == ' ' || *end == '\r' || *end == '\n')) end--;
318 *(end + 1) = '\0';
319 if (strcmp(token, column_name) == 0) {
320 *index_out = index;
321 PetscFunctionReturn(0);
322 }
323 token = strtok_r(NULL, "|\r\n", &saveptr);
324 index++;
325 }
326 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Log column '%s' was not found.", column_name);
327}
Here is the caller graph for this function:

◆ LogGetColumnText()

static PetscErrorCode LogGetColumnText ( const char *  header,
const char *  row,
const char *  column_name,
char *  value,
size_t  value_len 
)
static

Extracts one pipe-delimited log cell as text by header name.

Definition at line 332 of file test_logging.c.

337{
338 char local_row[8192];
339 char *saveptr = NULL;
340 char *token = NULL;
341 PetscInt target_index = -1;
342 PetscInt index = 0;
343
344 PetscFunctionBeginUser;
345 PetscCheck(row != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log row cannot be NULL.");
346 PetscCheck(value != NULL && value_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log value buffer cannot be NULL.");
347
348 PetscCall(LogFindColumnIndex(header, column_name, &target_index));
349 PetscCall(PetscStrncpy(local_row, row, sizeof(local_row)));
350
351 token = strtok_r(local_row, "|\r\n", &saveptr);
352 while (token != NULL) {
353 if (index == target_index) {
354 while (*token == ' ') token++;
355 char *end = token + strlen(token) - 1;
356 while (end > token && (*end == ' ' || *end == '\r' || *end == '\n')) end--;
357 *(end + 1) = '\0';
358 PetscCall(PetscStrncpy(value, token, value_len));
359 PetscFunctionReturn(0);
360 }
361 token = strtok_r(NULL, "|\r\n", &saveptr);
362 index++;
363 }
364 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Log row is missing column '%s'.", column_name);
365}
static PetscErrorCode LogFindColumnIndex(const char *header, const char *column_name, PetscInt *index_out)
Returns the zero-based column index for one pipe-delimited header field.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LogGetColumnInt()

static PetscErrorCode LogGetColumnInt ( const char *  header,
const char *  row,
const char *  column_name,
PetscInt *  value_out 
)
static

Extracts one pipe-delimited log cell as an integer by header name.

Definition at line 370 of file test_logging.c.

371{
372 char text[256];
373 char *endptr = NULL;
374 long parsed = 0;
375
376 PetscFunctionBeginUser;
377 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log integer output cannot be NULL.");
378 PetscCall(LogGetColumnText(header, row, column_name, text, sizeof(text)));
379 parsed = strtol(text, &endptr, 10);
380 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Log column '%s' did not contain an integer.", column_name);
381 *value_out = (PetscInt)parsed;
382 PetscFunctionReturn(0);
383}
static PetscErrorCode LogGetColumnText(const char *header, const char *row, const char *column_name, char *value, size_t value_len)
Extracts one pipe-delimited log cell as text by header name.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LogGetColumnReal()

static PetscErrorCode LogGetColumnReal ( const char *  header,
const char *  row,
const char *  column_name,
PetscReal *  value_out 
)
static

Extracts one pipe-delimited log cell as a real by header name.

Definition at line 388 of file test_logging.c.

389{
390 char text[256];
391 char *endptr = NULL;
392 double parsed = 0.0;
393
394 PetscFunctionBeginUser;
395 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Log real output cannot be NULL.");
396 PetscCall(LogGetColumnText(header, row, column_name, text, sizeof(text)));
397 parsed = strtod(text, &endptr);
398 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Log column '%s' did not contain a real value.", column_name);
399 *value_out = (PetscReal)parsed;
400 PetscFunctionReturn(0);
401}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CaptureLoggingOutput()

static PetscErrorCode CaptureLoggingOutput ( UserCtx *  user,
SimCtx *  simCtx,
CapturedLoggingFn  fn,
void *  ctx,
char *  captured,
size_t  captured_len 
)
static

Captures stdout emitted by one logging helper into a temporary file-backed buffer.

Definition at line 413 of file test_logging.c.

419{
420 char tmpdir[PETSC_MAX_PATH_LEN];
421 char capture_path[PETSC_MAX_PATH_LEN];
422 FILE *capture_file = NULL;
423 int saved_stdout = -1;
424 int capture_fd = -1;
425 size_t bytes_read = 0;
426 PetscErrorCode ierr;
427
428 PetscFunctionBeginUser;
429 PetscCheck(fn != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Capture callback cannot be NULL.");
430 PetscCheck(captured != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Capture buffer cannot be NULL.");
431 PetscCheck(captured_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Capture buffer must be non-empty.");
432
433 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
434 PetscCall(PetscSNPrintf(capture_path, sizeof(capture_path), "%s/logging.out", tmpdir));
435
436 fflush(stdout);
437 saved_stdout = dup(STDOUT_FILENO);
438 PetscCheck(saved_stdout >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "dup(STDOUT_FILENO) failed.");
439 capture_fd = open(capture_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
440 PetscCheck(capture_fd >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to open capture file '%s'.", capture_path);
441 PetscCheck(dup2(capture_fd, STDOUT_FILENO) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "dup2() failed while redirecting stdout.");
442 close(capture_fd);
443 capture_fd = -1;
444
445 ierr = fn(user, simCtx, ctx);
446 fflush(stdout);
447 PetscCheck(dup2(saved_stdout, STDOUT_FILENO) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "dup2() failed while restoring stdout.");
448 close(saved_stdout);
449 saved_stdout = -1;
450 PetscCall(ierr);
451
452 capture_file = fopen(capture_path, "r");
453 PetscCheck(capture_file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to read capture file '%s'.", capture_path);
454 bytes_read = fread(captured, 1, captured_len - 1, capture_file);
455 captured[bytes_read] = '\0';
456 fclose(capture_file);
457 PetscCall(PicurvRemoveTempDir(tmpdir));
458 PetscFunctionReturn(0);
459}
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:

◆ InvokeParticleFieldLog()

static PetscErrorCode InvokeParticleFieldLog ( UserCtx *  user,
SimCtx *  simCtx,
void *  ctx 
)
static

Adapts LOG_PARTICLE_FIELDS() to the generic stdout-capture callback shape.

Definition at line 464 of file test_logging.c.

465{
466 PetscInt print_interval = *((PetscInt *)ctx);
467
468 PetscFunctionBeginUser;
469 (void)simCtx;
470 PetscCall(LOG_PARTICLE_FIELDS(user, print_interval));
471 PetscFunctionReturn(0);
472}
PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx *user, PetscInt printInterval)
Prints particle fields in a table that automatically adjusts its column widths.
Definition logging.c:400
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InvokeParticleConsoleSnapshot()

static PetscErrorCode InvokeParticleConsoleSnapshot ( UserCtx *  user,
SimCtx *  simCtx,
void *  ctx 
)
static

Adapts EmitParticleConsoleSnapshot() to the generic stdout-capture callback shape.

Definition at line 477 of file test_logging.c.

478{
479 PetscInt step = *((PetscInt *)ctx);
480
481 PetscFunctionBeginUser;
482 PetscCall(EmitParticleConsoleSnapshot(user, simCtx, step));
483 PetscFunctionReturn(0);
484}
PetscErrorCode EmitParticleConsoleSnapshot(UserCtx *user, SimCtx *simCtx, PetscInt step)
Emits one particle console snapshot into the main solver log.
Definition logging.c:559
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InvokeStatisticsConsoleSnapshot()

static PetscErrorCode InvokeStatisticsConsoleSnapshot ( UserCtx *  user,
SimCtx *  simCtx,
void *  ctx 
)
static

Adapts EmitStatisticsConsoleSnapshot() to the generic stdout-capture callback shape.

Definition at line 489 of file test_logging.c.

490{
491 PetscInt step = *((PetscInt *)ctx);
492
493 PetscFunctionBeginUser;
494 PetscCall(EmitStatisticsConsoleSnapshot(user, simCtx, step));
495 PetscFunctionReturn(0);
496}
PetscErrorCode EmitStatisticsConsoleSnapshot(UserCtx *user, const struct SimCtx *simCtx, PetscInt step)
Emits one console snapshot of window progress.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InvokeFieldAnatomyLog()

static PetscErrorCode InvokeFieldAnatomyLog ( UserCtx *  user,
SimCtx *  simCtx,
void *  ctx 
)
static

Adapts LOG_FIELD_ANATOMY() to the generic stdout-capture callback shape.

Definition at line 501 of file test_logging.c.

502{
503 const AnatomyCaptureCtx *anatomy_ctx = (const AnatomyCaptureCtx *)ctx;
504
505 PetscFunctionBeginUser;
506 (void)simCtx;
507 PetscCall(LOG_FIELD_ANATOMY(user, anatomy_ctx->field_id, anatomy_ctx->stage_name));
508 PetscFunctionReturn(0);
509}
PetscErrorCode LOG_FIELD_ANATOMY(UserCtx *user, FieldId field_id, const char *stage_name)
Logs the anatomy of a specified field at key boundary locations, respecting the solver's specific gri...
Definition logging.c:2861
const char * stage_name
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SeedLoggingParticleFixture()

static PetscErrorCode SeedLoggingParticleFixture ( SimCtx **  simCtx_out,
UserCtx **  user_out 
)
static

Creates a small particle-bearing runtime fixture used by logging tests.

Definition at line 514 of file test_logging.c.

515{
516 PetscReal *positions = NULL;
517 PetscReal *velocities = NULL;
518 PetscReal *weights = NULL;
519 PetscInt *cell_ids = NULL;
520 PetscInt *status = NULL;
521 PetscReal *psi = NULL;
522
523 PetscFunctionBeginUser;
524 PetscCall(PicurvCreateMinimalContexts(simCtx_out, user_out, 4, 4, 4));
525 PetscCall(PicurvCreateSwarmPair(*user_out, 2, "ske"));
526 (*simCtx_out)->np = 2;
527 (*simCtx_out)->particleConsoleOutputFreq = 2;
528 (*simCtx_out)->LoggingFrequency = 1;
529
530 PetscCall(DMSwarmGetField((*user_out)->swarm, "position", NULL, NULL, (void **)&positions));
531 PetscCall(DMSwarmGetField((*user_out)->swarm, "velocity", NULL, NULL, (void **)&velocities));
532 PetscCall(DMSwarmGetField((*user_out)->swarm, "weight", NULL, NULL, (void **)&weights));
533 PetscCall(DMSwarmGetField((*user_out)->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
534 PetscCall(DMSwarmGetField((*user_out)->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
535 PetscCall(DMSwarmGetField((*user_out)->swarm, "Psi", NULL, NULL, (void **)&psi));
536
537 positions[0] = 0.25; positions[1] = 0.50; positions[2] = 0.75;
538 positions[3] = 0.50; positions[4] = 0.50; positions[5] = 0.50;
539 velocities[0] = 1.0; velocities[1] = 2.0; velocities[2] = 3.0;
540 velocities[3] = 4.0; velocities[4] = 5.0; velocities[5] = 6.0;
541 weights[0] = 0.2; weights[1] = 0.3; weights[2] = 0.4;
542 weights[3] = 0.5; weights[4] = 0.5; weights[5] = 0.5;
543 cell_ids[0] = 0; cell_ids[1] = 0; cell_ids[2] = 0;
544 cell_ids[3] = 1; cell_ids[4] = 1; cell_ids[5] = 1;
545 status[0] = ACTIVE_AND_LOCATED;
546 status[1] = ACTIVE_AND_LOCATED;
547 psi[0] = 1.0;
548 psi[1] = 3.0;
549
550 PetscCall(DMSwarmRestoreField((*user_out)->swarm, "Psi", NULL, NULL, (void **)&psi));
551 PetscCall(DMSwarmRestoreField((*user_out)->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
552 PetscCall(DMSwarmRestoreField((*user_out)->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
553 PetscCall(DMSwarmRestoreField((*user_out)->swarm, "weight", NULL, NULL, (void **)&weights));
554 PetscCall(DMSwarmRestoreField((*user_out)->swarm, "velocity", NULL, NULL, (void **)&velocities));
555 PetscCall(DMSwarmRestoreField((*user_out)->swarm, "position", NULL, NULL, (void **)&positions));
556 PetscFunctionReturn(0);
557}
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 PicurvCreateSwarmPair(UserCtx *user, PetscInt nlocal, const char *post_field_name)
Creates matched solver and post-processing swarms for tests.
@ ACTIVE_AND_LOCATED
Definition variables.h:165
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetUniformVelocityField()

static PetscErrorCode SetUniformVelocityField ( UserCtx *  user,
Vec  field,
PetscReal  ux,
PetscReal  uy,
PetscReal  uz 
)
static

Fills one Cartesian velocity field with a uniform constant state.

Definition at line 562 of file test_logging.c.

563{
564 Cmpnts ***arr = NULL;
565
566 PetscFunctionBeginUser;
567 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
568 PetscCheck(field != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Velocity field cannot be NULL.");
569
570 PetscCall(DMDAVecGetArray(user->fda, field, &arr));
571 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
572 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
573 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
574 arr[k][j][i].x = ux;
575 arr[k][j][i].y = uy;
576 arr[k][j][i].z = uz;
577 }
578 }
579 }
580 PetscCall(DMDAVecRestoreArray(user->fda, field, &arr));
581 PetscFunctionReturn(0);
582}
PetscScalar x
Definition variables.h:122
PetscScalar z
Definition variables.h:122
DMDALocalInfo info
Definition variables.h:1086
PetscScalar y
Definition variables.h:122
A 3D point or vector with PetscScalar components.
Definition variables.h:121
Here is the caller graph for this function:

◆ SetUniformScalarField()

static PetscErrorCode SetUniformScalarField ( UserCtx *  user,
Vec  field,
PetscReal  value 
)
static

Fills one scalar field with a uniform constant state.

Definition at line 587 of file test_logging.c.

588{
589 PetscReal ***arr = NULL;
590
591 PetscFunctionBeginUser;
592 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
593 PetscCheck(field != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Scalar field cannot be NULL.");
594
595 PetscCall(DMDAVecGetArray(user->da, field, &arr));
596 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
597 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
598 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
599 arr[k][j][i] = value;
600 }
601 }
602 }
603 PetscCall(DMDAVecRestoreArray(user->da, field, &arr));
604 PetscFunctionReturn(0);
605}
Here is the caller graph for this function:

◆ SetSinusoidalVZField()

static PetscErrorCode SetSinusoidalVZField ( UserCtx *  user,
Vec  field,
PetscReal  v_amp,
PetscReal  w_const 
)
static

Fills one Cartesian velocity field with u=0, v=v_amp*sin(2π*k/km), w=w_const.

Sets the sinusoidal profile at ALL owned nodes (including the periodic duplicate endpoint), matching how the IC routines populate fields before any periodic-endpoint fix is applied.

Definition at line 612 of file test_logging.c.

613{
614 Cmpnts ***arr = NULL;
615 /* Production layout: physical cells occupy 1..mz-2; 0 and mz-1 are ghost layers,
616 which on a periodic axis hold copies of the opposite physical cell. */
617 const PetscInt ncells = user->info.mz - 2;
618
619 PetscFunctionBeginUser;
620 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
621 PetscCheck(field != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Velocity field cannot be NULL.");
622
623 PetscCall(DMDAVecGetArray(user->fda, field, &arr));
624 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
625 const PetscInt cell = (k == 0) ? ncells : (k == user->info.mz - 1) ? 1 : k;
626 PetscReal z_phase = (2.0 * PETSC_PI * (PetscReal)(cell - 1)) / (PetscReal)ncells;
627 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
628 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
629 arr[k][j][i].x = 0.0;
630 arr[k][j][i].y = v_amp * PetscSinReal(z_phase);
631 arr[k][j][i].z = w_const;
632 }
633 }
634 }
635 PetscCall(DMDAVecRestoreArray(user->fda, field, &arr));
636 PetscFunctionReturn(0);
637}
Here is the caller graph for this function:

◆ TestStringConversionHelpers()

static PetscErrorCode TestStringConversionHelpers ( void  )
static

Tests string-conversion helpers for configured enums and unknown values.

Definition at line 643 of file test_logging.c.

644{
645 PetscFunctionBeginUser;
646 PetscCall(PicurvAssertBool(strcmp(BCFaceToString(BC_FACE_NEG_X), "-Xi (I-Min)") == 0,
647 "BCFaceToString should report the negative-x face"));
648 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_ZERO), "Zero") == 0,
649 "InitialConditionModeToString should report the zero mode"));
650 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_CONSTANT_CARTESIAN), "Cartesian Constant") == 0,
651 "InitialConditionModeToString should report the Cartesian constant mode"));
652 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_CONSTANT_STREAMWISE), "Streamwise Constant") == 0,
653 "InitialConditionModeToString should report the streamwise constant mode"));
654 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_POISEUILLE), "Poiseuille") == 0,
655 "InitialConditionModeToString should report the Poiseuille mode"));
656 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_FILE), "File") == 0,
657 "InitialConditionModeToString should report the file mode"));
658 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString((InitialConditionMode)99), "Unknown Initial Condition") == 0,
659 "InitialConditionModeToString should reject unknown selectors"));
661 "ParticleInitializationToString should report the volume mode"));
662 PetscCall(PicurvAssertBool(strcmp(LESModelToString(CONSTANT_SMAGORINSKY), "Constant Smagorinsky") == 0,
663 "LESModelToString should report the constant model"));
664 PetscCall(PicurvAssertBool(strcmp(MomentumSolverTypeToString(MOMENTUM_SOLVER_EXPLICIT_RK), "Explicit 4 stage Runge-Kutta ") == 0,
665 "MomentumSolverTypeToString should report the explicit solver"));
666 PetscCall(PicurvAssertBool(strcmp(MomentumSolverTypeToString(MOMENTUM_SOLVER_NEWTON_KRYLOV), "Newton Krylov") == 0,
667 "MomentumSolverTypeToString should report the Newton Krylov solver"));
668 PetscCall(PicurvAssertBool(strcmp(BCTypeToString(PERIODIC), "PERIODIC") == 0,
669 "BCTypeToString should report periodic boundaries"));
671 "BCHandlerTypeToString should report the driven periodic handler"));
672 PetscCall(PicurvAssertBool(strcmp(ParticleLocationStatusToString(LOST), "LOST") == 0,
673 "ParticleLocationStatusToString should report LOST state"));
674 PetscFunctionReturn(0);
675}
const char * BCHandlerTypeToString(BCHandlerType handler_type)
Converts a BCHandlerType enum to its string representation.
Definition logging.c:889
const char * BCFaceToString(BCFace face)
Returns the canonical log token for a boundary-face enum value.
Definition logging.c:671
const char * BCTypeToString(BCType type)
Returns the canonical log token for a boundary mathematical type.
Definition logging.c:869
const char * ParticleLocationStatusToString(ParticleLocationStatus level)
A function that outputs the name of the current level in the ParticleLocation enum.
Definition logging.c:1953
const char * InitialConditionModeToString(InitialConditionMode mode)
Convert an initial-condition mode to a string representation.
Definition logging.c:689
const char * LESModelToString(LESModelType LESFlag)
Returns the canonical log token for an LES model selector.
Definition logging.c:741
const char * MomentumSolverTypeToString(MomentumSolverType SolverFlag)
Returns the canonical log token for a momentum-solver selector.
Definition logging.c:853
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Returns the canonical log token for a particle-initialization mode.
Definition logging.c:724
@ CONSTANT_SMAGORINSKY
Definition variables.h:550
@ PERIODIC
Definition variables.h:318
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
Definition variables.h:711
@ LOST
Definition variables.h:167
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:342
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:693
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:695
InitialConditionMode
Selects the algorithm used to populate a fresh Eulerian velocity field.
Definition variables.h:177
@ IC_MODE_CONSTANT_CARTESIAN
Definition variables.h:179
@ IC_MODE_POISEUILLE
Definition variables.h:180
@ IC_MODE_CONSTANT_STREAMWISE
Definition variables.h:181
@ IC_MODE_FILE
Definition variables.h:182
@ IC_MODE_ZERO
Definition variables.h:178
@ BC_FACE_NEG_X
Definition variables.h:288
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestGetLogLevelFromEnvironment()

static PetscErrorCode TestGetLogLevelFromEnvironment ( void  )
static

Tests that log level selection honors the environment variable.

Definition at line 680 of file test_logging.c.

681{
682 PetscFunctionBeginUser;
684 "get_log_level should honor LOG_LEVEL=INFO in this test binary"));
685 PetscCall(print_log_level());
686 PetscFunctionReturn(0);
687}
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
Definition logging.c:119
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:87
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestAllowedFunctionsFilter()

static PetscErrorCode TestAllowedFunctionsFilter ( void  )
static

Tests the function allow-list filter used by the logging layer.

Definition at line 692 of file test_logging.c.

693{
694 const char *allow_list[] = {"ComputeSpecificKE", "WriteEulerianFile"};
695
696 PetscFunctionBeginUser;
697 set_allowed_functions(allow_list, 2);
698 PetscCall(PicurvAssertBool(is_function_allowed("ComputeSpecificKE"),
699 "Allowed list should include ComputeSpecificKE"));
700 PetscCall(PicurvAssertBool((PetscBool)!is_function_allowed("UnlistedFunction"),
701 "Allowed list should exclude unknown function names"));
702
703 set_allowed_functions(NULL, 0);
704 PetscCall(PicurvAssertBool(is_function_allowed("AnyFunction"),
705 "Empty allow-list should permit all functions"));
706 PetscFunctionReturn(0);
707}
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
Definition logging.c:155
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:186
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParticleConsoleSnapshotCadence()

static PetscErrorCode TestParticleConsoleSnapshotCadence ( void  )
static

Tests periodic particle console snapshot enablement and cadence.

Definition at line 712 of file test_logging.c.

713{
714 SimCtx simCtx;
715
716 PetscFunctionBeginUser;
717 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
718 simCtx.np = 32;
719 simCtx.particleConsoleOutputFreq = 4;
720
722 "Particle snapshot contract should be enabled when particles and cadence are configured"));
724 "Snapshot should emit on cadence-aligned completed steps"));
725 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicParticleConsoleSnapshot(&simCtx, 7),
726 "Snapshot should not emit off-cadence"));
727
728 simCtx.particleConsoleOutputFreq = 0;
729 PetscCall(PicurvAssertBool((PetscBool)!IsParticleConsoleSnapshotEnabled(&simCtx),
730 "Zero cadence should disable periodic particle snapshots"));
731 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicParticleConsoleSnapshot(NULL, 4),
732 "NULL SimCtx should never emit periodic snapshots"));
733 PetscFunctionReturn(0);
734}
PetscBool ShouldEmitPeriodicParticleConsoleSnapshot(const SimCtx *simCtx, PetscInt completed_step)
Returns whether a particle console snapshot should be emitted for the.
Definition logging.c:545
PetscBool IsParticleConsoleSnapshotEnabled(const SimCtx *simCtx)
Returns whether periodic particle console snapshots are enabled.
Definition logging.c:528
PetscInt np
Definition variables.h:990
PetscInt particleConsoleOutputFreq
Definition variables.h:872
The master context for the entire simulation.
Definition variables.h:859
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LoggingStatisticsDefinition()

static PicurvWindowDefinition LoggingStatisticsDefinition ( void  )
static

Builds the window definition backing this suite's statistics console fixture.

One bounded pressure window on a per-step cadence: bounded so the snapshot exercises its percentage-progress branch, and a single field so the fixture stays cheap.

Definition at line 741 of file test_logging.c.

742{
743 PicurvWindowDefinition definition;
744
745 memset(&definition, 0, sizeof(definition));
746 strncpy(definition.name, "console_window", PICURV_WINDOW_NAME_LENGTH - 1);
749 definition.step_cadence = 1;
750 definition.bounded = PETSC_TRUE;
751 definition.end_time = 4.0;
752 definition.field_count = 1;
753 definition.fields[0].field_id = FIELD_ID_P;
754 return definition;
755}
@ FIELD_ID_P
PicurvWindowFieldRequest fields[16]
PetscReal end_time
Requested end; ignored when bounded is false.
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 bounded
False for an open-ended window.
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:

◆ TestStatisticsConsoleSnapshotCadence()

static PetscErrorCode TestStatisticsConsoleSnapshotCadence ( void  )
static

Tests periodic statistics console snapshot enablement and cadence.

Definition at line 760 of file test_logging.c.

761{
762 SimCtx simCtx;
763 PicurvWindow window;
765
766 PetscFunctionBeginUser;
767 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
768 PetscCall(PicurvWindowInit(&window, &definition));
769 simCtx.fieldStatisticsEnabled = PETSC_TRUE;
771 simCtx.fieldStatisticsWindows = &window;
773
775 "Statistics snapshot contract should be enabled when a window and cadence are configured"));
777 "Snapshot should emit on cadence-aligned completed steps"));
778 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicStatisticsConsoleSnapshot(&simCtx, 7),
779 "Snapshot should not emit off-cadence"));
780 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicStatisticsConsoleSnapshot(&simCtx, -1),
781 "Snapshot should not emit for a step that has not completed"));
782
784 PetscCall(PicurvAssertBool((PetscBool)!IsStatisticsConsoleSnapshotEnabled(&simCtx),
785 "Zero cadence should disable periodic statistics snapshots"));
786 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicStatisticsConsoleSnapshot(&simCtx, 0),
787 "Zero cadence should not emit even on the step that opens a run"));
788
789 /* The console cadence is a reporting contract layered on the subsystem gate: with
790 * nothing accumulating there is nothing to report, whatever the cadence says. */
793 PetscCall(PicurvAssertBool((PetscBool)!IsStatisticsConsoleSnapshotEnabled(&simCtx),
794 "A configured cadence should not enable snapshots without an accumulating window"));
795
797 simCtx.fieldStatisticsEnabled = PETSC_FALSE;
798 PetscCall(PicurvAssertBool((PetscBool)!IsStatisticsConsoleSnapshotEnabled(&simCtx),
799 "A disabled subsystem should not emit statistics snapshots"));
800
802 "NULL SimCtx should never emit periodic snapshots"));
803 PetscFunctionReturn(0);
804}
PetscBool ShouldEmitPeriodicStatisticsConsoleSnapshot(const struct SimCtx *simCtx, PetscInt completed_step)
Reports whether a completed step falls on the console snapshot cadence.
PetscBool IsStatisticsConsoleSnapshotEnabled(const struct SimCtx *simCtx)
Reports whether the periodic statistics console snapshot is enabled.
PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
Validates a definition and initializes a window to the pending state.
Runtime state of one window.
static PicurvWindowDefinition LoggingStatisticsDefinition(void)
Builds the window definition backing this suite's statistics console fixture.
PetscInt fieldStatisticsWindowCount
Definition variables.h:932
PetscInt statisticsConsoleOutputFreq
Definition variables.h:934
PetscBool fieldStatisticsEnabled
Definition variables.h:931
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:933
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestLoggingFileParsingAndFormattingHelpers()

static PetscErrorCode TestLoggingFileParsingAndFormattingHelpers ( void  )
static

Tests logging-side file parsing, helper formatting, and progress utilities.

Definition at line 809 of file test_logging.c.

810{
811 char tmpdir[PETSC_MAX_PATH_LEN];
812 char allow_path[PETSC_MAX_PATH_LEN];
813 char dual_log_path[PETSC_MAX_PATH_LEN];
814 FILE *file = NULL;
815 char **funcs = NULL;
816 PetscInt nfuncs = 0;
817 Cell cell;
818 PetscReal distances[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
819 DualMonitorCtx *monctx = NULL;
820 void *ctx = NULL;
821
822 PetscFunctionBeginUser;
823 PetscCall(PetscMemzero(&cell, sizeof(cell)));
824 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
825 PetscCall(PetscSNPrintf(allow_path, sizeof(allow_path), "%s/allowed_functions.txt", tmpdir));
826 PetscCall(PetscSNPrintf(dual_log_path, sizeof(dual_log_path), "%s/dual-monitor.log", tmpdir));
827
828 file = fopen(allow_path, "w");
829 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to create allow-list file '%s'.", allow_path);
830 fputs(" ComputeSpecificKE \n", file);
831 fputs("# comment-only line\n", file);
832 for (PetscInt i = 0; i < 17; ++i) {
833 fprintf(file, "Helper_%02d # trailing comment\n", (int)i);
834 }
835 fclose(file);
836 file = NULL;
837
838 PetscCall(LoadAllowedFunctionsFromFile(allow_path, &funcs, &nfuncs));
839 PetscCall(PicurvAssertIntEqual(18, nfuncs, "LoadAllowedFunctionsFromFile should trim comments and keep all identifiers"));
840 PetscCall(PicurvAssertBool((PetscBool)(strcmp(funcs[0], "ComputeSpecificKE") == 0),
841 "LoadAllowedFunctionsFromFile should trim leading and trailing whitespace"));
842 PetscCall(PicurvAssertBool((PetscBool)(strcmp(funcs[17], "Helper_16") == 0),
843 "LoadAllowedFunctionsFromFile should grow past the initial pointer capacity"));
844 PetscCall(FreeAllowedFunctions(funcs, nfuncs));
845
846 for (PetscInt i = 0; i < 8; ++i) {
847 cell.vertices[i].x = (PetscReal)i;
848 cell.vertices[i].y = (PetscReal)(i + 1);
849 cell.vertices[i].z = (PetscReal)(i + 2);
850 }
851 PetscCall(LOG_CELL_VERTICES(&cell, 0));
852 PetscCall(LOG_FACE_DISTANCES(distances));
853
854 PetscCall(PetscCalloc1(1, &monctx));
855 monctx->file_handle = fopen(dual_log_path, "w");
856 PetscCheck(monctx->file_handle != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to create dual-monitor log '%s'.", dual_log_path);
857 ctx = monctx;
858 PetscCall(DualMonitorDestroy(&ctx));
859 PetscCall(PicurvAssertBool((PetscBool)(ctx == NULL),
860 "DualMonitorDestroy should clear the caller-owned context pointer"));
861
862 PrintProgressBar(0, 0, 4, 0.10);
863 PrintProgressBar(3, 0, 4, 0.40);
864 PrintProgressBar(0, 0, 0, 0.00);
865 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
866
867 PetscCall(PicurvRemoveTempDir(tmpdir));
868 PetscFunctionReturn(0);
869}
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
Definition logging.c:926
PetscErrorCode FreeAllowedFunctions(char **funcs, PetscInt n)
Free an array previously returned by LoadAllowedFunctionsFromFile().
Definition logging.c:652
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
Definition logging.c:598
void PrintProgressBar(PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime)
Prints a progress bar to the console.
Definition logging.c:2411
PetscErrorCode LOG_FACE_DISTANCES(PetscReal *d)
Prints the signed distances to each face of the cell.
Definition logging.c:233
PetscErrorCode LOG_CELL_VERTICES(const Cell *cell, PetscMPIInt rank)
Prints the coordinates of a cell's vertices.
Definition logging.c:208
FILE * file_handle
Definition logging.h:57
Context for a dual-purpose KSP monitor.
Definition logging.h:56
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
Definition variables.h:204
Defines the vertices of a single hexahedral grid cell.
Definition variables.h:203
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestLoggingContinuityAndFieldDiagnostics()

static PetscErrorCode TestLoggingContinuityAndFieldDiagnostics ( void  )
static

Tests continuity, min/max, and anatomy logging helpers on minimal runtime fixtures.

Definition at line 874 of file test_logging.c.

875{
876 SimCtx *simCtx = NULL;
877 UserCtx *user = NULL;
878 char tmpdir[PETSC_MAX_PATH_LEN];
879 char continuity_path[PETSC_MAX_PATH_LEN];
880 PetscReal ***p = NULL;
881 Cmpnts ***ucat = NULL;
882 Cmpnts ***ucont = NULL;
883 PetscErrorCode ierr_minmax = 0;
884
885 PetscFunctionBeginUser;
886 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
887 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
888 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
889
890 simCtx->StartStep = 0;
891 simCtx->step = 1;
892 simCtx->MaxDiv = 1.25;
893 simCtx->MaxDivx = 1;
894 simCtx->MaxDivy = 2;
895 simCtx->MaxDivz = 3;
896 simCtx->MaxDivFlatArg = 17;
897 simCtx->poissonSourceImbalance = 8.5;
898 simCtx->FluxInSum = 5.0;
899 simCtx->FluxOutSum = 3.25;
900 PetscCall(LOG_CONTINUITY_METRICS(user));
901
902 simCtx->step = 2;
903 simCtx->MaxDiv = 0.75;
904 simCtx->poissonSourceImbalance = 4.5;
905 simCtx->FluxInSum = 2.5;
906 simCtx->FluxOutSum = 1.0;
907 PetscCall(LOG_CONTINUITY_METRICS(user));
908
909 PetscCall(PetscSNPrintf(continuity_path, sizeof(continuity_path), "%s/Continuity_Metrics.log", simCtx->log_dir));
910 PetscCall(PicurvAssertFileExists(continuity_path, "continuity metrics log should be written"));
911 PetscCall(AssertFileContains(continuity_path, "Timestep", "continuity metrics log should include the header"));
912 PetscCall(AssertFileContains(continuity_path, "([3][2][1] = 17)", "continuity metrics log should include the divergence location"));
913 PetscCall(AssertFileContains(continuity_path, "2 | 0", "continuity metrics log should append later timesteps"));
914
915 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
916 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
917 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &ucont));
918 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
919 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
920 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
921 p[k][j][i] = (PetscReal)(i + j + k);
922 ucat[k][j][i].x = (PetscReal)i;
923 ucat[k][j][i].y = (PetscReal)(-j);
924 ucat[k][j][i].z = (PetscReal)(2 * k);
925 ucont[k][j][i].x = (PetscReal)(10 + i);
926 ucont[k][j][i].y = (PetscReal)(20 + j);
927 ucont[k][j][i].z = (PetscReal)(30 + k);
928 }
929 }
930 }
931 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &ucont));
932 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
933 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
934
935 PetscCall(DMGlobalToLocalBegin(user->da, user->P, INSERT_VALUES, user->lP));
936 PetscCall(DMGlobalToLocalEnd(user->da, user->P, INSERT_VALUES, user->lP));
937 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
938 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
939 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
940 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
941
942 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_P));
943 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_UCAT));
944 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_COORDINATES));
945 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_UCONT));
946
947 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
948 ierr_minmax = LOG_FIELD_MIN_MAX(user, FIELD_ID_INVALID);
949 PetscCall(PetscPopErrorHandler());
950 PetscCall(PicurvAssertBool((PetscBool)(ierr_minmax != 0),
951 "LOG_FIELD_MIN_MAX should reject invalid field IDs"));
952
953 PetscCall(PicurvRemoveTempDir(tmpdir));
954 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
955 PetscFunctionReturn(0);
956}
@ FIELD_ID_UCAT
@ FIELD_ID_COORDINATES
@ FIELD_ID_UCONT
@ FIELD_ID_INVALID
PetscErrorCode LOG_FIELD_MIN_MAX(UserCtx *user, FieldId field_id)
Computes and logs the local and global min/max values of a 3-component vector field.
Definition logging.c:2458
PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user)
Logs continuity metrics for a single block to a file.
Definition logging.c:1891
static PetscErrorCode AssertFileContains(const char *path, const char *needle, const char *context)
Asserts that one text file contains a required substring.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvAssertFileExists(const char *path, const char *context)
Asserts that a filesystem path exists as a readable file.
PetscReal FluxOutSum
Definition variables.h:959
PetscReal poissonSourceImbalance
Definition variables.h:1026
Vec Ucont
Definition variables.h:1113
PetscInt StartStep
Definition variables.h:869
PetscReal MaxDiv
Definition variables.h:1027
PetscInt MaxDivx
Definition variables.h:1028
PetscInt MaxDivy
Definition variables.h:1028
PetscInt MaxDivz
Definition variables.h:1028
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:882
PetscInt MaxDivFlatArg
Definition variables.h:1028
PetscReal FluxInSum
Definition variables.h:959
Vec lUcont
Definition variables.h:1113
PetscInt step
Definition variables.h:867
Vec lUcat
Definition variables.h:1113
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestInterpolationErrorLogging()

static PetscErrorCode TestInterpolationErrorLogging ( void  )
static

Tests interpolation-error logging against an analytically matched particle field.

Definition at line 961 of file test_logging.c.

962{
963 SimCtx *simCtx = NULL;
964 UserCtx *user = NULL;
965 PetscReal (*pos_arr)[3] = NULL;
966 PetscReal (*vel_arr)[3] = NULL;
967 Vec position_vec = NULL;
968 Vec analytical_vec = NULL;
969 const PetscScalar *analytical_arr = NULL;
970 char tmpdir[PETSC_MAX_PATH_LEN];
971 char metrics_path[PETSC_MAX_PATH_LEN];
972
973 PetscFunctionBeginUser;
974 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
975 PetscCall(PicurvCreateSwarmPair(user, 2, "ske"));
976 PetscCall(PetscStrncpy(simCtx->AnalyticalSolutionType, "TGV3D", sizeof(simCtx->AnalyticalSolutionType)));
977 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
978 PetscCall(PetscStrncpy(simCtx->analysis_dir, tmpdir, sizeof(simCtx->analysis_dir)));
979 simCtx->ren = 1.0;
980 /* ti is physical time, not a step count. The CSV once wrote ti * dt, which read
981 2.5e-03 here instead of 0.25. */
982 simCtx->step = 25;
983 simCtx->dt = 0.01;
984 simCtx->ti = 0.25;
985
986 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void *)&pos_arr));
987 pos_arr[0][0] = 0.5 * PETSC_PI; pos_arr[0][1] = 0.0; pos_arr[0][2] = 0.0;
988 pos_arr[1][0] = 0.0; pos_arr[1][1] = 0.5 * PETSC_PI; pos_arr[1][2] = 0.0;
989 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void *)&pos_arr));
990
991 PetscCall(DMSwarmCreateGlobalVectorFromField(user->swarm, "position", &position_vec));
992 PetscCall(VecDuplicate(position_vec, &analytical_vec));
993 PetscCall(VecCopy(position_vec, analytical_vec));
994 PetscCall(SetAnalyticalSolutionForParticles(analytical_vec, simCtx));
995
996 PetscCall(DMSwarmGetField(user->swarm, "velocity", NULL, NULL, (void *)&vel_arr));
997 PetscCall(VecGetArrayRead(analytical_vec, &analytical_arr));
998 for (PetscInt particle = 0; particle < 2; ++particle) {
999 vel_arr[particle][0] = PetscRealPart(analytical_arr[3 * particle + 0]);
1000 vel_arr[particle][1] = PetscRealPart(analytical_arr[3 * particle + 1]);
1001 vel_arr[particle][2] = PetscRealPart(analytical_arr[3 * particle + 2]);
1002 }
1003 PetscCall(VecRestoreArrayRead(analytical_vec, &analytical_arr));
1004 PetscCall(DMSwarmRestoreField(user->swarm, "velocity", NULL, NULL, (void *)&vel_arr));
1005
1006 PetscCall(VecDestroy(&analytical_vec));
1007 PetscCall(DMSwarmDestroyGlobalVectorFromField(user->swarm, "position", &position_vec));
1008 PetscCall(LOG_INTERPOLATION_ERROR(user));
1009
1010 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/interpolation_error.csv", simCtx->analysis_dir));
1011 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_INTERPOLATION_ERROR should write interpolation_error.csv"));
1012 PetscCall(AssertFileContains(metrics_path, "25,2.500000e-01,",
1013 "interpolation_error.csv should record physical time, not time multiplied by dt"));
1014 PetscCall(PicurvRemoveTempDir(tmpdir));
1015 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1016 PetscFunctionReturn(0);
1017}
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
PetscErrorCode LOG_INTERPOLATION_ERROR(UserCtx *user)
Logs the interpolation error between the analytical and computed solutions.
Definition logging.c:2974
PetscReal ren
Definition variables.h:906
PetscReal dt
Definition variables.h:874
char analysis_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:883
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:893
PetscReal ti
Definition variables.h:868
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestScatterMetricsLogging()

static PetscErrorCode TestScatterMetricsLogging ( void  )
static

Tests file-backed scatter metrics logging against a fully occupied constant field.

Definition at line 1022 of file test_logging.c.

1023{
1024 SimCtx *simCtx = NULL;
1025 UserCtx *user = NULL;
1026 char tmpdir[PETSC_MAX_PATH_LEN];
1027 char metrics_path[PETSC_MAX_PATH_LEN];
1028 PetscReal *positions = NULL;
1029 PetscReal *psi = NULL;
1030 PetscInt *cell_ids = NULL;
1031 PetscInt *status = NULL;
1032 PetscInt particle = 0;
1033
1034 PetscFunctionBeginUser;
1035 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1036 PetscCall(PicurvCreateSwarmPair(user, 27, "ske"));
1037 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1038 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1039 simCtx->np = 27;
1040 simCtx->step = 3;
1041 simCtx->ti = 0.3;
1042 simCtx->verificationScalar.enabled = PETSC_TRUE;
1043 PetscCall(PetscStrncpy(simCtx->verificationScalar.mode,
1044 "analytical",
1045 sizeof(simCtx->verificationScalar.mode)));
1046 PetscCall(PetscStrncpy(simCtx->verificationScalar.profile,
1047 "CONSTANT",
1048 sizeof(simCtx->verificationScalar.profile)));
1049 simCtx->verificationScalar.value = 2.0;
1050
1051 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void **)&positions));
1052 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
1053 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
1054 PetscCall(DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
1055
1056 for (PetscInt k = 0; k < 3; ++k) {
1057 for (PetscInt j = 0; j < 3; ++j) {
1058 for (PetscInt i = 0; i < 3; ++i) {
1059 positions[3 * particle + 0] = (i + 0.5) / 4.0;
1060 positions[3 * particle + 1] = (j + 0.5) / 4.0;
1061 positions[3 * particle + 2] = (k + 0.5) / 4.0;
1062 cell_ids[3 * particle + 0] = i;
1063 cell_ids[3 * particle + 1] = j;
1064 cell_ids[3 * particle + 2] = k;
1065 status[particle] = ACTIVE_AND_LOCATED;
1066 psi[particle] = 2.0;
1067 ++particle;
1068 }
1069 }
1070 }
1071
1072 PetscCall(DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
1073 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
1074 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
1075 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void **)&positions));
1076
1078 PetscCall(LOG_SCATTER_METRICS(user));
1079
1080 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/scatter_metrics.csv", simCtx->analysis_dir));
1081 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_SCATTER_METRICS should write scatter_metrics.csv"));
1082 PetscCall(AssertFileContains(metrics_path, "relative_L2_error",
1083 "Scatter metrics CSV header should include relative_L2_error"));
1084 PetscCall(AssertFileContains(metrics_path,
1085 "3,3.000000e-01,27,27,27,1.000000e+00,1.000000e+00,5.400000e+01,5.400000e+01,0.000000e+00,0.000000e+00,0.000000e+00,0.000000e+00,0.000000e+00",
1086 "Scatter metrics CSV should record the expected constant-field zero-error row"));
1087
1088 PetscCall(PicurvRemoveTempDir(tmpdir));
1089 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1090 PetscFunctionReturn(0);
1091}
PetscErrorCode ScatterAllParticleFieldsToEulerFields(UserCtx *user)
Scatters a predefined set of particle fields to their corresponding Eulerian fields.
PetscErrorCode LOG_SCATTER_METRICS(UserCtx *user)
Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.
Definition logging.c:3056
VerificationScalarConfig verificationScalar
Definition variables.h:940
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParticleFieldTableLogging()

static PetscErrorCode TestParticleFieldTableLogging ( void  )
static

Tests stdout particle-table logging on a production-like swarm fixture.

Definition at line 1096 of file test_logging.c.

1097{
1098 SimCtx *simCtx = NULL;
1099 UserCtx *user = NULL;
1100 PetscInt print_interval = 1;
1101 char captured[8192];
1102
1103 PetscFunctionBeginUser;
1104 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1105 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeParticleFieldLog, &print_interval, captured, sizeof(captured)));
1106 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Position (x,y,z)") != NULL),
1107 "LOG_PARTICLE_FIELDS should print the particle table header"));
1108 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Weights (a1,a2,a3)") != NULL),
1109 "LOG_PARTICLE_FIELDS should print the weight-column header"));
1110 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1111 PetscFunctionReturn(0);
1112}
static PetscErrorCode CaptureLoggingOutput(UserCtx *user, SimCtx *simCtx, CapturedLoggingFn fn, void *ctx, char *captured, size_t captured_len)
Captures stdout emitted by one logging helper into a temporary file-backed buffer.
static PetscErrorCode SeedLoggingParticleFixture(SimCtx **simCtx_out, UserCtx **user_out)
Creates a small particle-bearing runtime fixture used by logging tests.
static PetscErrorCode InvokeParticleFieldLog(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts LOG_PARTICLE_FIELDS() to the generic stdout-capture callback shape.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParticleConsoleSnapshotLogging()

static PetscErrorCode TestParticleConsoleSnapshotLogging ( void  )
static

Tests console snapshot logging against the public periodic-snapshot helper.

Definition at line 1117 of file test_logging.c.

1118{
1119 SimCtx *simCtx = NULL;
1120 UserCtx *user = NULL;
1121 PetscInt step = 4;
1122 char captured[8192];
1123
1124 PetscFunctionBeginUser;
1125 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1126 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeParticleConsoleSnapshot, &step, captured, sizeof(captured)));
1127 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Particle states at step 4") != NULL),
1128 "EmitParticleConsoleSnapshot should print the step banner"));
1129 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Position (x,y,z)") != NULL),
1130 "EmitParticleConsoleSnapshot should reuse the particle table output"));
1131 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1132 PetscFunctionReturn(0);
1133}
static PetscErrorCode InvokeParticleConsoleSnapshot(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts EmitParticleConsoleSnapshot() to the generic stdout-capture callback shape.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestStatisticsConsoleSnapshotLogging()

static PetscErrorCode TestStatisticsConsoleSnapshotLogging ( void  )
static

Tests statistics console snapshot content, and its silence when disabled.

Covers both halves of the monitoring contract from one fixture: an active window reports its window-level scalars, and the identical call on a disabled subsystem writes nothing at all, which is the observable form of the gate the runloop relies on to keep a non-statistics run's log untouched.

Definition at line 1143 of file test_logging.c.

1144{
1145 SimCtx *simCtx = NULL;
1146 UserCtx *user = NULL;
1147 PicurvWindow window;
1148 PicurvWindowStorage storage;
1150 PetscInt step = 2;
1151 char captured[8192];
1152
1153 PetscFunctionBeginUser;
1154 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1155 PetscCall(VecSet(user->Nvert, 0.0));
1156 PetscCall(PicurvWindowInit(&window, &definition));
1157 PetscCall(PicurvWindowStorageCreate(user, &definition, &storage));
1158
1159 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
1160 simCtx->fieldStatisticsWindowCount = 1;
1161 simCtx->fieldStatisticsWindows = &window;
1162 simCtx->statisticsConsoleOutputFreq = 1;
1163 user->fieldStatisticsStorage = &storage;
1164
1165 /* Step 0 anchors the origin without sampling; steps 1 and 2 each represent one
1166 * unit of time, so the snapshot has two accepted samples to report. */
1167 for (PetscInt offered = 0; offered <= step; ++offered) {
1168 PetscCall(FieldStatisticsUpdateWindows(simCtx, offered, (PetscReal)offered));
1169 }
1170
1171 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeStatisticsConsoleSnapshot, &step,
1172 captured, sizeof(captured)));
1173 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Statistics windows at step 2") != NULL),
1174 "EmitStatisticsConsoleSnapshot should print the step banner"));
1175 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "console_window") != NULL),
1176 "EmitStatisticsConsoleSnapshot should name each configured window"));
1177 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "samples=2") != NULL),
1178 "EmitStatisticsConsoleSnapshot should report the accepted sample count"));
1179 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "valid=[") != NULL),
1180 "EmitStatisticsConsoleSnapshot should report mask coverage once storage carries samples"));
1181
1182 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
1183 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeStatisticsConsoleSnapshot, &step,
1184 captured, sizeof(captured)));
1185 PetscCall(PicurvAssertIntEqual(0, (PetscInt)strlen(captured),
1186 "a disabled subsystem emits no statistics console output"));
1187
1188 simCtx->fieldStatisticsWindows = NULL;
1189 simCtx->fieldStatisticsWindowCount = 0;
1190 user->fieldStatisticsStorage = NULL;
1191 PetscCall(PicurvWindowStorageDestroy(&storage));
1192 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1193 PetscFunctionReturn(0);
1194}
PetscErrorCode PicurvWindowStorageCreate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage)
Allocates the accumulator state one window owns on one block.
PetscErrorCode PicurvWindowStorageDestroy(PicurvWindowStorage *storage)
Releases accumulator state previously created for one window.
Independent accumulator state for one window on one block.
PetscErrorCode FieldStatisticsUpdateWindows(struct SimCtx *simCtx, PetscInt step, PetscReal time)
Offers one completed state to every configured window.
static PetscErrorCode InvokeStatisticsConsoleSnapshot(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts EmitStatisticsConsoleSnapshot() to the generic stdout-capture callback shape.
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:1136
Vec Nvert
Definition variables.h:1113
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetUniformPressure()

static PetscErrorCode SetUniformPressure ( UserCtx *  user,
PetscReal  value 
)
static

Sets the pressure field to a uniform value across the owned range.

Definition at line 1198 of file test_logging.c.

1199{
1200 PetscReal ***p = NULL;
1201 const DMDALocalInfo info = user->info;
1202
1203 PetscFunctionBeginUser;
1204 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
1205 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k)
1206 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j)
1207 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) p[k][j][i] = value;
1208 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
1209 PetscFunctionReturn(0);
1210}
Here is the caller graph for this function:

◆ AccumulateAtConsoleCadence()

static PetscErrorCode AccumulateAtConsoleCadence ( SimCtx *  simCtx,
UserCtx *  user,
PicurvWindow *  window,
PicurvWindowStorage *  storage,
const PicurvWindowDefinition *  definition,
PetscInt  console_frequency 
)
static

Drives one accumulation run at a given console cadence, in the runloop's order.

Reproduces the sequence the run loop applies for each completed step so the console observes exactly the states a real run would present to it.

Definition at line 1217 of file test_logging.c.

1222{
1223 PetscFunctionBeginUser;
1224 PetscCall(PicurvWindowInit(window, definition));
1225 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
1226 simCtx->fieldStatisticsWindowCount = 1;
1227 simCtx->fieldStatisticsWindows = window;
1228 simCtx->statisticsConsoleOutputFreq = console_frequency;
1229 user->fieldStatisticsStorage = storage;
1230
1231 for (PetscInt step = 0; step <= 3; ++step) {
1232 PetscCall(SetUniformPressure(user, 1.0 + (PetscReal)step));
1233 PetscCall(FieldStatisticsUpdateWindows(simCtx, step, (PetscReal)step));
1235 PetscCall(EmitStatisticsConsoleSnapshot(user, simCtx, step));
1236 }
1237 }
1238 PetscFunctionReturn(0);
1239}
static PetscErrorCode SetUniformPressure(UserCtx *user, PetscReal value)
Sets the pressure field to a uniform value across the owned range.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AssertVecsIdentical()

static PetscErrorCode AssertVecsIdentical ( Vec  expected,
Vec  actual,
const char *  context 
)
static

Asserts two accumulator vectors are bit-identical.

Definition at line 1243 of file test_logging.c.

1244{
1245 PetscBool equal = PETSC_FALSE;
1246
1247 PetscFunctionBeginUser;
1248 PetscCall(VecEqual(expected, actual, &equal));
1249 PetscCall(PicurvAssertBool(equal, context));
1250 PetscFunctionReturn(0);
1251}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestConsoleCadenceDoesNotChangeAccumulation()

static PetscErrorCode TestConsoleCadenceDoesNotChangeAccumulation ( void  )
static

Tests that the console cadence has no effect on any accumulated result.

This is the observable form of the console cadence's exclusion from the window definition hash: two runs over an identical field series, one reporting every step and one reporting never, must leave bit-identical accumulator state. Running it where the log level is at least LOG_INFO matters, because a snapshot that silently declined to emit would make the comparison vacuous.

Definition at line 1262 of file test_logging.c.

1263{
1264 SimCtx *simCtx = NULL;
1265 UserCtx *user = NULL;
1266 PicurvWindow reported, silent;
1267 PicurvWindowStorage reported_storage, silent_storage;
1269 char captured[8192];
1270 PetscInt step = 3;
1271
1272 PetscFunctionBeginUser;
1273 definition.fields[0].want_second = PETSC_TRUE;
1274 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1275 PetscCall(VecSet(user->Nvert, 0.0));
1276 PetscCall(PicurvWindowStorageCreate(user, &definition, &reported_storage));
1277 PetscCall(PicurvWindowStorageCreate(user, &definition, &silent_storage));
1278
1279 PetscCall(AccumulateAtConsoleCadence(simCtx, user, &reported, &reported_storage, &definition, 1));
1280 PetscCall(AccumulateAtConsoleCadence(simCtx, user, &silent, &silent_storage, &definition, 0));
1281
1282 PetscCall(PicurvAssertIntEqual(reported.sample_count, silent.sample_count,
1283 "both cadences accept the same states"));
1284 PetscCall(PicurvAssertRealNear(reported.total_weight, silent.total_weight, 0.0,
1285 "both cadences accumulate the same total weight"));
1286 PetscCall(AssertVecsIdentical(reported_storage.count, silent_storage.count,
1287 "per-point sample counts are independent of the console cadence"));
1288 PetscCall(AssertVecsIdentical(reported_storage.weight, silent_storage.weight,
1289 "per-point weights are independent of the console cadence"));
1290 PetscCall(AssertVecsIdentical(reported_storage.mean[0], silent_storage.mean[0],
1291 "means are independent of the console cadence"));
1292 PetscCall(AssertVecsIdentical(reported_storage.m2[0], silent_storage.m2[0],
1293 "second moments are independent of the console cadence"));
1294
1295 /* The reporting cadence did drive real output, so the comparison above compared a
1296 * reported run against a silent one rather than two silent ones. */
1297 simCtx->statisticsConsoleOutputFreq = 1;
1298 simCtx->fieldStatisticsWindows = &reported;
1299 user->fieldStatisticsStorage = &reported_storage;
1300 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeStatisticsConsoleSnapshot, &step,
1301 captured, sizeof(captured)));
1302 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "console_window") != NULL),
1303 "the reporting cadence emits console output at this log level"));
1304
1305 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
1306 simCtx->fieldStatisticsWindows = NULL;
1307 simCtx->fieldStatisticsWindowCount = 0;
1308 user->fieldStatisticsStorage = NULL;
1309 PetscCall(PicurvWindowStorageDestroy(&silent_storage));
1310 PetscCall(PicurvWindowStorageDestroy(&reported_storage));
1311 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1312 PetscFunctionReturn(0);
1313}
Vec weight
Per-point valid weight.
Vec * mean
One per field, matching that field's layout.
Vec * m2
One per field; NULL when no second moment was requested.
Vec count
Per-point accepted sample count.
PetscInt sample_count
PetscReal total_weight
PetscBool want_second
Also keep the centered second moment.
static PetscErrorCode AssertVecsIdentical(Vec expected, Vec actual, const char *context)
Asserts two accumulator vectors are bit-identical.
static PetscErrorCode AccumulateAtConsoleCadence(SimCtx *simCtx, UserCtx *user, PicurvWindow *window, PicurvWindowStorage *storage, const PicurvWindowDefinition *definition, PetscInt console_frequency)
Drives one accumulation run at a given console cadence, in the runloop's order.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestParticleMetricsLogging()

static PetscErrorCode TestParticleMetricsLogging ( void  )
static

Tests file-backed particle metrics logging after derived metrics are computed.

Definition at line 1318 of file test_logging.c.

1319{
1320 SimCtx *simCtx = NULL;
1321 UserCtx *user = NULL;
1322 char tmpdir[PETSC_MAX_PATH_LEN];
1323 char metrics_path[PETSC_MAX_PATH_LEN];
1324
1325 PetscFunctionBeginUser;
1326 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1327 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1328 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1329 simCtx->StartStep = 0;
1330 simCtx->step = 1;
1331 simCtx->particlesLostLastStep = 1;
1332 simCtx->particlesLostCumulative = 7;
1333 simCtx->particlesMigratedLastStep = 2;
1334 simCtx->migrationPassesLastStep = 3;
1335
1336 PetscCall(CalculateParticleCountPerCell(user));
1337 PetscCall(CalculateAdvancedParticleMetrics(user));
1338 PetscCall(LOG_PARTICLE_METRICS(user, "Timestep Metrics"));
1339
1340 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/Particle_Metrics.log", simCtx->log_dir));
1341 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_PARTICLE_METRICS should write Particle_Metrics.log"));
1342 PetscCall(AssertFileContains(metrics_path, "Timestep Metrics", "Particle metrics log should include the caller-provided stage label"));
1343 PetscCall(AssertFileContains(metrics_path, "Occupied Cells", "Particle metrics log should include the metrics table header"));
1344 PetscCall(AssertFileContains(metrics_path, "Lost Total", "Particle metrics log should include the cumulative-loss column"));
1345 PetscCall(AssertFileContains(metrics_path, "| 1 | 7 | 2", "Particle metrics log should record both per-step and cumulative loss values"));
1346 PetscCall(PicurvRemoveTempDir(tmpdir));
1347 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1348 PetscFunctionReturn(0);
1349}
PetscErrorCode CalculateParticleCountPerCell(UserCtx *user)
Counts particles in each cell of the DMDA 'da' and stores the result in user->ParticleCount.
PetscErrorCode LOG_PARTICLE_METRICS(UserCtx *user, const char *stageName)
Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.
Definition logging.c:3458
PetscErrorCode CalculateAdvancedParticleMetrics(UserCtx *user)
Computes advanced particle statistics and stores them in SimCtx.
Definition logging.c:3404
PetscInt particlesLostLastStep
Definition variables.h:997
PetscInt particlesLostCumulative
Definition variables.h:998
PetscInt particlesMigratedLastStep
Definition variables.h:1002
PetscInt migrationPassesLastStep
Definition variables.h:1001
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSearchMetricsLogging()

static PetscErrorCode TestSearchMetricsLogging ( void  )
static

Tests file-backed search metrics logging with the compact CSV contract.

Definition at line 1354 of file test_logging.c.

1355{
1356 SimCtx *simCtx = NULL;
1357 UserCtx *user = NULL;
1358 char tmpdir[PETSC_MAX_PATH_LEN];
1359 char metrics_path[PETSC_MAX_PATH_LEN];
1360
1361 PetscFunctionBeginUser;
1362 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1363 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1364 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1365 simCtx->step = 2;
1366 simCtx->ti = 0.2;
1367 simCtx->particlesLostLastStep = 1;
1368 simCtx->particlesLostCumulative = 7;
1369 simCtx->particlesMigratedLastStep = 2;
1370 simCtx->migrationPassesLastStep = 3;
1371 simCtx->particleLoadImbalance = 1.5;
1372 simCtx->searchMetrics.searchAttempts = 4;
1373 simCtx->searchMetrics.searchPopulation = 2;
1375 simCtx->searchMetrics.searchLostCount = 1;
1376 simCtx->searchMetrics.traversalStepsSum = 10;
1377 simCtx->searchMetrics.reSearchCount = 2;
1378 simCtx->searchMetrics.maxTraversalSteps = 6;
1380 simCtx->searchMetrics.tieBreakCount = 1;
1385
1386 PetscCall(LOG_SEARCH_METRICS(user));
1387
1388 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/search_metrics.csv", simCtx->analysis_dir));
1389 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_SEARCH_METRICS should write search_metrics.csv"));
1390 PetscCall(AssertFileContains(metrics_path, "search_attempts", "Search metrics CSV header should include search_attempts"));
1391 PetscCall(AssertFileContains(metrics_path, "search_population", "Search metrics CSV header should include search_population"));
1392 PetscCall(AssertFileContains(metrics_path, "max_particle_pass_depth", "Search metrics CSV header should include max_particle_pass_depth"));
1393 PetscCall(AssertFileContains(metrics_path, "search_work_index", "Search metrics CSV header should include search_work_index"));
1394 PetscCall(AssertFileContains(metrics_path, "re_search_fraction", "Search metrics CSV header should include re_search_fraction"));
1395 PetscCall(AssertFileContains(metrics_path, "lost_cumulative", "Search metrics CSV header should include the cumulative-loss column"));
1396 PetscCall(AssertFileContains(metrics_path, "2,2.000000e-01,2,1,7,2,3,4,2.500000e+00,6,1,2,3,1,3,1.500000e+00,2,1,1,10,2,1,5.000000e-01,5.000000e+00,1.000000e+00", "Search metrics CSV should record the V2 raw and derived search metrics"));
1397 PetscCall(PicurvRemoveTempDir(tmpdir));
1398 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1399 PetscFunctionReturn(0);
1400}
PetscErrorCode LOG_SEARCH_METRICS(UserCtx *user)
Writes compact runtime search metrics to CSV and optionally to console.
Definition logging.c:3245
PetscInt64 searchLocatedCount
Definition variables.h:267
PetscInt64 searchLostCount
Definition variables.h:268
PetscInt64 boundaryClampCount
Definition variables.h:274
PetscInt64 traversalStepsSum
Definition variables.h:269
PetscInt64 searchPopulation
Definition variables.h:266
PetscInt64 reSearchCount
Definition variables.h:270
PetscInt64 bboxGuessFallbackCount
Definition variables.h:276
PetscInt64 bboxGuessSuccessCount
Definition variables.h:275
PetscInt64 maxParticlePassDepth
Definition variables.h:277
PetscInt64 maxTraversalSteps
Definition variables.h:271
SearchMetricsState searchMetrics
Definition variables.h:1005
PetscInt64 searchAttempts
Definition variables.h:265
PetscInt64 tieBreakCount
Definition variables.h:273
PetscInt64 maxTraversalFailCount
Definition variables.h:272
PetscReal particleLoadImbalance
Definition variables.h:1004
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestFieldAnatomyLogging()

static PetscErrorCode TestFieldAnatomyLogging ( void  )
static

Tests stdout field-anatomy logging on the corrected production-like DM fixture.

Definition at line 1405 of file test_logging.c.

1406{
1407 SimCtx *simCtx = NULL;
1408 UserCtx *user = NULL;
1409 char captured[8192];
1410 AnatomyCaptureCtx anatomy_ctx = {FIELD_ID_P, "unit-test"};
1411
1412 PetscFunctionBeginUser;
1413 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1414 PetscCall(VecSet(user->P, 7.0));
1415 PetscCall(DMGlobalToLocalBegin(user->da, user->P, INSERT_VALUES, user->lP));
1416 PetscCall(DMGlobalToLocalEnd(user->da, user->P, INSERT_VALUES, user->lP));
1417 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeFieldAnatomyLog, &anatomy_ctx, captured, sizeof(captured)));
1418 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Field Anatomy Log: [P]") != NULL),
1419 "LOG_FIELD_ANATOMY should print the requested field name"));
1420 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Layout: [Cell-Centered]") != NULL),
1421 "LOG_FIELD_ANATOMY should report the inferred data layout"));
1422 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1423 PetscFunctionReturn(0);
1424}
static PetscErrorCode InvokeFieldAnatomyLog(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts LOG_FIELD_ANATOMY() to the generic stdout-capture callback shape.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestProfilingLifecycleHelpers()

static PetscErrorCode TestProfilingLifecycleHelpers ( void  )
static

Tests profiling helper lifecycle logging for timestep and final-summary outputs.

Definition at line 1429 of file test_logging.c.

1430{
1431 SimCtx simCtx;
1432 char tmpdir[PETSC_MAX_PATH_LEN];
1433 char timestep_path[PETSC_MAX_PATH_LEN];
1434 char summary_path[PETSC_MAX_PATH_LEN];
1435 static char selected_name[] = "FlowSolver";
1436 char *selected_funcs[] = {selected_name};
1437
1438 PetscFunctionBeginUser;
1439 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
1440 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1441 PetscCall(PetscStrncpy(simCtx.log_dir, tmpdir, sizeof(simCtx.log_dir)));
1442 PetscCall(PetscStrncpy(simCtx.profilingTimestepMode, "selected", sizeof(simCtx.profilingTimestepMode)));
1443 PetscCall(PetscStrncpy(simCtx.profilingTimestepFile, "Profiling_Timestep_Summary.csv", sizeof(simCtx.profilingTimestepFile)));
1444 simCtx.rank = 0;
1445 simCtx.exec_mode = EXEC_MODE_SOLVER;
1446 simCtx.StartStep = 0;
1447 simCtx.nProfilingSelectedFuncs = 1;
1448 simCtx.profilingSelectedFuncs = selected_funcs;
1449 simCtx.profilingFinalSummary = PETSC_TRUE;
1450
1451 PetscCall(ProfilingInitialize(&simCtx));
1452
1453 _ProfilingStart("FlowSolver");
1454 _ProfilingEnd("FlowSolver");
1455 _ProfilingStart("UnselectedHelper");
1456 _ProfilingEnd("UnselectedHelper");
1457 PetscCall(ProfilingLogTimestepSummary(&simCtx, 1));
1458
1459 _ProfilingStart("FlowSolver");
1460 _ProfilingEnd("FlowSolver");
1461 PetscCall(ProfilingResetTimestepCounters());
1462 PetscCall(ProfilingLogTimestepSummary(&simCtx, 2));
1463 PetscCall(ProfilingFinalize(&simCtx));
1464
1465 PetscCall(PetscSNPrintf(timestep_path, sizeof(timestep_path), "%s/%s", simCtx.log_dir, simCtx.profilingTimestepFile));
1466 PetscCall(PetscSNPrintf(summary_path, sizeof(summary_path), "%s/ProfilingSummary_Solver.log", simCtx.log_dir));
1467 PetscCall(PicurvAssertFileExists(timestep_path, "profiling timestep summary should be written"));
1468 PetscCall(PicurvAssertFileExists(summary_path, "profiling final summary should be written"));
1469 PetscCall(AssertFileContains(timestep_path, "step,function,calls,step_time_s",
1470 "profiling timestep summary should contain the CSV header"));
1471 PetscCall(AssertFileContains(timestep_path, "1,FlowSolver,1,",
1472 "profiling timestep summary should log selected functions"));
1473 PetscCall(AssertFileNotContains(timestep_path, "UnselectedHelper",
1474 "profiling timestep summary should omit unselected functions in selected mode"));
1475 PetscCall(AssertFileContains(summary_path, "FINAL PROFILING SUMMARY",
1476 "profiling final summary should include its table banner"));
1477 PetscCall(AssertFileContains(summary_path, "FlowSolver",
1478 "profiling final summary should include selected functions"));
1479 PetscCall(AssertFileContains(summary_path, "UnselectedHelper",
1480 "profiling final summary should include total-time entries for unselected functions"));
1481 PetscCall(PicurvRemoveTempDir(tmpdir));
1482 PetscFunctionReturn(0);
1483}
PetscErrorCode ProfilingFinalize(SimCtx *simCtx)
the profiling excercise and build a profiling summary which is then printed to a log file.
Definition logging.c:2305
PetscErrorCode ProfilingLogTimestepSummary(SimCtx *simCtx, PetscInt step)
Logs the performance summary for the current timestep and resets timers.
Definition logging.c:2100
void _ProfilingEnd(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_END.
Definition logging.c:2061
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:2023
PetscErrorCode ProfilingResetTimestepCounters(void)
Resets per-timestep profiling counters for the next solver step.
Definition logging.c:2083
void _ProfilingStart(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.
Definition logging.c:2047
static PetscErrorCode AssertFileNotContains(const char *path, const char *needle, const char *context)
Asserts that one text file does not contain an excluded substring.
PetscBool profilingFinalSummary
Definition variables.h:1036
PetscMPIInt rank
Definition variables.h:862
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:1035
char profilingTimestepMode[32]
Definition variables.h:1034
char ** profilingSelectedFuncs
Definition variables.h:1032
PetscInt nProfilingSelectedFuncs
Definition variables.h:1033
@ EXEC_MODE_SOLVER
Definition variables.h:832
ExecutionMode exec_mode
Definition variables.h:878
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestRuntimeMemoryLogHelpers()

static PetscErrorCode TestRuntimeMemoryLogHelpers ( void  )
static

Tests runtime memory log header, step rows, final rows, and disabled mode.

Definition at line 1488 of file test_logging.c.

1489{
1490 SimCtx simCtx;
1491 char tmpdir[PETSC_MAX_PATH_LEN];
1492 char memory_path[PETSC_MAX_PATH_LEN];
1493
1494 PetscFunctionBeginUser;
1495 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
1496 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1497 PetscCall(PetscStrncpy(simCtx.log_dir, tmpdir, sizeof(simCtx.log_dir)));
1498 PetscCall(PetscStrncpy(simCtx.runtimeMemoryLogFile, "Runtime_Memory.log", sizeof(simCtx.runtimeMemoryLogFile)));
1499 simCtx.rank = 0;
1500 simCtx.runtimeMemoryLogEnabled = PETSC_TRUE;
1501 simCtx.runtimeMemoryLogStarted = PETSC_FALSE;
1502 simCtx.runtimeMemoryLogHasPrevious = PETSC_FALSE;
1503 simCtx.continueMode = PETSC_FALSE;
1504 simCtx.StartStep = 0;
1505 PetscCall(PetscMemorySetGetMaximumUsage());
1506
1507 PetscCall(RuntimeMemoryLogSample(&simCtx, 1, "Step", "-"));
1508 PetscCall(RuntimeMemoryLogSample(&simCtx, 1, "Final", "Complete"));
1509 PetscCall(PetscSNPrintf(memory_path, sizeof(memory_path), "%s/%s", simCtx.log_dir, simCtx.runtimeMemoryLogFile));
1510 PetscCall(PicurvAssertFileExists(memory_path, "runtime memory log should be written"));
1511 PetscCall(AssertFileContains(memory_path, "Process Current MB Max",
1512 "runtime memory log should contain readable column labels"));
1513 PetscCall(AssertFileContains(memory_path, "Step",
1514 "runtime memory log should contain a step row"));
1515 PetscCall(AssertFileContains(memory_path, "Final",
1516 "runtime memory log should contain a final row"));
1517 PetscCall(AssertFileContains(memory_path, "Complete",
1518 "runtime memory log should record final reason"));
1519
1520 simCtx.runtimeMemoryLogEnabled = PETSC_FALSE;
1521 PetscCall(PetscStrncpy(simCtx.runtimeMemoryLogFile, "Runtime_Memory_Disabled.log", sizeof(simCtx.runtimeMemoryLogFile)));
1522 PetscCall(RuntimeMemoryLogSample(&simCtx, 2, "Step", "-"));
1523 PetscCall(PetscSNPrintf(memory_path, sizeof(memory_path), "%s/%s", simCtx.log_dir, simCtx.runtimeMemoryLogFile));
1524 PetscCall(PicurvAssertBool((PetscBool)(access(memory_path, F_OK) != 0),
1525 "disabled runtime memory log should not create a file"));
1526 PetscCall(PicurvRemoveTempDir(tmpdir));
1527 PetscFunctionReturn(0);
1528}
PetscErrorCode RuntimeMemoryLogSample(SimCtx *simCtx, PetscInt step, const char *event, const char *reason)
Append a reduced runtime memory sample to the configured memory log.
Definition logging.c:2195
PetscBool continueMode
Definition variables.h:876
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:1051
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:1052
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
Definition variables.h:1053
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
Definition variables.h:1054
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSolutionConvergenceDisabled()

static PetscErrorCode TestSolutionConvergenceDisabled ( void  )
static

Verifies -solution_convergence_enabled=false suppresses the convergence writer.

Definition at line 1533 of file test_logging.c.

1534{
1535 SimCtx *simCtx = NULL;
1536 UserCtx *user = NULL;
1537 char tmpdir[PETSC_MAX_PATH_LEN];
1538 char log_path[PETSC_MAX_PATH_LEN];
1539 PetscBool exists = PETSC_FALSE;
1540
1541 PetscFunctionBeginUser;
1542 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1543 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1544 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1545 simCtx->solutionConvergenceEnabled = PETSC_FALSE;
1546
1547 PetscCall(InitializeSolutionConvergenceState(simCtx));
1548 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1549 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1550 PetscCall(PetscTestFile(log_path, 'r', &exists));
1551 PetscCall(PicurvAssertBool((PetscBool)!exists,
1552 "disabled solution convergence must not create a log"));
1553
1554 PetscCall(PicurvRemoveTempDir(tmpdir));
1555 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1556 PetscFunctionReturn(0);
1557}
PetscErrorCode LOG_SOLUTION_CONVERGENCE(SimCtx *simCtx)
Logs physical solution-convergence metrics once per completed timestep.
Definition logging.c:1695
PetscErrorCode InitializeSolutionConvergenceState(SimCtx *simCtx)
Allocates any runtime storage required by solution-convergence logging.
Definition setup.c:96
PetscBool solutionConvergenceEnabled
Definition variables.h:923
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSolutionConvergenceSteadyLogging()

static PetscErrorCode TestSolutionConvergenceSteadyLogging ( void  )
static

Tests steady solution-convergence log output, IBM masking, and gauge-invariant pressure drift.

Definition at line 1562 of file test_logging.c.

1563{
1564 SimCtx *simCtx = NULL;
1565 UserCtx *user = NULL;
1566 char tmpdir[PETSC_MAX_PATH_LEN];
1567 char log_path[PETSC_MAX_PATH_LEN];
1568 char header[4096];
1569 char row1[4096];
1570 char row2[4096];
1571 char mode[128];
1572 Cmpnts ***ucat = NULL;
1573 PetscReal ***nvert = NULL;
1574 PetscReal mean_speed = NAN;
1575 PetscReal mean_speed_ref = NAN;
1576 PetscReal mean_speed_abs = NAN;
1577 PetscReal p_abs = NAN;
1578 PetscInt has_reference_1 = 0;
1579 PetscInt has_reference_2 = 0;
1580
1581 PetscFunctionBeginUser;
1582 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1583 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1584 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1586
1587 PetscCall(InitializeSolutionConvergenceState(simCtx));
1588
1589 simCtx->step = 1;
1590 simCtx->ti = 0.1;
1591 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.0, 0.0, 0.0));
1592 PetscCall(SetUniformScalarField(user, user->P, 11.0));
1593 PetscCall(DMDAVecGetArray(user->da, user->Nvert, &nvert));
1594 nvert[1][1][1] = 1.0;
1595 PetscCall(DMDAVecRestoreArray(user->da, user->Nvert, &nvert));
1596 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
1597 ucat[1][1][1].x = 999.0;
1598 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
1599 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1600
1601 simCtx->step = 2;
1602 simCtx->ti = 0.2;
1603 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.0, 0.0, 0.0));
1604 PetscCall(SetUniformVelocityField(user, user->Ucat_o, 0.5, 0.0, 0.0));
1605 PetscCall(SetUniformScalarField(user, user->P, 11.0));
1606 PetscCall(SetUniformScalarField(user, user->P_o, 7.0));
1607 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
1608 ucat[1][1][1].x = 999.0;
1609 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
1610 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1611
1612 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1613 PetscCall(PicurvAssertFileExists(log_path, "steady solution-convergence logging should write the log"));
1614 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row1, sizeof(row1)));
1615 PetscCall(ReadLogHeaderAndRow(log_path, 2, header, sizeof(header), row2, sizeof(row2)));
1616 PetscCall(LogGetColumnText(header, row1, "mode", mode, sizeof(mode)));
1617 PetscCall(LogGetColumnInt(header, row1, "ref", &has_reference_1));
1618 PetscCall(LogGetColumnInt(header, row2, "ref", &has_reference_2));
1619 PetscCall(LogGetColumnReal(header, row2, "mean_speed", &mean_speed));
1620 PetscCall(LogGetColumnReal(header, row2, "spd_ref", &mean_speed_ref));
1621 PetscCall(LogGetColumnReal(header, row2, "spd_abs", &mean_speed_abs));
1622 PetscCall(LogGetColumnReal(header, row2, "p_abs_l2", &p_abs));
1623
1624 PetscCall(PicurvAssertBool((PetscBool)(strcmp(mode, "steady_deterministic") == 0),
1625 "steady solution convergence row should record the mode name"));
1626 PetscCall(PicurvAssertIntEqual(0, has_reference_1,
1627 "the first steady solution-convergence row should be a warmup row"));
1628 PetscCall(PicurvAssertIntEqual(1, has_reference_2,
1629 "steady solution convergence should compare against the previous solved step"));
1630 PetscCall(PicurvAssertRealNear(1.0, mean_speed, 1.0e-12,
1631 "steady solution convergence should mask IBM-marked solid cells"));
1632 PetscCall(PicurvAssertRealNear(0.5, mean_speed_ref, 1.0e-12,
1633 "steady solution convergence should report the previous-step mean speed"));
1634 PetscCall(PicurvAssertRealNear(0.5, mean_speed_abs, 1.0e-12,
1635 "steady solution convergence should report mean-speed drift"));
1636 PetscCall(PicurvAssertRealNear(0.0, p_abs, 1.0e-12,
1637 "steady solution convergence pressure drift should be gauge invariant"));
1638
1639 PetscCall(PicurvRemoveTempDir(tmpdir));
1640 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1641 PetscFunctionReturn(0);
1642}
static PetscErrorCode SetUniformScalarField(UserCtx *user, Vec field, PetscReal value)
Fills one scalar field with a uniform constant state.
static PetscErrorCode SetUniformVelocityField(UserCtx *user, Vec field, PetscReal ux, PetscReal uy, PetscReal uz)
Fills one Cartesian velocity field with a uniform constant state.
static PetscErrorCode ReadLogHeaderAndRow(const char *path, PetscInt row_index, char *header, size_t header_len, char *row, size_t row_len)
Reads the column header and the requested 1-based data row from a pipe-delimited solution-convergence...
static PetscErrorCode LogGetColumnReal(const char *header, const char *row, const char *column_name, PetscReal *value_out)
Extracts one pipe-delimited log cell as a real by header name.
static PetscErrorCode LogGetColumnInt(const char *header, const char *row, const char *column_name, PetscInt *value_out)
Extracts one pipe-delimited log cell as an integer by header name.
Vec Ucat_o
Definition variables.h:1120
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:702
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:924
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSolutionConvergencePeriodicLogging()

static PetscErrorCode TestSolutionConvergencePeriodicLogging ( void  )
static

Tests periodic solution-convergence warmup and phase-aligned reference reuse.

Definition at line 1647 of file test_logging.c.

1648{
1649 SimCtx *simCtx = NULL;
1650 UserCtx *user = NULL;
1651 char tmpdir[PETSC_MAX_PATH_LEN];
1652 char log_path[PETSC_MAX_PATH_LEN];
1653 char header[4096];
1654 char row1[4096];
1655 char row2[4096];
1656 char row3[4096];
1657 PetscInt has_reference_1 = 0;
1658 PetscInt has_reference_2 = 0;
1659 PetscInt has_reference_3 = 0;
1660 PetscInt phase_step_1 = -1;
1661 PetscInt phase_step_2 = -1;
1662 PetscInt phase_step_3 = -1;
1663 PetscReal mean_speed_ref_2 = NAN;
1664 PetscReal mean_speed_abs_2 = NAN;
1665
1666 PetscFunctionBeginUser;
1667 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1668 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1669 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1672
1673 PetscCall(InitializeSolutionConvergenceState(simCtx));
1674
1675 simCtx->step = 1;
1676 simCtx->ti = 0.1;
1677 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.0, 0.0, 0.0));
1678 PetscCall(SetUniformScalarField(user, user->P, 2.0));
1679 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1680
1681 simCtx->step = 2;
1682 simCtx->ti = 0.2;
1683 PetscCall(SetUniformVelocityField(user, user->Ucat, 2.0, 0.0, 0.0));
1684 PetscCall(SetUniformScalarField(user, user->P, 5.0));
1685 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1686
1687 simCtx->step = 3;
1688 simCtx->ti = 0.3;
1689 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.25, 0.0, 0.0));
1690 PetscCall(SetUniformScalarField(user, user->P, 9.0));
1691 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1692
1693 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1694 PetscCall(PicurvAssertFileExists(log_path, "periodic solution-convergence logging should write the log"));
1695 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row1, sizeof(row1)));
1696 PetscCall(ReadLogHeaderAndRow(log_path, 2, header, sizeof(header), row2, sizeof(row2)));
1697 PetscCall(ReadLogHeaderAndRow(log_path, 3, header, sizeof(header), row3, sizeof(row3)));
1698 PetscCall(LogGetColumnInt(header, row1, "ref", &has_reference_1));
1699 PetscCall(LogGetColumnInt(header, row2, "ref", &has_reference_2));
1700 PetscCall(LogGetColumnInt(header, row3, "ref", &has_reference_3));
1701 PetscCall(LogGetColumnInt(header, row1, "ph", &phase_step_1));
1702 PetscCall(LogGetColumnInt(header, row2, "ph", &phase_step_2));
1703 PetscCall(LogGetColumnInt(header, row3, "ph", &phase_step_3));
1704 PetscCall(LogGetColumnReal(header, row3, "spd_ref", &mean_speed_ref_2));
1705 PetscCall(LogGetColumnReal(header, row3, "spd_abs", &mean_speed_abs_2));
1706
1707 PetscCall(PicurvAssertIntEqual(0, has_reference_1,
1708 "the first periodic phase visit should log warmup without a reference"));
1709 PetscCall(PicurvAssertIntEqual(0, has_reference_2,
1710 "the first periodic cycle should fully warm up before comparisons begin"));
1711 PetscCall(PicurvAssertIntEqual(1, has_reference_3,
1712 "the repeated periodic phase visit should compare against the stored reference"));
1713 PetscCall(PicurvAssertIntEqual(1, phase_step_1,
1714 "periodic solution convergence should log the current phase slot"));
1715 PetscCall(PicurvAssertIntEqual(0, phase_step_2,
1716 "periodic solution convergence should log distinct phase slots during warmup"));
1717 PetscCall(PicurvAssertIntEqual(1, phase_step_3,
1718 "periodic solution convergence should reuse the same phase slot on later cycles"));
1719 PetscCall(PicurvAssertRealNear(1.0, mean_speed_ref_2, 1.0e-12,
1720 "periodic solution convergence should report the stored phase-aligned reference"));
1721 PetscCall(PicurvAssertRealNear(0.25, mean_speed_abs_2, 1.0e-12,
1722 "periodic solution convergence should report the phase-aligned drift"));
1723
1724 PetscCall(PicurvRemoveTempDir(tmpdir));
1725 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1726 PetscFunctionReturn(0);
1727}
PetscInt solutionConvergencePeriodSteps
Definition variables.h:925
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:703
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSolutionConvergenceStatisticalLogging()

static PetscErrorCode TestSolutionConvergenceStatisticalLogging ( void  )
static

Tests statistical solution-convergence sliding-window metrics.

Definition at line 1732 of file test_logging.c.

1733{
1734 SimCtx *simCtx = NULL;
1735 UserCtx *user = NULL;
1736 char tmpdir[PETSC_MAX_PATH_LEN];
1737 char log_path[PETSC_MAX_PATH_LEN];
1738 char header[4096];
1739 char row[4096];
1740 PetscReal mean_speed_window = NAN;
1741 PetscReal mean_speed_window_prev = NAN;
1742 PetscReal mean_speed_window_abs = NAN;
1743 PetscReal mean_speed_rms_window = NAN;
1744 PetscReal mean_ke_window = NAN;
1745 PetscReal mean_ke_window_prev = NAN;
1746 PetscReal mean_ke_window_abs = NAN;
1747 PetscReal mean_ke_rms_window_abs = NAN;
1748 PetscInt has_reference = 0;
1749 const PetscReal speed_samples[4] = {1.0, 3.0, 2.0, 4.0};
1750
1751 PetscFunctionBeginUser;
1752 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1753 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1754 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1757
1758 PetscCall(InitializeSolutionConvergenceState(simCtx));
1759 for (PetscInt step = 0; step < 4; ++step) {
1760 simCtx->step = step + 1;
1761 simCtx->ti = 0.1 * (PetscReal)(step + 1);
1762 PetscCall(SetUniformVelocityField(user, user->Ucat, speed_samples[step], 0.0, 0.0));
1763 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1764 }
1765
1766 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1767 PetscCall(PicurvAssertFileExists(log_path, "statistical solution-convergence logging should write the log"));
1768 PetscCall(ReadLogHeaderAndRow(log_path, 4, header, sizeof(header), row, sizeof(row)));
1769 PetscCall(LogGetColumnInt(header, row, "ref", &has_reference));
1770 PetscCall(LogGetColumnReal(header, row, "spd_win", &mean_speed_window));
1771 PetscCall(LogGetColumnReal(header, row, "spd_win_prev", &mean_speed_window_prev));
1772 PetscCall(LogGetColumnReal(header, row, "spd_win_abs", &mean_speed_window_abs));
1773 PetscCall(LogGetColumnReal(header, row, "spd_rms_win", &mean_speed_rms_window));
1774 PetscCall(LogGetColumnReal(header, row, "ke_win", &mean_ke_window));
1775 PetscCall(LogGetColumnReal(header, row, "ke_win_prev", &mean_ke_window_prev));
1776 PetscCall(LogGetColumnReal(header, row, "ke_win_abs", &mean_ke_window_abs));
1777 PetscCall(LogGetColumnReal(header, row, "ke_rms_abs", &mean_ke_rms_window_abs));
1778
1779 PetscCall(PicurvAssertIntEqual(1, has_reference,
1780 "statistical solution convergence should emit adjacent-window drift once two windows exist"));
1781 PetscCall(PicurvAssertRealNear(3.0, mean_speed_window, 1.0e-12,
1782 "statistical solution convergence should report the current mean-speed window"));
1783 PetscCall(PicurvAssertRealNear(2.0, mean_speed_window_prev, 1.0e-12,
1784 "statistical solution convergence should report the previous mean-speed window"));
1785 PetscCall(PicurvAssertRealNear(1.0, mean_speed_window_abs, 1.0e-12,
1786 "statistical solution convergence should report mean-speed window drift"));
1787 PetscCall(PicurvAssertRealNear(1.0, mean_speed_rms_window, 1.0e-12,
1788 "statistical solution convergence should report current mean-speed RMS"));
1789 PetscCall(PicurvAssertRealNear(5.0, mean_ke_window, 1.0e-12,
1790 "statistical solution convergence should report the current kinetic-energy window"));
1791 PetscCall(PicurvAssertRealNear(2.5, mean_ke_window_prev, 1.0e-12,
1792 "statistical solution convergence should report the previous kinetic-energy window"));
1793 PetscCall(PicurvAssertRealNear(2.5, mean_ke_window_abs, 1.0e-12,
1794 "statistical solution convergence should report kinetic-energy window drift"));
1795 PetscCall(PicurvAssertRealNear(1.0, mean_ke_rms_window_abs, 1.0e-12,
1796 "statistical solution convergence should report RMS kinetic-energy drift"));
1797
1798 PetscCall(PicurvRemoveTempDir(tmpdir));
1799 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1800 PetscFunctionReturn(0);
1801}
PetscInt solutionConvergenceWindowSteps
Definition variables.h:926
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:704
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestSolutionConvergenceMeansExcludeGhostLayers()

static PetscErrorCode TestSolutionConvergenceMeansExcludeGhostLayers ( void  )
static

Regression test: convergence observables ignore the ghost layers of a walled box.

Interior cells carry speed 1 and every ghost layer carries speed 100, as a boundary-condition image may. The volume-averaged mean speed must be exactly 1: the loops once ran over the ghost layers too, which put wall images into every mean.

Definition at line 1809 of file test_logging.c.

1810{
1811 SimCtx *simCtx = NULL;
1812 UserCtx *user = NULL;
1813 char tmpdir[PETSC_MAX_PATH_LEN];
1814 char log_path[PETSC_MAX_PATH_LEN];
1815 char header[4096];
1816 char row[4096];
1817 PetscReal mean_speed = NAN;
1818 Cmpnts ***arr = NULL;
1819
1820 PetscFunctionBeginUser;
1821 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
1822 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1823 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1824 PetscCall(PicurvPopulateIdentityMetrics(user));
1825 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &arr));
1826 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
1827 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
1828 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
1829 const PetscBool ghost = (PetscBool)(i == 0 || j == 0 || k == 0 || i == user->info.mx - 1 ||
1830 j == user->info.my - 1 || k == user->info.mz - 1);
1831 arr[k][j][i].x = 0.0;
1832 arr[k][j][i].y = 0.0;
1833 arr[k][j][i].z = ghost ? 100.0 : 1.0;
1834 }
1835 }
1836 }
1837 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &arr));
1838
1840 PetscCall(InitializeSolutionConvergenceState(simCtx));
1841 simCtx->step = 1;
1842 simCtx->ti = 0.1;
1843 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1844
1845 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1846 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row, sizeof(row)));
1847 PetscCall(LogGetColumnReal(header, row, "mean_speed", &mean_speed));
1848 PetscCall(PicurvAssertRealNear(1.0, mean_speed, 1.0e-12,
1849 "mean speed must average physical cells only, not wall ghost images"));
1850
1851 PetscCall(PicurvRemoveTempDir(tmpdir));
1852 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1853 PetscFunctionReturn(0);
1854}
PetscErrorCode PicurvPopulateIdentityMetrics(UserCtx *user)
Populates identity metric vectors on the minimal grid fixture.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPeriodicSinusoidalMeanKE()

static PetscErrorCode TestPeriodicSinusoidalMeanKE ( void  )
static

Regression test: volume-averaged mean KE of a sinusoidal field in a fully periodic domain.

For u=0, v=0.1*sin(2πz), w=1 on a uniform [0,1]³ grid the exact continuous mean KE is 0.5025. With identity metrics (Aj=1) the discrete mean over the N physical cells also equals 0.5025 for any N >= 3, because Σ_{k=0}^{N-1} sin²(2πk/N) = N/2.

The physical cells are 1..mz-2. The ghost layers at 0 and mz-1 hold periodic copies of the opposite cells, so counting either one weights a cell twice. The loops once counted the upper ghost, and later still counted the lower one; this test requires both excluded.

Definition at line 1866 of file test_logging.c.

1867{
1868 const PetscInt km_values[] = {8, 16};
1869 const PetscInt n_cases = (PetscInt)(sizeof(km_values) / sizeof(km_values[0]));
1870
1871 PetscFunctionBeginUser;
1872 for (PetscInt t = 0; t < n_cases; ++t) {
1873 const PetscInt km = km_values[t];
1874 SimCtx *simCtx = NULL;
1875 UserCtx *user = NULL;
1876 char tmpdir[PETSC_MAX_PATH_LEN];
1877 char log_path[PETSC_MAX_PATH_LEN];
1878 char header[4096];
1879 char row[4096];
1880 PetscReal mean_ke = NAN;
1881
1882 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, km, km, km,
1883 PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
1884 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1885 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1886 PetscCall(PicurvPopulateIdentityMetrics(user));
1887 PetscCall(SetSinusoidalVZField(user, user->Ucat, 0.1, 1.0));
1888
1891 PetscCall(InitializeSolutionConvergenceState(simCtx));
1892
1893 simCtx->step = 1;
1894 simCtx->ti = 0.1;
1895 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1896
1897 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1898 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row, sizeof(row)));
1899 PetscCall(LogGetColumnReal(header, row, "mean_ke", &mean_ke));
1900 PetscCall(PicurvAssertRealNear(0.5025, mean_ke, 1.0e-10,
1901 "periodic sinusoidal field mean KE must equal 0.5025 (no duplicate endpoint)"));
1902
1903 PetscCall(PicurvRemoveTempDir(tmpdir));
1904 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1905 }
1906 PetscFunctionReturn(0);
1907}
static PetscErrorCode SetSinusoidalVZField(UserCtx *user, Vec field, PetscReal v_amp, PetscReal w_const)
Fills one Cartesian velocity field with u=0, v=v_amp*sin(2π*k/km), w=w_const.
PetscErrorCode PicurvCreateMinimalContextsWithPeriodicity(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz, PetscBool x_periodic, PetscBool y_periodic, PetscBool z_periodic)
Builds minimal SimCtx and UserCtx fixtures for C unit tests with configurable periodicity.
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-logging PETSc test binary.

Definition at line 1913 of file test_logging.c.

1914{
1915 PetscErrorCode ierr;
1916 const PicurvTestCase cases[] = {
1917 {"string-conversion-helpers", TestStringConversionHelpers},
1918 {"get-log-level-from-environment", TestGetLogLevelFromEnvironment},
1919 {"allowed-functions-filter", TestAllowedFunctionsFilter},
1920 {"particle-console-snapshot-cadence", TestParticleConsoleSnapshotCadence},
1921 {"statistics-console-snapshot-cadence", TestStatisticsConsoleSnapshotCadence},
1922 {"logging-file-parsing-and-formatting-helpers", TestLoggingFileParsingAndFormattingHelpers},
1923 {"logging-continuity-and-field-diagnostics", TestLoggingContinuityAndFieldDiagnostics},
1924 {"interpolation-error-logging", TestInterpolationErrorLogging},
1925 {"scatter-metrics-logging", TestScatterMetricsLogging},
1926 {"particle-field-table-logging", TestParticleFieldTableLogging},
1927 {"particle-console-snapshot-logging", TestParticleConsoleSnapshotLogging},
1928 {"statistics-console-snapshot-logging", TestStatisticsConsoleSnapshotLogging},
1929 {"console-cadence-does-not-change-accumulation", TestConsoleCadenceDoesNotChangeAccumulation},
1930 {"particle-metrics-logging", TestParticleMetricsLogging},
1931 {"search-metrics-logging", TestSearchMetricsLogging},
1932 {"field-anatomy-logging", TestFieldAnatomyLogging},
1933 {"profiling-lifecycle-helpers", TestProfilingLifecycleHelpers},
1934 {"runtime-memory-log-helpers", TestRuntimeMemoryLogHelpers},
1935 {"solution-convergence-disabled", TestSolutionConvergenceDisabled},
1936 {"solution-convergence-steady-logging", TestSolutionConvergenceSteadyLogging},
1937 {"solution-convergence-periodic-logging", TestSolutionConvergencePeriodicLogging},
1938 {"solution-convergence-statistical-logging", TestSolutionConvergenceStatisticalLogging},
1939 {"periodic-sinusoidal-mean-ke", TestPeriodicSinusoidalMeanKE},
1940 {"solution-convergence-means-exclude-ghost-layers", TestSolutionConvergenceMeansExcludeGhostLayers},
1941 };
1942
1943 (void)setenv("LOG_LEVEL", "INFO", 1);
1944
1945 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv logging tests");
1946 if (ierr) {
1947 return (int)ierr;
1948 }
1949
1950 ierr = PicurvRunTests("unit-logging", cases, sizeof(cases) / sizeof(cases[0]));
1951 if (ierr) {
1952 PetscFinalize();
1953 return (int)ierr;
1954 }
1955
1956 set_allowed_functions(NULL, 0);
1957
1958 ierr = PetscFinalize();
1959 return (int)ierr;
1960}
static PetscErrorCode TestParticleConsoleSnapshotCadence(void)
Tests periodic particle console snapshot enablement and cadence.
static PetscErrorCode TestFieldAnatomyLogging(void)
Tests stdout field-anatomy logging on the corrected production-like DM fixture.
static PetscErrorCode TestStatisticsConsoleSnapshotLogging(void)
Tests statistics console snapshot content, and its silence when disabled.
static PetscErrorCode TestParticleConsoleSnapshotLogging(void)
Tests console snapshot logging against the public periodic-snapshot helper.
static PetscErrorCode TestStatisticsConsoleSnapshotCadence(void)
Tests periodic statistics console snapshot enablement and cadence.
static PetscErrorCode TestGetLogLevelFromEnvironment(void)
Tests that log level selection honors the environment variable.
static PetscErrorCode TestLoggingContinuityAndFieldDiagnostics(void)
Tests continuity, min/max, and anatomy logging helpers on minimal runtime fixtures.
static PetscErrorCode TestPeriodicSinusoidalMeanKE(void)
Regression test: volume-averaged mean KE of a sinusoidal field in a fully periodic domain.
static PetscErrorCode TestSolutionConvergenceStatisticalLogging(void)
Tests statistical solution-convergence sliding-window metrics.
static PetscErrorCode TestSolutionConvergenceMeansExcludeGhostLayers(void)
Regression test: convergence observables ignore the ghost layers of a walled box.
static PetscErrorCode TestSolutionConvergencePeriodicLogging(void)
Tests periodic solution-convergence warmup and phase-aligned reference reuse.
static PetscErrorCode TestStringConversionHelpers(void)
Tests string-conversion helpers for configured enums and unknown values.
static PetscErrorCode TestLoggingFileParsingAndFormattingHelpers(void)
Tests logging-side file parsing, helper formatting, and progress utilities.
static PetscErrorCode TestAllowedFunctionsFilter(void)
Tests the function allow-list filter used by the logging layer.
static PetscErrorCode TestInterpolationErrorLogging(void)
Tests interpolation-error logging against an analytically matched particle field.
static PetscErrorCode TestScatterMetricsLogging(void)
Tests file-backed scatter metrics logging against a fully occupied constant field.
static PetscErrorCode TestParticleMetricsLogging(void)
Tests file-backed particle metrics logging after derived metrics are computed.
static PetscErrorCode TestSearchMetricsLogging(void)
Tests file-backed search metrics logging with the compact CSV contract.
static PetscErrorCode TestParticleFieldTableLogging(void)
Tests stdout particle-table logging on a production-like swarm fixture.
static PetscErrorCode TestSolutionConvergenceDisabled(void)
Verifies -solution_convergence_enabled=false suppresses the convergence writer.
static PetscErrorCode TestSolutionConvergenceSteadyLogging(void)
Tests steady solution-convergence log output, IBM masking, and gauge-invariant pressure drift.
static PetscErrorCode TestProfilingLifecycleHelpers(void)
Tests profiling helper lifecycle logging for timestep and final-summary outputs.
static PetscErrorCode TestConsoleCadenceDoesNotChangeAccumulation(void)
Tests that the console cadence has no effect on any accumulated result.
static PetscErrorCode TestRuntimeMemoryLogHelpers(void)
Tests runtime memory log header, step rows, final rows, and disabled mode.
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: