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 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:2752
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:139
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:103
PetscScalar z
Definition variables.h:103
DMDALocalInfo info
Definition variables.h:918
PetscScalar y
Definition variables.h:103
A 3D point or vector with PetscScalar components.
Definition variables.h:102
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 PetscInt km = user->KM;
616
617 PetscFunctionBeginUser;
618 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
619 PetscCheck(field != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Velocity field cannot be NULL.");
620
621 PetscCall(DMDAVecGetArray(user->fda, field, &arr));
622 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
623 PetscReal z_phase = (2.0 * PETSC_PI * (PetscReal)k) / (PetscReal)km;
624 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
625 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
626 arr[k][j][i].x = 0.0;
627 arr[k][j][i].y = v_amp * PetscSinReal(z_phase);
628 arr[k][j][i].z = w_const;
629 }
630 }
631 }
632 PetscCall(DMDAVecRestoreArray(user->fda, field, &arr));
633 PetscFunctionReturn(0);
634}
PetscInt KM
Definition variables.h:920
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 640 of file test_logging.c.

641{
642 PetscFunctionBeginUser;
643 PetscCall(PicurvAssertBool(strcmp(BCFaceToString(BC_FACE_NEG_X), "-Xi (I-Min)") == 0,
644 "BCFaceToString should report the negative-x face"));
645 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_ZERO), "Zero") == 0,
646 "InitialConditionModeToString should report the zero mode"));
647 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_CONSTANT_CARTESIAN), "Cartesian Constant") == 0,
648 "InitialConditionModeToString should report the Cartesian constant mode"));
649 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_CONSTANT_STREAMWISE), "Streamwise Constant") == 0,
650 "InitialConditionModeToString should report the streamwise constant mode"));
651 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_POISEUILLE), "Poiseuille") == 0,
652 "InitialConditionModeToString should report the Poiseuille mode"));
653 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString(IC_MODE_FILE), "File") == 0,
654 "InitialConditionModeToString should report the file mode"));
655 PetscCall(PicurvAssertBool(strcmp(InitialConditionModeToString((InitialConditionMode)99), "Unknown Initial Condition") == 0,
656 "InitialConditionModeToString should reject unknown selectors"));
658 "ParticleInitializationToString should report the volume mode"));
659 PetscCall(PicurvAssertBool(strcmp(LESModelToString(CONSTANT_SMAGORINSKY), "Constant Smagorinsky") == 0,
660 "LESModelToString should report the constant model"));
661 PetscCall(PicurvAssertBool(strcmp(MomentumSolverTypeToString(MOMENTUM_SOLVER_EXPLICIT_RK), "Explicit 4 stage Runge-Kutta ") == 0,
662 "MomentumSolverTypeToString should report the explicit solver"));
663 PetscCall(PicurvAssertBool(strcmp(MomentumSolverTypeToString(MOMENTUM_SOLVER_NEWTON_KRYLOV), "Newton Krylov") == 0,
664 "MomentumSolverTypeToString should report the Newton Krylov solver"));
665 PetscCall(PicurvAssertBool(strcmp(BCTypeToString(PERIODIC), "PERIODIC") == 0,
666 "BCTypeToString should report periodic boundaries"));
668 "BCHandlerTypeToString should report the driven periodic handler"));
669 PetscCall(PicurvAssertBool(strcmp(ParticleLocationStatusToString(LOST), "LOST") == 0,
670 "ParticleLocationStatusToString should report LOST state"));
671 PetscFunctionReturn(0);
672}
const char * BCHandlerTypeToString(BCHandlerType handler_type)
Converts a BCHandlerType enum to its string representation.
Definition logging.c:793
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:773
const char * ParticleLocationStatusToString(ParticleLocationStatus level)
A function that outputs the name of the current level in the ParticleLocation enum.
Definition logging.c:1858
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:757
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Returns the canonical log token for a particle-initialization mode.
Definition logging.c:724
@ CONSTANT_SMAGORINSKY
Definition variables.h:522
@ PERIODIC
Definition variables.h:292
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
Definition variables.h:553
@ LOST
Definition variables.h:141
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:318
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:535
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:537
InitialConditionMode
Selects the algorithm used to populate a fresh Eulerian velocity field.
Definition variables.h:151
@ IC_MODE_CONSTANT_CARTESIAN
Definition variables.h:153
@ IC_MODE_POISEUILLE
Definition variables.h:154
@ IC_MODE_CONSTANT_STREAMWISE
Definition variables.h:155
@ IC_MODE_FILE
Definition variables.h:156
@ IC_MODE_ZERO
Definition variables.h:152
@ BC_FACE_NEG_X
Definition variables.h:262
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 677 of file test_logging.c.

678{
679 PetscFunctionBeginUser;
681 "get_log_level should honor LOG_LEVEL=INFO in this test binary"));
682 PetscCall(print_log_level());
683 PetscFunctionReturn(0);
684}
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 689 of file test_logging.c.

690{
691 const char *allow_list[] = {"ComputeSpecificKE", "WriteEulerianFile"};
692
693 PetscFunctionBeginUser;
694 set_allowed_functions(allow_list, 2);
695 PetscCall(PicurvAssertBool(is_function_allowed("ComputeSpecificKE"),
696 "Allowed list should include ComputeSpecificKE"));
697 PetscCall(PicurvAssertBool((PetscBool)!is_function_allowed("UnlistedFunction"),
698 "Allowed list should exclude unknown function names"));
699
700 set_allowed_functions(NULL, 0);
701 PetscCall(PicurvAssertBool(is_function_allowed("AnyFunction"),
702 "Empty allow-list should permit all functions"));
703 PetscFunctionReturn(0);
704}
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 709 of file test_logging.c.

710{
711 SimCtx simCtx;
712
713 PetscFunctionBeginUser;
714 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
715 simCtx.np = 32;
716 simCtx.particleConsoleOutputFreq = 4;
717
719 "Particle snapshot contract should be enabled when particles and cadence are configured"));
721 "Snapshot should emit on cadence-aligned completed steps"));
722 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicParticleConsoleSnapshot(&simCtx, 7),
723 "Snapshot should not emit off-cadence"));
724
725 simCtx.particleConsoleOutputFreq = 0;
726 PetscCall(PicurvAssertBool((PetscBool)!IsParticleConsoleSnapshotEnabled(&simCtx),
727 "Zero cadence should disable periodic particle snapshots"));
728 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicParticleConsoleSnapshot(NULL, 4),
729 "NULL SimCtx should never emit periodic snapshots"));
730 PetscFunctionReturn(0);
731}
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:827
PetscInt particleConsoleOutputFreq
Definition variables.h:708
The master context for the entire simulation.
Definition variables.h:695
Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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 738 of file test_logging.c.

739{
740 PicurvWindowDefinition definition;
741
742 memset(&definition, 0, sizeof(definition));
743 strncpy(definition.name, "console_window", PICURV_WINDOW_NAME_LENGTH - 1);
746 definition.step_cadence = 1;
747 definition.bounded = PETSC_TRUE;
748 definition.end_time = 4.0;
749 definition.field_count = 1;
750 definition.fields[0].field_id = FIELD_ID_P;
751 return definition;
752}
@ 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 757 of file test_logging.c.

758{
759 SimCtx simCtx;
760 PicurvWindow window;
762
763 PetscFunctionBeginUser;
764 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
765 PetscCall(PicurvWindowInit(&window, &definition));
766 simCtx.fieldStatisticsEnabled = PETSC_TRUE;
768 simCtx.fieldStatisticsWindows = &window;
770
772 "Statistics snapshot contract should be enabled when a window and cadence are configured"));
774 "Snapshot should emit on cadence-aligned completed steps"));
775 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicStatisticsConsoleSnapshot(&simCtx, 7),
776 "Snapshot should not emit off-cadence"));
777 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicStatisticsConsoleSnapshot(&simCtx, -1),
778 "Snapshot should not emit for a step that has not completed"));
779
781 PetscCall(PicurvAssertBool((PetscBool)!IsStatisticsConsoleSnapshotEnabled(&simCtx),
782 "Zero cadence should disable periodic statistics snapshots"));
783 PetscCall(PicurvAssertBool((PetscBool)!ShouldEmitPeriodicStatisticsConsoleSnapshot(&simCtx, 0),
784 "Zero cadence should not emit even on the step that opens a run"));
785
786 /* The console cadence is a reporting contract layered on the subsystem gate: with
787 * nothing accumulating there is nothing to report, whatever the cadence says. */
790 PetscCall(PicurvAssertBool((PetscBool)!IsStatisticsConsoleSnapshotEnabled(&simCtx),
791 "A configured cadence should not enable snapshots without an accumulating window"));
792
794 simCtx.fieldStatisticsEnabled = PETSC_FALSE;
795 PetscCall(PicurvAssertBool((PetscBool)!IsStatisticsConsoleSnapshotEnabled(&simCtx),
796 "A disabled subsystem should not emit statistics snapshots"));
797
799 "NULL SimCtx should never emit periodic snapshots"));
800 PetscFunctionReturn(0);
801}
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:770
PetscInt statisticsConsoleOutputFreq
Definition variables.h:772
PetscBool fieldStatisticsEnabled
Definition variables.h:769
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:771
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 806 of file test_logging.c.

807{
808 char tmpdir[PETSC_MAX_PATH_LEN];
809 char allow_path[PETSC_MAX_PATH_LEN];
810 char dual_log_path[PETSC_MAX_PATH_LEN];
811 FILE *file = NULL;
812 char **funcs = NULL;
813 PetscInt nfuncs = 0;
814 Cell cell;
815 PetscReal distances[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
816 DualMonitorCtx *monctx = NULL;
817 void *ctx = NULL;
818
819 PetscFunctionBeginUser;
820 PetscCall(PetscMemzero(&cell, sizeof(cell)));
821 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
822 PetscCall(PetscSNPrintf(allow_path, sizeof(allow_path), "%s/allowed_functions.txt", tmpdir));
823 PetscCall(PetscSNPrintf(dual_log_path, sizeof(dual_log_path), "%s/dual-monitor.log", tmpdir));
824
825 file = fopen(allow_path, "w");
826 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to create allow-list file '%s'.", allow_path);
827 fputs(" ComputeSpecificKE \n", file);
828 fputs("# comment-only line\n", file);
829 for (PetscInt i = 0; i < 17; ++i) {
830 fprintf(file, "Helper_%02d # trailing comment\n", (int)i);
831 }
832 fclose(file);
833 file = NULL;
834
835 PetscCall(LoadAllowedFunctionsFromFile(allow_path, &funcs, &nfuncs));
836 PetscCall(PicurvAssertIntEqual(18, nfuncs, "LoadAllowedFunctionsFromFile should trim comments and keep all identifiers"));
837 PetscCall(PicurvAssertBool((PetscBool)(strcmp(funcs[0], "ComputeSpecificKE") == 0),
838 "LoadAllowedFunctionsFromFile should trim leading and trailing whitespace"));
839 PetscCall(PicurvAssertBool((PetscBool)(strcmp(funcs[17], "Helper_16") == 0),
840 "LoadAllowedFunctionsFromFile should grow past the initial pointer capacity"));
841 PetscCall(FreeAllowedFunctions(funcs, nfuncs));
842
843 for (PetscInt i = 0; i < 8; ++i) {
844 cell.vertices[i].x = (PetscReal)i;
845 cell.vertices[i].y = (PetscReal)(i + 1);
846 cell.vertices[i].z = (PetscReal)(i + 2);
847 }
848 PetscCall(LOG_CELL_VERTICES(&cell, 0));
849 PetscCall(LOG_FACE_DISTANCES(distances));
850
851 PetscCall(PetscCalloc1(1, &monctx));
852 monctx->file_handle = fopen(dual_log_path, "w");
853 PetscCheck(monctx->file_handle != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Failed to create dual-monitor log '%s'.", dual_log_path);
854 ctx = monctx;
855 PetscCall(DualMonitorDestroy(&ctx));
856 PetscCall(PicurvAssertBool((PetscBool)(ctx == NULL),
857 "DualMonitorDestroy should clear the caller-owned context pointer"));
858
859 PrintProgressBar(0, 0, 4, 0.10);
860 PrintProgressBar(3, 0, 4, 0.40);
861 PrintProgressBar(0, 0, 0, 0.00);
862 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
863
864 PetscCall(PicurvRemoveTempDir(tmpdir));
865 PetscFunctionReturn(0);
866}
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
Definition logging.c:831
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:2302
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:178
Defines the vertices of a single hexahedral grid cell.
Definition variables.h:177
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 871 of file test_logging.c.

872{
873 SimCtx *simCtx = NULL;
874 UserCtx *user = NULL;
875 char tmpdir[PETSC_MAX_PATH_LEN];
876 char continuity_path[PETSC_MAX_PATH_LEN];
877 PetscReal ***p = NULL;
878 Cmpnts ***ucat = NULL;
879 Cmpnts ***ucont = NULL;
880 PetscErrorCode ierr_minmax = 0;
881
882 PetscFunctionBeginUser;
883 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
884 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
885 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
886
887 simCtx->StartStep = 0;
888 simCtx->step = 1;
889 simCtx->MaxDiv = 1.25;
890 simCtx->MaxDivx = 1;
891 simCtx->MaxDivy = 2;
892 simCtx->MaxDivz = 3;
893 simCtx->MaxDivFlatArg = 17;
894 simCtx->summationRHS = 8.5;
895 simCtx->FluxInSum = 5.0;
896 simCtx->FluxOutSum = 3.25;
897 PetscCall(LOG_CONTINUITY_METRICS(user));
898
899 simCtx->step = 2;
900 simCtx->MaxDiv = 0.75;
901 simCtx->summationRHS = 4.5;
902 simCtx->FluxInSum = 2.5;
903 simCtx->FluxOutSum = 1.0;
904 PetscCall(LOG_CONTINUITY_METRICS(user));
905
906 PetscCall(PetscSNPrintf(continuity_path, sizeof(continuity_path), "%s/Continuity_Metrics.log", simCtx->log_dir));
907 PetscCall(PicurvAssertFileExists(continuity_path, "continuity metrics log should be written"));
908 PetscCall(AssertFileContains(continuity_path, "Timestep", "continuity metrics log should include the header"));
909 PetscCall(AssertFileContains(continuity_path, "([3][2][1] = 17)", "continuity metrics log should include the divergence location"));
910 PetscCall(AssertFileContains(continuity_path, "2 | 0", "continuity metrics log should append later timesteps"));
911
912 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
913 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
914 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &ucont));
915 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
916 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
917 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
918 p[k][j][i] = (PetscReal)(i + j + k);
919 ucat[k][j][i].x = (PetscReal)i;
920 ucat[k][j][i].y = (PetscReal)(-j);
921 ucat[k][j][i].z = (PetscReal)(2 * k);
922 ucont[k][j][i].x = (PetscReal)(10 + i);
923 ucont[k][j][i].y = (PetscReal)(20 + j);
924 ucont[k][j][i].z = (PetscReal)(30 + k);
925 }
926 }
927 }
928 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &ucont));
929 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
930 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
931
932 PetscCall(DMGlobalToLocalBegin(user->da, user->P, INSERT_VALUES, user->lP));
933 PetscCall(DMGlobalToLocalEnd(user->da, user->P, INSERT_VALUES, user->lP));
934 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
935 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
936 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
937 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
938
939 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_P));
940 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_UCAT));
941 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_COORDINATES));
942 PetscCall(LOG_FIELD_MIN_MAX(user, FIELD_ID_UCONT));
943
944 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
945 ierr_minmax = LOG_FIELD_MIN_MAX(user, FIELD_ID_INVALID);
946 PetscCall(PetscPopErrorHandler());
947 PetscCall(PicurvAssertBool((PetscBool)(ierr_minmax != 0),
948 "LOG_FIELD_MIN_MAX should reject invalid field IDs"));
949
950 PetscCall(PicurvRemoveTempDir(tmpdir));
951 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
952 PetscFunctionReturn(0);
953}
@ 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:2349
PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user)
Logs continuity metrics for a single block to a file.
Definition logging.c:1796
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:799
Vec Ucont
Definition variables.h:939
PetscInt StartStep
Definition variables.h:705
PetscReal MaxDiv
Definition variables.h:859
PetscInt MaxDivx
Definition variables.h:860
PetscInt MaxDivy
Definition variables.h:860
PetscInt MaxDivz
Definition variables.h:860
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:718
PetscInt MaxDivFlatArg
Definition variables.h:860
PetscReal FluxInSum
Definition variables.h:799
Vec Ucat
Definition variables.h:939
Vec lUcont
Definition variables.h:939
PetscInt step
Definition variables.h:703
Vec lUcat
Definition variables.h:939
PetscReal summationRHS
Definition variables.h:858
User-defined context containing data specific to a single computational grid level.
Definition variables.h:906
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestInterpolationErrorLogging()

static PetscErrorCode TestInterpolationErrorLogging ( void  )
static

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

Definition at line 958 of file test_logging.c.

959{
960 SimCtx *simCtx = NULL;
961 UserCtx *user = NULL;
962 PetscReal (*pos_arr)[3] = NULL;
963 PetscReal (*vel_arr)[3] = NULL;
964 Vec position_vec = NULL;
965 Vec analytical_vec = NULL;
966 const PetscScalar *analytical_arr = NULL;
967
968 PetscFunctionBeginUser;
969 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
970 PetscCall(PicurvCreateSwarmPair(user, 2, "ske"));
971 PetscCall(PetscStrncpy(simCtx->AnalyticalSolutionType, "TGV3D", sizeof(simCtx->AnalyticalSolutionType)));
972 simCtx->ren = 1.0;
973 simCtx->ti = 0.0;
974
975 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void *)&pos_arr));
976 pos_arr[0][0] = 0.5 * PETSC_PI; pos_arr[0][1] = 0.0; pos_arr[0][2] = 0.0;
977 pos_arr[1][0] = 0.0; pos_arr[1][1] = 0.5 * PETSC_PI; pos_arr[1][2] = 0.0;
978 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void *)&pos_arr));
979
980 PetscCall(DMSwarmCreateGlobalVectorFromField(user->swarm, "position", &position_vec));
981 PetscCall(VecDuplicate(position_vec, &analytical_vec));
982 PetscCall(VecCopy(position_vec, analytical_vec));
983 PetscCall(SetAnalyticalSolutionForParticles(analytical_vec, simCtx));
984
985 PetscCall(DMSwarmGetField(user->swarm, "velocity", NULL, NULL, (void *)&vel_arr));
986 PetscCall(VecGetArrayRead(analytical_vec, &analytical_arr));
987 for (PetscInt particle = 0; particle < 2; ++particle) {
988 vel_arr[particle][0] = PetscRealPart(analytical_arr[3 * particle + 0]);
989 vel_arr[particle][1] = PetscRealPart(analytical_arr[3 * particle + 1]);
990 vel_arr[particle][2] = PetscRealPart(analytical_arr[3 * particle + 2]);
991 }
992 PetscCall(VecRestoreArrayRead(analytical_vec, &analytical_arr));
993 PetscCall(DMSwarmRestoreField(user->swarm, "velocity", NULL, NULL, (void *)&vel_arr));
994
995 PetscCall(VecDestroy(&analytical_vec));
996 PetscCall(DMSwarmDestroyGlobalVectorFromField(user->swarm, "position", &position_vec));
997 PetscCall(LOG_INTERPOLATION_ERROR(user));
998 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
999 PetscFunctionReturn(0);
1000}
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:2865
PetscReal ren
Definition variables.h:744
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:729
PetscReal ti
Definition variables.h:704
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 1005 of file test_logging.c.

1006{
1007 SimCtx *simCtx = NULL;
1008 UserCtx *user = NULL;
1009 char tmpdir[PETSC_MAX_PATH_LEN];
1010 char metrics_path[PETSC_MAX_PATH_LEN];
1011 PetscReal *positions = NULL;
1012 PetscReal *psi = NULL;
1013 PetscInt *cell_ids = NULL;
1014 PetscInt *status = NULL;
1015 PetscInt particle = 0;
1016
1017 PetscFunctionBeginUser;
1018 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1019 PetscCall(PicurvCreateSwarmPair(user, 27, "ske"));
1020 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1021 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1022 simCtx->np = 27;
1023 simCtx->step = 3;
1024 simCtx->ti = 0.3;
1025 simCtx->verificationScalar.enabled = PETSC_TRUE;
1026 PetscCall(PetscStrncpy(simCtx->verificationScalar.mode,
1027 "analytical",
1028 sizeof(simCtx->verificationScalar.mode)));
1029 PetscCall(PetscStrncpy(simCtx->verificationScalar.profile,
1030 "CONSTANT",
1031 sizeof(simCtx->verificationScalar.profile)));
1032 simCtx->verificationScalar.value = 2.0;
1033
1034 PetscCall(DMSwarmGetField(user->swarm, "position", NULL, NULL, (void **)&positions));
1035 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
1036 PetscCall(DMSwarmGetField(user->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
1037 PetscCall(DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
1038
1039 for (PetscInt k = 0; k < 3; ++k) {
1040 for (PetscInt j = 0; j < 3; ++j) {
1041 for (PetscInt i = 0; i < 3; ++i) {
1042 positions[3 * particle + 0] = (i + 0.5) / 4.0;
1043 positions[3 * particle + 1] = (j + 0.5) / 4.0;
1044 positions[3 * particle + 2] = (k + 0.5) / 4.0;
1045 cell_ids[3 * particle + 0] = i;
1046 cell_ids[3 * particle + 1] = j;
1047 cell_ids[3 * particle + 2] = k;
1048 status[particle] = ACTIVE_AND_LOCATED;
1049 psi[particle] = 2.0;
1050 ++particle;
1051 }
1052 }
1053 }
1054
1055 PetscCall(DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&psi));
1056 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_location_status", NULL, NULL, (void **)&status));
1057 PetscCall(DMSwarmRestoreField(user->swarm, "DMSwarm_CellID", NULL, NULL, (void **)&cell_ids));
1058 PetscCall(DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void **)&positions));
1059
1061 PetscCall(LOG_SCATTER_METRICS(user));
1062
1063 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/scatter_metrics.csv", simCtx->log_dir));
1064 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_SCATTER_METRICS should write scatter_metrics.csv"));
1065 PetscCall(AssertFileContains(metrics_path, "relative_L2_error",
1066 "Scatter metrics CSV header should include relative_L2_error"));
1067 PetscCall(AssertFileContains(metrics_path,
1068 "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",
1069 "Scatter metrics CSV should record the expected constant-field zero-error row"));
1070
1071 PetscCall(PicurvRemoveTempDir(tmpdir));
1072 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1073 PetscFunctionReturn(0);
1074}
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:2944
VerificationScalarConfig verificationScalar
Definition variables.h:778
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 1079 of file test_logging.c.

1080{
1081 SimCtx *simCtx = NULL;
1082 UserCtx *user = NULL;
1083 PetscInt print_interval = 1;
1084 char captured[8192];
1085
1086 PetscFunctionBeginUser;
1087 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1088 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeParticleFieldLog, &print_interval, captured, sizeof(captured)));
1089 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Position (x,y,z)") != NULL),
1090 "LOG_PARTICLE_FIELDS should print the particle table header"));
1091 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Weights (a1,a2,a3)") != NULL),
1092 "LOG_PARTICLE_FIELDS should print the weight-column header"));
1093 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1094 PetscFunctionReturn(0);
1095}
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 1100 of file test_logging.c.

1101{
1102 SimCtx *simCtx = NULL;
1103 UserCtx *user = NULL;
1104 PetscInt step = 4;
1105 char captured[8192];
1106
1107 PetscFunctionBeginUser;
1108 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1109 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeParticleConsoleSnapshot, &step, captured, sizeof(captured)));
1110 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Particle states at step 4") != NULL),
1111 "EmitParticleConsoleSnapshot should print the step banner"));
1112 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Position (x,y,z)") != NULL),
1113 "EmitParticleConsoleSnapshot should reuse the particle table output"));
1114 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1115 PetscFunctionReturn(0);
1116}
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 1126 of file test_logging.c.

1127{
1128 SimCtx *simCtx = NULL;
1129 UserCtx *user = NULL;
1130 PicurvWindow window;
1131 PicurvWindowStorage storage;
1133 PetscInt step = 2;
1134 char captured[8192];
1135
1136 PetscFunctionBeginUser;
1137 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1138 PetscCall(VecSet(user->Nvert, 0.0));
1139 PetscCall(PicurvWindowInit(&window, &definition));
1140 PetscCall(PicurvWindowStorageCreate(user, &definition, &storage));
1141
1142 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
1143 simCtx->fieldStatisticsWindowCount = 1;
1144 simCtx->fieldStatisticsWindows = &window;
1145 simCtx->statisticsConsoleOutputFreq = 1;
1146 user->fieldStatisticsStorage = &storage;
1147
1148 /* Step 0 anchors the origin without sampling; steps 1 and 2 each represent one
1149 * unit of time, so the snapshot has two accepted samples to report. */
1150 for (PetscInt offered = 0; offered <= step; ++offered) {
1151 PetscCall(FieldStatisticsUpdateWindows(simCtx, offered, (PetscReal)offered));
1152 }
1153
1154 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeStatisticsConsoleSnapshot, &step,
1155 captured, sizeof(captured)));
1156 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Statistics windows at step 2") != NULL),
1157 "EmitStatisticsConsoleSnapshot should print the step banner"));
1158 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "console_window") != NULL),
1159 "EmitStatisticsConsoleSnapshot should name each configured window"));
1160 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "samples=2") != NULL),
1161 "EmitStatisticsConsoleSnapshot should report the accepted sample count"));
1162 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "valid=[") != NULL),
1163 "EmitStatisticsConsoleSnapshot should report mask coverage once storage carries samples"));
1164
1165 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
1166 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeStatisticsConsoleSnapshot, &step,
1167 captured, sizeof(captured)));
1168 PetscCall(PicurvAssertIntEqual(0, (PetscInt)strlen(captured),
1169 "a disabled subsystem emits no statistics console output"));
1170
1171 simCtx->fieldStatisticsWindows = NULL;
1172 simCtx->fieldStatisticsWindowCount = 0;
1173 user->fieldStatisticsStorage = NULL;
1174 PetscCall(PicurvWindowStorageDestroy(&storage));
1175 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1176 PetscFunctionReturn(0);
1177}
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:962
Vec Nvert
Definition variables.h:939
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 1181 of file test_logging.c.

1182{
1183 PetscReal ***p = NULL;
1184 const DMDALocalInfo info = user->info;
1185
1186 PetscFunctionBeginUser;
1187 PetscCall(DMDAVecGetArray(user->da, user->P, &p));
1188 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k)
1189 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j)
1190 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) p[k][j][i] = value;
1191 PetscCall(DMDAVecRestoreArray(user->da, user->P, &p));
1192 PetscFunctionReturn(0);
1193}
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 1200 of file test_logging.c.

1205{
1206 PetscFunctionBeginUser;
1207 PetscCall(PicurvWindowInit(window, definition));
1208 simCtx->fieldStatisticsEnabled = PETSC_TRUE;
1209 simCtx->fieldStatisticsWindowCount = 1;
1210 simCtx->fieldStatisticsWindows = window;
1211 simCtx->statisticsConsoleOutputFreq = console_frequency;
1212 user->fieldStatisticsStorage = storage;
1213
1214 for (PetscInt step = 0; step <= 3; ++step) {
1215 PetscCall(SetUniformPressure(user, 1.0 + (PetscReal)step));
1216 PetscCall(FieldStatisticsUpdateWindows(simCtx, step, (PetscReal)step));
1218 PetscCall(EmitStatisticsConsoleSnapshot(user, simCtx, step));
1219 }
1220 }
1221 PetscFunctionReturn(0);
1222}
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 1226 of file test_logging.c.

1227{
1228 PetscBool equal = PETSC_FALSE;
1229
1230 PetscFunctionBeginUser;
1231 PetscCall(VecEqual(expected, actual, &equal));
1232 PetscCall(PicurvAssertBool(equal, context));
1233 PetscFunctionReturn(0);
1234}
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 1245 of file test_logging.c.

1246{
1247 SimCtx *simCtx = NULL;
1248 UserCtx *user = NULL;
1249 PicurvWindow reported, silent;
1250 PicurvWindowStorage reported_storage, silent_storage;
1252 char captured[8192];
1253 PetscInt step = 3;
1254
1255 PetscFunctionBeginUser;
1256 definition.fields[0].want_second = PETSC_TRUE;
1257 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1258 PetscCall(VecSet(user->Nvert, 0.0));
1259 PetscCall(PicurvWindowStorageCreate(user, &definition, &reported_storage));
1260 PetscCall(PicurvWindowStorageCreate(user, &definition, &silent_storage));
1261
1262 PetscCall(AccumulateAtConsoleCadence(simCtx, user, &reported, &reported_storage, &definition, 1));
1263 PetscCall(AccumulateAtConsoleCadence(simCtx, user, &silent, &silent_storage, &definition, 0));
1264
1265 PetscCall(PicurvAssertIntEqual(reported.sample_count, silent.sample_count,
1266 "both cadences accept the same states"));
1267 PetscCall(PicurvAssertRealNear(reported.total_weight, silent.total_weight, 0.0,
1268 "both cadences accumulate the same total weight"));
1269 PetscCall(AssertVecsIdentical(reported_storage.count, silent_storage.count,
1270 "per-point sample counts are independent of the console cadence"));
1271 PetscCall(AssertVecsIdentical(reported_storage.weight, silent_storage.weight,
1272 "per-point weights are independent of the console cadence"));
1273 PetscCall(AssertVecsIdentical(reported_storage.mean[0], silent_storage.mean[0],
1274 "means are independent of the console cadence"));
1275 PetscCall(AssertVecsIdentical(reported_storage.m2[0], silent_storage.m2[0],
1276 "second moments are independent of the console cadence"));
1277
1278 /* The reporting cadence did drive real output, so the comparison above compared a
1279 * reported run against a silent one rather than two silent ones. */
1280 simCtx->statisticsConsoleOutputFreq = 1;
1281 simCtx->fieldStatisticsWindows = &reported;
1282 user->fieldStatisticsStorage = &reported_storage;
1283 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeStatisticsConsoleSnapshot, &step,
1284 captured, sizeof(captured)));
1285 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "console_window") != NULL),
1286 "the reporting cadence emits console output at this log level"));
1287
1288 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
1289 simCtx->fieldStatisticsWindows = NULL;
1290 simCtx->fieldStatisticsWindowCount = 0;
1291 user->fieldStatisticsStorage = NULL;
1292 PetscCall(PicurvWindowStorageDestroy(&silent_storage));
1293 PetscCall(PicurvWindowStorageDestroy(&reported_storage));
1294 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1295 PetscFunctionReturn(0);
1296}
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 1301 of file test_logging.c.

1302{
1303 SimCtx *simCtx = NULL;
1304 UserCtx *user = NULL;
1305 char tmpdir[PETSC_MAX_PATH_LEN];
1306 char metrics_path[PETSC_MAX_PATH_LEN];
1307
1308 PetscFunctionBeginUser;
1309 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1310 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1311 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1312 simCtx->StartStep = 0;
1313 simCtx->step = 1;
1314 simCtx->particlesLostLastStep = 1;
1315 simCtx->particlesLostCumulative = 7;
1316 simCtx->particlesMigratedLastStep = 2;
1317 simCtx->migrationPassesLastStep = 3;
1318
1319 PetscCall(CalculateParticleCountPerCell(user));
1320 PetscCall(CalculateAdvancedParticleMetrics(user));
1321 PetscCall(LOG_PARTICLE_METRICS(user, "Timestep Metrics"));
1322
1323 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/Particle_Metrics.log", simCtx->log_dir));
1324 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_PARTICLE_METRICS should write Particle_Metrics.log"));
1325 PetscCall(AssertFileContains(metrics_path, "Timestep Metrics", "Particle metrics log should include the caller-provided stage label"));
1326 PetscCall(AssertFileContains(metrics_path, "Occupied Cells", "Particle metrics log should include the metrics table header"));
1327 PetscCall(AssertFileContains(metrics_path, "Lost Total", "Particle metrics log should include the cumulative-loss column"));
1328 PetscCall(AssertFileContains(metrics_path, "| 1 | 7 | 2", "Particle metrics log should record both per-step and cumulative loss values"));
1329 PetscCall(PicurvRemoveTempDir(tmpdir));
1330 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1331 PetscFunctionReturn(0);
1332}
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:3337
PetscErrorCode CalculateAdvancedParticleMetrics(UserCtx *user)
Computes advanced particle statistics and stores them in SimCtx.
Definition logging.c:3283
PetscInt particlesLostLastStep
Definition variables.h:834
PetscInt particlesLostCumulative
Definition variables.h:835
PetscInt particlesMigratedLastStep
Definition variables.h:837
PetscInt migrationPassesLastStep
Definition variables.h:836
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 1337 of file test_logging.c.

1338{
1339 SimCtx *simCtx = NULL;
1340 UserCtx *user = NULL;
1341 char tmpdir[PETSC_MAX_PATH_LEN];
1342 char metrics_path[PETSC_MAX_PATH_LEN];
1343
1344 PetscFunctionBeginUser;
1345 PetscCall(SeedLoggingParticleFixture(&simCtx, &user));
1346 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1347 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1348 simCtx->step = 2;
1349 simCtx->ti = 0.2;
1350 simCtx->particlesLostLastStep = 1;
1351 simCtx->particlesLostCumulative = 7;
1352 simCtx->particlesMigratedLastStep = 2;
1353 simCtx->migrationPassesLastStep = 3;
1354 simCtx->particleLoadImbalance = 1.5;
1355 simCtx->searchMetrics.searchAttempts = 4;
1356 simCtx->searchMetrics.searchPopulation = 2;
1358 simCtx->searchMetrics.searchLostCount = 1;
1359 simCtx->searchMetrics.traversalStepsSum = 10;
1360 simCtx->searchMetrics.reSearchCount = 2;
1361 simCtx->searchMetrics.maxTraversalSteps = 6;
1363 simCtx->searchMetrics.tieBreakCount = 1;
1368
1369 PetscCall(LOG_SEARCH_METRICS(user));
1370
1371 PetscCall(PetscSNPrintf(metrics_path, sizeof(metrics_path), "%s/search_metrics.csv", simCtx->log_dir));
1372 PetscCall(PicurvAssertFileExists(metrics_path, "LOG_SEARCH_METRICS should write search_metrics.csv"));
1373 PetscCall(AssertFileContains(metrics_path, "search_attempts", "Search metrics CSV header should include search_attempts"));
1374 PetscCall(AssertFileContains(metrics_path, "search_population", "Search metrics CSV header should include search_population"));
1375 PetscCall(AssertFileContains(metrics_path, "max_particle_pass_depth", "Search metrics CSV header should include max_particle_pass_depth"));
1376 PetscCall(AssertFileContains(metrics_path, "search_work_index", "Search metrics CSV header should include search_work_index"));
1377 PetscCall(AssertFileContains(metrics_path, "re_search_fraction", "Search metrics CSV header should include re_search_fraction"));
1378 PetscCall(AssertFileContains(metrics_path, "lost_cumulative", "Search metrics CSV header should include the cumulative-loss column"));
1379 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"));
1380 PetscCall(PicurvRemoveTempDir(tmpdir));
1381 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1382 PetscFunctionReturn(0);
1383}
PetscErrorCode LOG_SEARCH_METRICS(UserCtx *user)
Writes compact runtime search metrics to CSV and optionally to console.
Definition logging.c:3129
PetscInt64 searchLocatedCount
Definition variables.h:241
PetscInt64 searchLostCount
Definition variables.h:242
PetscInt64 boundaryClampCount
Definition variables.h:248
PetscInt64 traversalStepsSum
Definition variables.h:243
PetscInt64 searchPopulation
Definition variables.h:240
PetscInt64 reSearchCount
Definition variables.h:244
PetscInt64 bboxGuessFallbackCount
Definition variables.h:250
PetscInt64 bboxGuessSuccessCount
Definition variables.h:249
PetscInt64 maxParticlePassDepth
Definition variables.h:251
PetscInt64 maxTraversalSteps
Definition variables.h:245
SearchMetricsState searchMetrics
Definition variables.h:840
PetscInt64 searchAttempts
Definition variables.h:239
PetscInt64 tieBreakCount
Definition variables.h:247
PetscInt64 maxTraversalFailCount
Definition variables.h:246
PetscReal particleLoadImbalance
Definition variables.h:839
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 1388 of file test_logging.c.

1389{
1390 SimCtx *simCtx = NULL;
1391 UserCtx *user = NULL;
1392 char captured[8192];
1393 AnatomyCaptureCtx anatomy_ctx = {FIELD_ID_P, "unit-test"};
1394
1395 PetscFunctionBeginUser;
1396 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1397 PetscCall(VecSet(user->P, 7.0));
1398 PetscCall(DMGlobalToLocalBegin(user->da, user->P, INSERT_VALUES, user->lP));
1399 PetscCall(DMGlobalToLocalEnd(user->da, user->P, INSERT_VALUES, user->lP));
1400 PetscCall(CaptureLoggingOutput(user, simCtx, InvokeFieldAnatomyLog, &anatomy_ctx, captured, sizeof(captured)));
1401 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Field Anatomy Log: [P]") != NULL),
1402 "LOG_FIELD_ANATOMY should print the requested field name"));
1403 PetscCall(PicurvAssertBool((PetscBool)(strstr(captured, "Layout: [Cell-Centered]") != NULL),
1404 "LOG_FIELD_ANATOMY should report the inferred data layout"));
1405 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1406 PetscFunctionReturn(0);
1407}
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 1412 of file test_logging.c.

1413{
1414 SimCtx simCtx;
1415 char tmpdir[PETSC_MAX_PATH_LEN];
1416 char timestep_path[PETSC_MAX_PATH_LEN];
1417 char summary_path[PETSC_MAX_PATH_LEN];
1418 static char selected_name[] = "FlowSolver";
1419 char *selected_funcs[] = {selected_name};
1420
1421 PetscFunctionBeginUser;
1422 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
1423 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1424 PetscCall(PetscStrncpy(simCtx.log_dir, tmpdir, sizeof(simCtx.log_dir)));
1425 PetscCall(PetscStrncpy(simCtx.profilingTimestepMode, "selected", sizeof(simCtx.profilingTimestepMode)));
1426 PetscCall(PetscStrncpy(simCtx.profilingTimestepFile, "Profiling_Timestep_Summary.csv", sizeof(simCtx.profilingTimestepFile)));
1427 simCtx.rank = 0;
1428 simCtx.exec_mode = EXEC_MODE_SOLVER;
1429 simCtx.StartStep = 0;
1430 simCtx.nProfilingSelectedFuncs = 1;
1431 simCtx.profilingSelectedFuncs = selected_funcs;
1432 simCtx.profilingFinalSummary = PETSC_TRUE;
1433
1434 PetscCall(ProfilingInitialize(&simCtx));
1435
1436 _ProfilingStart("FlowSolver");
1437 _ProfilingEnd("FlowSolver");
1438 _ProfilingStart("UnselectedHelper");
1439 _ProfilingEnd("UnselectedHelper");
1440 PetscCall(ProfilingLogTimestepSummary(&simCtx, 1));
1441
1442 _ProfilingStart("FlowSolver");
1443 _ProfilingEnd("FlowSolver");
1444 PetscCall(ProfilingResetTimestepCounters());
1445 PetscCall(ProfilingLogTimestepSummary(&simCtx, 2));
1446 PetscCall(ProfilingFinalize(&simCtx));
1447
1448 PetscCall(PetscSNPrintf(timestep_path, sizeof(timestep_path), "%s/%s", simCtx.log_dir, simCtx.profilingTimestepFile));
1449 PetscCall(PetscSNPrintf(summary_path, sizeof(summary_path), "%s/ProfilingSummary_Solver.log", simCtx.log_dir));
1450 PetscCall(PicurvAssertFileExists(timestep_path, "profiling timestep summary should be written"));
1451 PetscCall(PicurvAssertFileExists(summary_path, "profiling final summary should be written"));
1452 PetscCall(AssertFileContains(timestep_path, "step,function,calls,step_time_s",
1453 "profiling timestep summary should contain the CSV header"));
1454 PetscCall(AssertFileContains(timestep_path, "1,FlowSolver,1,",
1455 "profiling timestep summary should log selected functions"));
1456 PetscCall(AssertFileNotContains(timestep_path, "UnselectedHelper",
1457 "profiling timestep summary should omit unselected functions in selected mode"));
1458 PetscCall(AssertFileContains(summary_path, "FINAL PROFILING SUMMARY",
1459 "profiling final summary should include its table banner"));
1460 PetscCall(AssertFileContains(summary_path, "FlowSolver",
1461 "profiling final summary should include selected functions"));
1462 PetscCall(AssertFileContains(summary_path, "UnselectedHelper",
1463 "profiling final summary should include total-time entries for unselected functions"));
1464 PetscCall(PicurvRemoveTempDir(tmpdir));
1465 PetscFunctionReturn(0);
1466}
PetscErrorCode ProfilingFinalize(SimCtx *simCtx)
the profiling excercise and build a profiling summary which is then printed to a log file.
Definition logging.c:2196
PetscErrorCode ProfilingLogTimestepSummary(SimCtx *simCtx, PetscInt step)
Logs the performance summary for the current timestep and resets timers.
Definition logging.c:2005
void _ProfilingEnd(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_END.
Definition logging.c:1966
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:1928
PetscErrorCode ProfilingResetTimestepCounters(void)
Resets per-timestep profiling counters for the next solver step.
Definition logging.c:1988
void _ProfilingStart(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.
Definition logging.c:1952
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:868
PetscMPIInt rank
Definition variables.h:698
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:867
char profilingTimestepMode[32]
Definition variables.h:866
char ** profilingSelectedFuncs
Definition variables.h:864
PetscInt nProfilingSelectedFuncs
Definition variables.h:865
@ EXEC_MODE_SOLVER
Definition variables.h:668
ExecutionMode exec_mode
Definition variables.h:714
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 1471 of file test_logging.c.

1472{
1473 SimCtx simCtx;
1474 char tmpdir[PETSC_MAX_PATH_LEN];
1475 char memory_path[PETSC_MAX_PATH_LEN];
1476
1477 PetscFunctionBeginUser;
1478 PetscCall(PetscMemzero(&simCtx, sizeof(simCtx)));
1479 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1480 PetscCall(PetscStrncpy(simCtx.log_dir, tmpdir, sizeof(simCtx.log_dir)));
1481 PetscCall(PetscStrncpy(simCtx.runtimeMemoryLogFile, "Runtime_Memory.log", sizeof(simCtx.runtimeMemoryLogFile)));
1482 simCtx.rank = 0;
1483 simCtx.runtimeMemoryLogEnabled = PETSC_TRUE;
1484 simCtx.runtimeMemoryLogStarted = PETSC_FALSE;
1485 simCtx.runtimeMemoryLogHasPrevious = PETSC_FALSE;
1486 simCtx.continueMode = PETSC_FALSE;
1487 simCtx.StartStep = 0;
1488 PetscCall(PetscMemorySetGetMaximumUsage());
1489
1490 PetscCall(RuntimeMemoryLogSample(&simCtx, 1, "Step", "-"));
1491 PetscCall(RuntimeMemoryLogSample(&simCtx, 1, "Final", "Complete"));
1492 PetscCall(PetscSNPrintf(memory_path, sizeof(memory_path), "%s/%s", simCtx.log_dir, simCtx.runtimeMemoryLogFile));
1493 PetscCall(PicurvAssertFileExists(memory_path, "runtime memory log should be written"));
1494 PetscCall(AssertFileContains(memory_path, "Process Current MB Max",
1495 "runtime memory log should contain readable column labels"));
1496 PetscCall(AssertFileContains(memory_path, "Step",
1497 "runtime memory log should contain a step row"));
1498 PetscCall(AssertFileContains(memory_path, "Final",
1499 "runtime memory log should contain a final row"));
1500 PetscCall(AssertFileContains(memory_path, "Complete",
1501 "runtime memory log should record final reason"));
1502
1503 simCtx.runtimeMemoryLogEnabled = PETSC_FALSE;
1504 PetscCall(PetscStrncpy(simCtx.runtimeMemoryLogFile, "Runtime_Memory_Disabled.log", sizeof(simCtx.runtimeMemoryLogFile)));
1505 PetscCall(RuntimeMemoryLogSample(&simCtx, 2, "Step", "-"));
1506 PetscCall(PetscSNPrintf(memory_path, sizeof(memory_path), "%s/%s", simCtx.log_dir, simCtx.runtimeMemoryLogFile));
1507 PetscCall(PicurvAssertBool((PetscBool)(access(memory_path, F_OK) != 0),
1508 "disabled runtime memory log should not create a file"));
1509 PetscCall(PicurvRemoveTempDir(tmpdir));
1510 PetscFunctionReturn(0);
1511}
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:2086
PetscBool continueMode
Definition variables.h:712
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:883
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:884
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
Definition variables.h:885
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
Definition variables.h:886
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 1516 of file test_logging.c.

1517{
1518 SimCtx *simCtx = NULL;
1519 UserCtx *user = NULL;
1520 char tmpdir[PETSC_MAX_PATH_LEN];
1521 char log_path[PETSC_MAX_PATH_LEN];
1522 PetscBool exists = PETSC_FALSE;
1523
1524 PetscFunctionBeginUser;
1525 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1526 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1527 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1528 simCtx->solutionConvergenceEnabled = PETSC_FALSE;
1529
1530 PetscCall(InitializeSolutionConvergenceState(simCtx));
1531 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1532 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1533 PetscCall(PetscTestFile(log_path, 'r', &exists));
1534 PetscCall(PicurvAssertBool((PetscBool)!exists,
1535 "disabled solution convergence must not create a log"));
1536
1537 PetscCall(PicurvRemoveTempDir(tmpdir));
1538 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1539 PetscFunctionReturn(0);
1540}
PetscErrorCode LOG_SOLUTION_CONVERGENCE(SimCtx *simCtx)
Logs physical solution-convergence metrics once per completed timestep.
Definition logging.c:1600
PetscErrorCode InitializeSolutionConvergenceState(SimCtx *simCtx)
Allocates any runtime storage required by solution-convergence logging.
Definition setup.c:49
PetscBool solutionConvergenceEnabled
Definition variables.h:761
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 1545 of file test_logging.c.

1546{
1547 SimCtx *simCtx = NULL;
1548 UserCtx *user = NULL;
1549 char tmpdir[PETSC_MAX_PATH_LEN];
1550 char log_path[PETSC_MAX_PATH_LEN];
1551 char header[4096];
1552 char row1[4096];
1553 char row2[4096];
1554 char mode[128];
1555 Cmpnts ***ucat = NULL;
1556 PetscReal ***nvert = NULL;
1557 PetscReal mean_speed = NAN;
1558 PetscReal mean_speed_ref = NAN;
1559 PetscReal mean_speed_abs = NAN;
1560 PetscReal p_abs = NAN;
1561 PetscInt has_reference_1 = 0;
1562 PetscInt has_reference_2 = 0;
1563
1564 PetscFunctionBeginUser;
1565 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1566 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1567 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1569
1570 PetscCall(InitializeSolutionConvergenceState(simCtx));
1571
1572 simCtx->step = 1;
1573 simCtx->ti = 0.1;
1574 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.0, 0.0, 0.0));
1575 PetscCall(SetUniformScalarField(user, user->P, 11.0));
1576 PetscCall(DMDAVecGetArray(user->da, user->Nvert, &nvert));
1577 nvert[1][1][1] = 1.0;
1578 PetscCall(DMDAVecRestoreArray(user->da, user->Nvert, &nvert));
1579 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
1580 ucat[1][1][1].x = 999.0;
1581 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
1582 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1583
1584 simCtx->step = 2;
1585 simCtx->ti = 0.2;
1586 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.0, 0.0, 0.0));
1587 PetscCall(SetUniformVelocityField(user, user->Ucat_o, 0.5, 0.0, 0.0));
1588 PetscCall(SetUniformScalarField(user, user->P, 11.0));
1589 PetscCall(SetUniformScalarField(user, user->P_o, 7.0));
1590 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
1591 ucat[1][1][1].x = 999.0;
1592 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
1593 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1594
1595 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1596 PetscCall(PicurvAssertFileExists(log_path, "steady solution-convergence logging should write the log"));
1597 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row1, sizeof(row1)));
1598 PetscCall(ReadLogHeaderAndRow(log_path, 2, header, sizeof(header), row2, sizeof(row2)));
1599 PetscCall(LogGetColumnText(header, row1, "mode", mode, sizeof(mode)));
1600 PetscCall(LogGetColumnInt(header, row1, "ref", &has_reference_1));
1601 PetscCall(LogGetColumnInt(header, row2, "ref", &has_reference_2));
1602 PetscCall(LogGetColumnReal(header, row2, "mean_speed", &mean_speed));
1603 PetscCall(LogGetColumnReal(header, row2, "spd_ref", &mean_speed_ref));
1604 PetscCall(LogGetColumnReal(header, row2, "spd_abs", &mean_speed_abs));
1605 PetscCall(LogGetColumnReal(header, row2, "p_abs_l2", &p_abs));
1606
1607 PetscCall(PicurvAssertBool((PetscBool)(strcmp(mode, "steady_deterministic") == 0),
1608 "steady solution convergence row should record the mode name"));
1609 PetscCall(PicurvAssertIntEqual(0, has_reference_1,
1610 "the first steady solution-convergence row should be a warmup row"));
1611 PetscCall(PicurvAssertIntEqual(1, has_reference_2,
1612 "steady solution convergence should compare against the previous solved step"));
1613 PetscCall(PicurvAssertRealNear(1.0, mean_speed, 1.0e-12,
1614 "steady solution convergence should mask IBM-marked solid cells"));
1615 PetscCall(PicurvAssertRealNear(0.5, mean_speed_ref, 1.0e-12,
1616 "steady solution convergence should report the previous-step mean speed"));
1617 PetscCall(PicurvAssertRealNear(0.5, mean_speed_abs, 1.0e-12,
1618 "steady solution convergence should report mean-speed drift"));
1619 PetscCall(PicurvAssertRealNear(0.0, p_abs, 1.0e-12,
1620 "steady solution convergence pressure drift should be gauge invariant"));
1621
1622 PetscCall(PicurvRemoveTempDir(tmpdir));
1623 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1624 PetscFunctionReturn(0);
1625}
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:946
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:544
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:762
Vec P_o
Definition variables.h:946
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 1630 of file test_logging.c.

1631{
1632 SimCtx *simCtx = NULL;
1633 UserCtx *user = NULL;
1634 char tmpdir[PETSC_MAX_PATH_LEN];
1635 char log_path[PETSC_MAX_PATH_LEN];
1636 char header[4096];
1637 char row1[4096];
1638 char row2[4096];
1639 char row3[4096];
1640 PetscInt has_reference_1 = 0;
1641 PetscInt has_reference_2 = 0;
1642 PetscInt has_reference_3 = 0;
1643 PetscInt phase_step_1 = -1;
1644 PetscInt phase_step_2 = -1;
1645 PetscInt phase_step_3 = -1;
1646 PetscReal mean_speed_ref_2 = NAN;
1647 PetscReal mean_speed_abs_2 = NAN;
1648
1649 PetscFunctionBeginUser;
1650 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1651 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1652 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1655
1656 PetscCall(InitializeSolutionConvergenceState(simCtx));
1657
1658 simCtx->step = 1;
1659 simCtx->ti = 0.1;
1660 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.0, 0.0, 0.0));
1661 PetscCall(SetUniformScalarField(user, user->P, 2.0));
1662 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1663
1664 simCtx->step = 2;
1665 simCtx->ti = 0.2;
1666 PetscCall(SetUniformVelocityField(user, user->Ucat, 2.0, 0.0, 0.0));
1667 PetscCall(SetUniformScalarField(user, user->P, 5.0));
1668 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1669
1670 simCtx->step = 3;
1671 simCtx->ti = 0.3;
1672 PetscCall(SetUniformVelocityField(user, user->Ucat, 1.25, 0.0, 0.0));
1673 PetscCall(SetUniformScalarField(user, user->P, 9.0));
1674 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1675
1676 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1677 PetscCall(PicurvAssertFileExists(log_path, "periodic solution-convergence logging should write the log"));
1678 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row1, sizeof(row1)));
1679 PetscCall(ReadLogHeaderAndRow(log_path, 2, header, sizeof(header), row2, sizeof(row2)));
1680 PetscCall(ReadLogHeaderAndRow(log_path, 3, header, sizeof(header), row3, sizeof(row3)));
1681 PetscCall(LogGetColumnInt(header, row1, "ref", &has_reference_1));
1682 PetscCall(LogGetColumnInt(header, row2, "ref", &has_reference_2));
1683 PetscCall(LogGetColumnInt(header, row3, "ref", &has_reference_3));
1684 PetscCall(LogGetColumnInt(header, row1, "ph", &phase_step_1));
1685 PetscCall(LogGetColumnInt(header, row2, "ph", &phase_step_2));
1686 PetscCall(LogGetColumnInt(header, row3, "ph", &phase_step_3));
1687 PetscCall(LogGetColumnReal(header, row3, "spd_ref", &mean_speed_ref_2));
1688 PetscCall(LogGetColumnReal(header, row3, "spd_abs", &mean_speed_abs_2));
1689
1690 PetscCall(PicurvAssertIntEqual(0, has_reference_1,
1691 "the first periodic phase visit should log warmup without a reference"));
1692 PetscCall(PicurvAssertIntEqual(0, has_reference_2,
1693 "the first periodic cycle should fully warm up before comparisons begin"));
1694 PetscCall(PicurvAssertIntEqual(1, has_reference_3,
1695 "the repeated periodic phase visit should compare against the stored reference"));
1696 PetscCall(PicurvAssertIntEqual(1, phase_step_1,
1697 "periodic solution convergence should log the current phase slot"));
1698 PetscCall(PicurvAssertIntEqual(0, phase_step_2,
1699 "periodic solution convergence should log distinct phase slots during warmup"));
1700 PetscCall(PicurvAssertIntEqual(1, phase_step_3,
1701 "periodic solution convergence should reuse the same phase slot on later cycles"));
1702 PetscCall(PicurvAssertRealNear(1.0, mean_speed_ref_2, 1.0e-12,
1703 "periodic solution convergence should report the stored phase-aligned reference"));
1704 PetscCall(PicurvAssertRealNear(0.25, mean_speed_abs_2, 1.0e-12,
1705 "periodic solution convergence should report the phase-aligned drift"));
1706
1707 PetscCall(PicurvRemoveTempDir(tmpdir));
1708 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1709 PetscFunctionReturn(0);
1710}
PetscInt solutionConvergencePeriodSteps
Definition variables.h:763
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:545
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 1715 of file test_logging.c.

1716{
1717 SimCtx *simCtx = NULL;
1718 UserCtx *user = NULL;
1719 char tmpdir[PETSC_MAX_PATH_LEN];
1720 char log_path[PETSC_MAX_PATH_LEN];
1721 char header[4096];
1722 char row[4096];
1723 PetscReal mean_speed_window = NAN;
1724 PetscReal mean_speed_window_prev = NAN;
1725 PetscReal mean_speed_window_abs = NAN;
1726 PetscReal mean_speed_rms_window = NAN;
1727 PetscReal mean_ke_window = NAN;
1728 PetscReal mean_ke_window_prev = NAN;
1729 PetscReal mean_ke_window_abs = NAN;
1730 PetscReal mean_ke_rms_window_abs = NAN;
1731 PetscInt has_reference = 0;
1732 const PetscReal speed_samples[4] = {1.0, 3.0, 2.0, 4.0};
1733
1734 PetscFunctionBeginUser;
1735 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
1736 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1737 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1740
1741 PetscCall(InitializeSolutionConvergenceState(simCtx));
1742 for (PetscInt step = 0; step < 4; ++step) {
1743 simCtx->step = step + 1;
1744 simCtx->ti = 0.1 * (PetscReal)(step + 1);
1745 PetscCall(SetUniformVelocityField(user, user->Ucat, speed_samples[step], 0.0, 0.0));
1746 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1747 }
1748
1749 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1750 PetscCall(PicurvAssertFileExists(log_path, "statistical solution-convergence logging should write the log"));
1751 PetscCall(ReadLogHeaderAndRow(log_path, 4, header, sizeof(header), row, sizeof(row)));
1752 PetscCall(LogGetColumnInt(header, row, "ref", &has_reference));
1753 PetscCall(LogGetColumnReal(header, row, "spd_win", &mean_speed_window));
1754 PetscCall(LogGetColumnReal(header, row, "spd_win_prev", &mean_speed_window_prev));
1755 PetscCall(LogGetColumnReal(header, row, "spd_win_abs", &mean_speed_window_abs));
1756 PetscCall(LogGetColumnReal(header, row, "spd_rms_win", &mean_speed_rms_window));
1757 PetscCall(LogGetColumnReal(header, row, "ke_win", &mean_ke_window));
1758 PetscCall(LogGetColumnReal(header, row, "ke_win_prev", &mean_ke_window_prev));
1759 PetscCall(LogGetColumnReal(header, row, "ke_win_abs", &mean_ke_window_abs));
1760 PetscCall(LogGetColumnReal(header, row, "ke_rms_abs", &mean_ke_rms_window_abs));
1761
1762 PetscCall(PicurvAssertIntEqual(1, has_reference,
1763 "statistical solution convergence should emit adjacent-window drift once two windows exist"));
1764 PetscCall(PicurvAssertRealNear(3.0, mean_speed_window, 1.0e-12,
1765 "statistical solution convergence should report the current mean-speed window"));
1766 PetscCall(PicurvAssertRealNear(2.0, mean_speed_window_prev, 1.0e-12,
1767 "statistical solution convergence should report the previous mean-speed window"));
1768 PetscCall(PicurvAssertRealNear(1.0, mean_speed_window_abs, 1.0e-12,
1769 "statistical solution convergence should report mean-speed window drift"));
1770 PetscCall(PicurvAssertRealNear(1.0, mean_speed_rms_window, 1.0e-12,
1771 "statistical solution convergence should report current mean-speed RMS"));
1772 PetscCall(PicurvAssertRealNear(5.0, mean_ke_window, 1.0e-12,
1773 "statistical solution convergence should report the current kinetic-energy window"));
1774 PetscCall(PicurvAssertRealNear(2.5, mean_ke_window_prev, 1.0e-12,
1775 "statistical solution convergence should report the previous kinetic-energy window"));
1776 PetscCall(PicurvAssertRealNear(2.5, mean_ke_window_abs, 1.0e-12,
1777 "statistical solution convergence should report kinetic-energy window drift"));
1778 PetscCall(PicurvAssertRealNear(1.0, mean_ke_rms_window_abs, 1.0e-12,
1779 "statistical solution convergence should report RMS kinetic-energy drift"));
1780
1781 PetscCall(PicurvRemoveTempDir(tmpdir));
1782 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1783 PetscFunctionReturn(0);
1784}
PetscInt solutionConvergenceWindowSteps
Definition variables.h:764
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:546
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 unique cells also equals 0.5025 for any even N, because Σ_{k=0}^{N-1} sin²(2πk/N) = N/2.

Before the fix the statistics loops iterated over N+1 nodes (including the duplicated periodic endpoint at k=N), inflating the denominator and yielding mean_ke ≈ 0.5·(1 + 0.01·N/(2(N+1)³)) instead of 0.5025. This test verifies the endpoint is excluded.

Definition at line 1796 of file test_logging.c.

1797{
1798 const PetscInt km_values[] = {8, 16};
1799 const PetscInt n_cases = (PetscInt)(sizeof(km_values) / sizeof(km_values[0]));
1800
1801 PetscFunctionBeginUser;
1802 for (PetscInt t = 0; t < n_cases; ++t) {
1803 const PetscInt km = km_values[t];
1804 SimCtx *simCtx = NULL;
1805 UserCtx *user = NULL;
1806 char tmpdir[PETSC_MAX_PATH_LEN];
1807 char log_path[PETSC_MAX_PATH_LEN];
1808 char header[4096];
1809 char row[4096];
1810 PetscReal mean_ke = NAN;
1811
1812 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, km, km, km,
1813 PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
1814 PetscCall(PicurvMakeTempDir(tmpdir, sizeof(tmpdir)));
1815 PetscCall(PetscStrncpy(simCtx->log_dir, tmpdir, sizeof(simCtx->log_dir)));
1816 PetscCall(PicurvPopulateIdentityMetrics(user));
1817 PetscCall(SetSinusoidalVZField(user, user->Ucat, 0.1, 1.0));
1818
1821 PetscCall(InitializeSolutionConvergenceState(simCtx));
1822
1823 simCtx->step = 1;
1824 simCtx->ti = 0.1;
1825 PetscCall(LOG_SOLUTION_CONVERGENCE(simCtx));
1826
1827 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1828 PetscCall(ReadLogHeaderAndRow(log_path, 1, header, sizeof(header), row, sizeof(row)));
1829 PetscCall(LogGetColumnReal(header, row, "mean_ke", &mean_ke));
1830 PetscCall(PicurvAssertRealNear(0.5025, mean_ke, 1.0e-10,
1831 "periodic sinusoidal field mean KE must equal 0.5025 (no duplicate endpoint)"));
1832
1833 PetscCall(PicurvRemoveTempDir(tmpdir));
1834 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1835 }
1836 PetscFunctionReturn(0);
1837}
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.
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:

◆ main()

int main ( int  argc,
char **  argv 
)

Runs the unit-logging PETSc test binary.

Definition at line 1843 of file test_logging.c.

1844{
1845 PetscErrorCode ierr;
1846 const PicurvTestCase cases[] = {
1847 {"string-conversion-helpers", TestStringConversionHelpers},
1848 {"get-log-level-from-environment", TestGetLogLevelFromEnvironment},
1849 {"allowed-functions-filter", TestAllowedFunctionsFilter},
1850 {"particle-console-snapshot-cadence", TestParticleConsoleSnapshotCadence},
1851 {"statistics-console-snapshot-cadence", TestStatisticsConsoleSnapshotCadence},
1852 {"logging-file-parsing-and-formatting-helpers", TestLoggingFileParsingAndFormattingHelpers},
1853 {"logging-continuity-and-field-diagnostics", TestLoggingContinuityAndFieldDiagnostics},
1854 {"interpolation-error-logging", TestInterpolationErrorLogging},
1855 {"scatter-metrics-logging", TestScatterMetricsLogging},
1856 {"particle-field-table-logging", TestParticleFieldTableLogging},
1857 {"particle-console-snapshot-logging", TestParticleConsoleSnapshotLogging},
1858 {"statistics-console-snapshot-logging", TestStatisticsConsoleSnapshotLogging},
1859 {"console-cadence-does-not-change-accumulation", TestConsoleCadenceDoesNotChangeAccumulation},
1860 {"particle-metrics-logging", TestParticleMetricsLogging},
1861 {"search-metrics-logging", TestSearchMetricsLogging},
1862 {"field-anatomy-logging", TestFieldAnatomyLogging},
1863 {"profiling-lifecycle-helpers", TestProfilingLifecycleHelpers},
1864 {"runtime-memory-log-helpers", TestRuntimeMemoryLogHelpers},
1865 {"solution-convergence-disabled", TestSolutionConvergenceDisabled},
1866 {"solution-convergence-steady-logging", TestSolutionConvergenceSteadyLogging},
1867 {"solution-convergence-periodic-logging", TestSolutionConvergencePeriodicLogging},
1868 {"solution-convergence-statistical-logging", TestSolutionConvergenceStatisticalLogging},
1869 {"periodic-sinusoidal-mean-ke", TestPeriodicSinusoidalMeanKE},
1870 };
1871
1872 (void)setenv("LOG_LEVEL", "INFO", 1);
1873
1874 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv logging tests");
1875 if (ierr) {
1876 return (int)ierr;
1877 }
1878
1879 ierr = PicurvRunTests("unit-logging", cases, sizeof(cases) / sizeof(cases[0]));
1880 if (ierr) {
1881 PetscFinalize();
1882 return (int)ierr;
1883 }
1884
1885 set_allowed_functions(NULL, 0);
1886
1887 ierr = PetscFinalize();
1888 return (int)ierr;
1889}
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 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: