22static PetscErrorCode
AssertFileContains(
const char *path,
const char *needle,
const char *context)
28 PetscFunctionBeginUser;
29 fp = fopen(path,
"rb");
31 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to open '%s' for assertion.", path);
33 if (fseek(fp, 0, SEEK_END) != 0) {
35 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to seek '%s'.", path);
37 file_size = ftell(fp);
40 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to measure '%s'.", path);
42 if (fseek(fp, 0, SEEK_SET) != 0) {
44 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to rewind '%s'.", path);
47 PetscCall(PetscMalloc1((
size_t)file_size + 1, &buffer));
49 size_t bytes_read = fread(buffer, 1, (
size_t)file_size, fp);
50 if (bytes_read != (
size_t)file_size) {
52 PetscCall(PetscFree(buffer));
53 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to read '%s'.", path);
56 buffer[file_size] =
'\0';
59 PetscCall(
PicurvAssertBool((PetscBool)(strstr(buffer, needle) != NULL), context));
60 PetscCall(PetscFree(buffer));
61 PetscFunctionReturn(0);
73 PetscFunctionBeginUser;
74 fp = fopen(path,
"rb");
76 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to open '%s' for assertion.", path);
78 if (fseek(fp, 0, SEEK_END) != 0) {
80 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to seek '%s'.", path);
82 file_size = ftell(fp);
85 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to measure '%s'.", path);
87 if (fseek(fp, 0, SEEK_SET) != 0) {
89 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to rewind '%s'.", path);
92 PetscCall(PetscMalloc1((
size_t)file_size + 1, &buffer));
94 size_t bytes_read = fread(buffer, 1, (
size_t)file_size, fp);
95 if (bytes_read != (
size_t)file_size) {
97 PetscCall(PetscFree(buffer));
98 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to read '%s'.", path);
101 buffer[file_size] =
'\0';
104 PetscCall(
PicurvAssertBool((PetscBool)(strstr(buffer, needle) == NULL), context));
105 PetscCall(PetscFree(buffer));
106 PetscFunctionReturn(0);
120 PetscInt current_row = 0;
122 PetscFunctionBeginUser;
123 PetscCheck(path != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV path cannot be NULL.");
124 PetscCheck(header != NULL && header_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV header buffer cannot be NULL or empty.");
125 PetscCheck(row != NULL && row_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV row buffer cannot be NULL or empty.");
126 PetscCheck(row_index >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
"CSV row index must be >= 1.");
128 fp = fopen(path,
"r");
129 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to open CSV '%s'.", path);
130 PetscCheck(fgets(header, (
int)header_len, fp) != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"CSV header missing in '%s'.", path);
132 while (fgets(row, (
int)row_len, fp) != NULL) {
134 if (current_row == row_index) {
136 PetscFunctionReturn(0);
141 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"CSV '%s' does not contain data row %d.", path, (
int)row_index);
147static PetscErrorCode
CsvFindColumnIndex(
const char *header,
const char *column_name, PetscInt *index_out)
149 char local_header[4096];
150 char *saveptr = NULL;
154 PetscFunctionBeginUser;
155 PetscCheck(header != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV header cannot be NULL.");
156 PetscCheck(column_name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV column name cannot be NULL.");
157 PetscCheck(index_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV column index output cannot be NULL.");
158 PetscCheck(strlen(header) <
sizeof(local_header), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
"CSV header is too long for the local parser buffer.");
160 PetscCall(PetscStrncpy(local_header, header,
sizeof(local_header)));
161 token = strtok_r(local_header,
",\r\n", &saveptr);
162 while (token != NULL) {
163 if (strcmp(token, column_name) == 0) {
165 PetscFunctionReturn(0);
167 token = strtok_r(NULL,
",\r\n", &saveptr);
171 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"CSV column '%s' was not found.", column_name);
179 const char *column_name,
183 char local_row[4096];
184 char *saveptr = NULL;
186 PetscInt target_index = -1;
189 PetscFunctionBeginUser;
190 PetscCheck(row != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV row cannot be NULL.");
191 PetscCheck(value != NULL && value_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV value buffer cannot be NULL or empty.");
192 PetscCheck(strlen(row) <
sizeof(local_row), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
"CSV row is too long for the local parser buffer.");
195 PetscCall(PetscStrncpy(local_row, row,
sizeof(local_row)));
197 token = strtok_r(local_row,
",\r\n", &saveptr);
198 while (token != NULL) {
199 if (index == target_index) {
200 PetscCall(PetscStrncpy(value, token, value_len));
201 PetscFunctionReturn(0);
203 token = strtok_r(NULL,
",\r\n", &saveptr);
207 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"CSV row is missing column '%s'.", column_name);
213static PetscErrorCode
CsvGetColumnInt(
const char *header,
const char *row,
const char *column_name, PetscInt *value_out)
219 PetscFunctionBeginUser;
220 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV integer output cannot be NULL.");
222 parsed = strtol(text, &endptr, 10);
223 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"CSV column '%s' did not contain an integer.", column_name);
224 *value_out = (PetscInt)parsed;
225 PetscFunctionReturn(0);
231static PetscErrorCode
CsvGetColumnReal(
const char *header,
const char *row,
const char *column_name, PetscReal *value_out)
237 PetscFunctionBeginUser;
238 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"CSV real output cannot be NULL.");
240 parsed = strtod(text, &endptr);
241 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"CSV column '%s' did not contain a real value.", column_name);
242 *value_out = (PetscReal)parsed;
243 PetscFunctionReturn(0);
262 PetscInt current_row = 0;
264 PetscBool header_found = PETSC_FALSE;
266 PetscFunctionBeginUser;
267 PetscCheck(path != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log path cannot be NULL.");
268 PetscCheck(header != NULL && header_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log header buffer cannot be NULL.");
269 PetscCheck(row != NULL && row_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log row buffer cannot be NULL.");
270 PetscCheck(row_index >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
"Log row index must be >= 1.");
272 fp = fopen(path,
"r");
273 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to open log '%s'.", path);
275 while (fgets(line,
sizeof(line), fp) != NULL) {
276 if (line[0] ==
'=' || line[0] ==
'-' || line[0] ==
'\n' || line[0] ==
'\r')
continue;
278 PetscCall(PetscStrncpy(header, line, header_len));
279 header_found = PETSC_TRUE;
283 if (current_row == row_index) {
284 PetscCall(PetscStrncpy(row, line, row_len));
286 PetscFunctionReturn(0);
291 if (!header_found) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"Log '%s' has no column header.", path);
292 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"Log '%s' does not contain data row %d.", path, (
int)row_index);
298static PetscErrorCode
LogFindColumnIndex(
const char *header,
const char *column_name, PetscInt *index_out)
300 char local_header[8192];
301 char *saveptr = NULL;
305 PetscFunctionBeginUser;
306 PetscCheck(header != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log header cannot be NULL.");
307 PetscCheck(column_name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log column name cannot be NULL.");
308 PetscCheck(index_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log column index output cannot be NULL.");
310 PetscCall(PetscStrncpy(local_header, header,
sizeof(local_header)));
311 token = strtok_r(local_header,
"|\r\n", &saveptr);
312 while (token != NULL) {
313 while (*token ==
' ') token++;
314 char *end = token + strlen(token) - 1;
315 while (end > token && (*end ==
' ' || *end ==
'\r' || *end ==
'\n')) end--;
317 if (strcmp(token, column_name) == 0) {
319 PetscFunctionReturn(0);
321 token = strtok_r(NULL,
"|\r\n", &saveptr);
324 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"Log column '%s' was not found.", column_name);
332 const char *column_name,
336 char local_row[8192];
337 char *saveptr = NULL;
339 PetscInt target_index = -1;
342 PetscFunctionBeginUser;
343 PetscCheck(row != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log row cannot be NULL.");
344 PetscCheck(value != NULL && value_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log value buffer cannot be NULL.");
347 PetscCall(PetscStrncpy(local_row, row,
sizeof(local_row)));
349 token = strtok_r(local_row,
"|\r\n", &saveptr);
350 while (token != NULL) {
351 if (index == target_index) {
352 while (*token ==
' ') token++;
353 char *end = token + strlen(token) - 1;
354 while (end > token && (*end ==
' ' || *end ==
'\r' || *end ==
'\n')) end--;
356 PetscCall(PetscStrncpy(value, token, value_len));
357 PetscFunctionReturn(0);
359 token = strtok_r(NULL,
"|\r\n", &saveptr);
362 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"Log row is missing column '%s'.", column_name);
368static PetscErrorCode
LogGetColumnInt(
const char *header,
const char *row,
const char *column_name, PetscInt *value_out)
374 PetscFunctionBeginUser;
375 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log integer output cannot be NULL.");
377 parsed = strtol(text, &endptr, 10);
378 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"Log column '%s' did not contain an integer.", column_name);
379 *value_out = (PetscInt)parsed;
380 PetscFunctionReturn(0);
386static PetscErrorCode
LogGetColumnReal(
const char *header,
const char *row,
const char *column_name, PetscReal *value_out)
392 PetscFunctionBeginUser;
393 PetscCheck(value_out != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Log real output cannot be NULL.");
395 parsed = strtod(text, &endptr);
396 PetscCheck(endptr != text, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"Log column '%s' did not contain a real value.", column_name);
397 *value_out = (PetscReal)parsed;
398 PetscFunctionReturn(0);
418 char tmpdir[PETSC_MAX_PATH_LEN];
419 char capture_path[PETSC_MAX_PATH_LEN];
420 FILE *capture_file = NULL;
421 int saved_stdout = -1;
423 size_t bytes_read = 0;
426 PetscFunctionBeginUser;
427 PetscCheck(fn != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Capture callback cannot be NULL.");
428 PetscCheck(captured != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Capture buffer cannot be NULL.");
429 PetscCheck(captured_len > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
"Capture buffer must be non-empty.");
432 PetscCall(PetscSNPrintf(capture_path,
sizeof(capture_path),
"%s/logging.out", tmpdir));
435 saved_stdout = dup(STDOUT_FILENO);
436 PetscCheck(saved_stdout >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS,
"dup(STDOUT_FILENO) failed.");
437 capture_fd = open(capture_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
438 PetscCheck(capture_fd >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to open capture file '%s'.", capture_path);
439 PetscCheck(dup2(capture_fd, STDOUT_FILENO) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS,
"dup2() failed while redirecting stdout.");
443 ierr = fn(user, simCtx, ctx);
445 PetscCheck(dup2(saved_stdout, STDOUT_FILENO) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS,
"dup2() failed while restoring stdout.");
450 capture_file = fopen(capture_path,
"r");
451 PetscCheck(capture_file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to read capture file '%s'.", capture_path);
452 bytes_read = fread(captured, 1, captured_len - 1, capture_file);
453 captured[bytes_read] =
'\0';
454 fclose(capture_file);
456 PetscFunctionReturn(0);
464 PetscInt print_interval = *((PetscInt *)ctx);
466 PetscFunctionBeginUser;
469 PetscFunctionReturn(0);
477 PetscInt step = *((PetscInt *)ctx);
479 PetscFunctionBeginUser;
481 PetscFunctionReturn(0);
491 PetscFunctionBeginUser;
494 PetscFunctionReturn(0);
502 PetscReal *positions = NULL;
503 PetscReal *velocities = NULL;
504 PetscReal *weights = NULL;
505 PetscInt *cell_ids = NULL;
506 PetscInt *status = NULL;
507 PetscReal *psi = NULL;
509 PetscFunctionBeginUser;
512 (*simCtx_out)->np = 2;
513 (*simCtx_out)->particleConsoleOutputFreq = 2;
514 (*simCtx_out)->LoggingFrequency = 1;
516 PetscCall(DMSwarmGetField((*user_out)->swarm,
"position", NULL, NULL, (
void **)&positions));
517 PetscCall(DMSwarmGetField((*user_out)->swarm,
"velocity", NULL, NULL, (
void **)&velocities));
518 PetscCall(DMSwarmGetField((*user_out)->swarm,
"weight", NULL, NULL, (
void **)&weights));
519 PetscCall(DMSwarmGetField((*user_out)->swarm,
"DMSwarm_CellID", NULL, NULL, (
void **)&cell_ids));
520 PetscCall(DMSwarmGetField((*user_out)->swarm,
"DMSwarm_location_status", NULL, NULL, (
void **)&status));
521 PetscCall(DMSwarmGetField((*user_out)->swarm,
"Psi", NULL, NULL, (
void **)&psi));
523 positions[0] = 0.25; positions[1] = 0.50; positions[2] = 0.75;
524 positions[3] = 0.50; positions[4] = 0.50; positions[5] = 0.50;
525 velocities[0] = 1.0; velocities[1] = 2.0; velocities[2] = 3.0;
526 velocities[3] = 4.0; velocities[4] = 5.0; velocities[5] = 6.0;
527 weights[0] = 0.2; weights[1] = 0.3; weights[2] = 0.4;
528 weights[3] = 0.5; weights[4] = 0.5; weights[5] = 0.5;
529 cell_ids[0] = 0; cell_ids[1] = 0; cell_ids[2] = 0;
530 cell_ids[3] = 1; cell_ids[4] = 1; cell_ids[5] = 1;
536 PetscCall(DMSwarmRestoreField((*user_out)->swarm,
"Psi", NULL, NULL, (
void **)&psi));
537 PetscCall(DMSwarmRestoreField((*user_out)->swarm,
"DMSwarm_location_status", NULL, NULL, (
void **)&status));
538 PetscCall(DMSwarmRestoreField((*user_out)->swarm,
"DMSwarm_CellID", NULL, NULL, (
void **)&cell_ids));
539 PetscCall(DMSwarmRestoreField((*user_out)->swarm,
"weight", NULL, NULL, (
void **)&weights));
540 PetscCall(DMSwarmRestoreField((*user_out)->swarm,
"velocity", NULL, NULL, (
void **)&velocities));
541 PetscCall(DMSwarmRestoreField((*user_out)->swarm,
"position", NULL, NULL, (
void **)&positions));
542 PetscFunctionReturn(0);
552 PetscFunctionBeginUser;
553 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"UserCtx cannot be NULL.");
554 PetscCheck(field != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Velocity field cannot be NULL.");
556 PetscCall(DMDAVecGetArray(user->
fda, field, &arr));
557 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
558 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
559 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
566 PetscCall(DMDAVecRestoreArray(user->
fda, field, &arr));
567 PetscFunctionReturn(0);
575 PetscReal ***arr = NULL;
577 PetscFunctionBeginUser;
578 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"UserCtx cannot be NULL.");
579 PetscCheck(field != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Scalar field cannot be NULL.");
581 PetscCall(DMDAVecGetArray(user->
da, field, &arr));
582 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
583 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
584 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
585 arr[k][j][i] = value;
589 PetscCall(DMDAVecRestoreArray(user->
da, field, &arr));
590 PetscFunctionReturn(0);
598 PetscFunctionBeginUser;
600 "BCFaceToString should report the negative-x face"));
602 "FieldInitializationToString should report the zero mode"));
604 "FieldInitializationToString should reject unknown selectors"));
606 "ParticleInitializationToString should report the volume mode"));
608 "LESModelToString should report the constant model"));
610 "MomentumSolverTypeToString should report the explicit solver"));
612 "BCTypeToString should report periodic boundaries"));
614 "BCHandlerTypeToString should report the driven periodic handler"));
616 "ParticleLocationStatusToString should report LOST state"));
617 PetscFunctionReturn(0);
625 PetscFunctionBeginUser;
627 "get_log_level should honor LOG_LEVEL=INFO in this test binary"));
629 PetscFunctionReturn(0);
637 const char *allow_list[] = {
"ComputeSpecificKE",
"WriteEulerianFile"};
639 PetscFunctionBeginUser;
642 "Allowed list should include ComputeSpecificKE"));
644 "Allowed list should exclude unknown function names"));
648 "Empty allow-list should permit all functions"));
649 PetscFunctionReturn(0);
659 PetscFunctionBeginUser;
660 PetscCall(PetscMemzero(&simCtx,
sizeof(simCtx)));
665 "Particle snapshot contract should be enabled when particles and cadence are configured"));
667 "Snapshot should emit on cadence-aligned completed steps"));
669 "Snapshot should not emit off-cadence"));
673 "Zero cadence should disable periodic particle snapshots"));
675 "NULL SimCtx should never emit periodic snapshots"));
676 PetscFunctionReturn(0);
684 char tmpdir[PETSC_MAX_PATH_LEN];
685 char allow_path[PETSC_MAX_PATH_LEN];
686 char dual_log_path[PETSC_MAX_PATH_LEN];
691 PetscReal distances[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
695 PetscFunctionBeginUser;
696 PetscCall(PetscMemzero(&cell,
sizeof(cell)));
698 PetscCall(PetscSNPrintf(allow_path,
sizeof(allow_path),
"%s/allowed_functions.txt", tmpdir));
699 PetscCall(PetscSNPrintf(dual_log_path,
sizeof(dual_log_path),
"%s/dual-monitor.log", tmpdir));
701 file = fopen(allow_path,
"w");
702 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to create allow-list file '%s'.", allow_path);
703 fputs(
" ComputeSpecificKE \n", file);
704 fputs(
"# comment-only line\n", file);
705 for (PetscInt i = 0; i < 17; ++i) {
706 fprintf(file,
"Helper_%02d # trailing comment\n", (
int)i);
712 PetscCall(
PicurvAssertIntEqual(18, nfuncs,
"LoadAllowedFunctionsFromFile should trim comments and keep all identifiers"));
713 PetscCall(
PicurvAssertBool((PetscBool)(strcmp(funcs[0],
"ComputeSpecificKE") == 0),
714 "LoadAllowedFunctionsFromFile should trim leading and trailing whitespace"));
715 PetscCall(
PicurvAssertBool((PetscBool)(strcmp(funcs[17],
"Helper_16") == 0),
716 "LoadAllowedFunctionsFromFile should grow past the initial pointer capacity"));
719 for (PetscInt i = 0; i < 8; ++i) {
727 PetscCall(PetscCalloc1(1, &monctx));
729 PetscCheck(monctx->
file_handle != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to create dual-monitor log '%s'.", dual_log_path);
733 "DualMonitorDestroy should clear the caller-owned context pointer"));
738 PetscCall(PetscPrintf(PETSC_COMM_SELF,
"\n"));
741 PetscFunctionReturn(0);
751 char tmpdir[PETSC_MAX_PATH_LEN];
752 char continuity_path[PETSC_MAX_PATH_LEN];
753 PetscReal ***p = NULL;
756 PetscErrorCode ierr_minmax = 0;
758 PetscFunctionBeginUser;
761 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
782 PetscCall(PetscSNPrintf(continuity_path,
sizeof(continuity_path),
"%s/Continuity_Metrics.log", simCtx->
log_dir));
784 PetscCall(
AssertFileContains(continuity_path,
"Timestep",
"continuity metrics log should include the header"));
785 PetscCall(
AssertFileContains(continuity_path,
"([3][2][1] = 17)",
"continuity metrics log should include the divergence location"));
786 PetscCall(
AssertFileContains(continuity_path,
"2 | 0",
"continuity metrics log should append later timesteps"));
788 PetscCall(DMDAVecGetArray(user->
da, user->
P, &p));
789 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &ucat));
790 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucont, &ucont));
791 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
792 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
793 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
794 p[k][j][i] = (PetscReal)(i + j + k);
795 ucat[k][j][i].
x = (PetscReal)i;
796 ucat[k][j][i].
y = (PetscReal)(-j);
797 ucat[k][j][i].
z = (PetscReal)(2 * k);
798 ucont[k][j][i].
x = (PetscReal)(10 + i);
799 ucont[k][j][i].
y = (PetscReal)(20 + j);
800 ucont[k][j][i].
z = (PetscReal)(30 + k);
804 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucont, &ucont));
805 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &ucat));
806 PetscCall(DMDAVecRestoreArray(user->
da, user->
P, &p));
808 PetscCall(DMGlobalToLocalBegin(user->
da, user->
P, INSERT_VALUES, user->
lP));
809 PetscCall(DMGlobalToLocalEnd(user->
da, user->
P, INSERT_VALUES, user->
lP));
810 PetscCall(DMGlobalToLocalBegin(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
811 PetscCall(DMGlobalToLocalEnd(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
812 PetscCall(DMGlobalToLocalBegin(user->
fda, user->
Ucont, INSERT_VALUES, user->
lUcont));
813 PetscCall(DMGlobalToLocalEnd(user->
fda, user->
Ucont, INSERT_VALUES, user->
lUcont));
820 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
822 PetscCall(PetscPopErrorHandler());
824 "LOG_FIELD_MIN_MAX should reject unknown field names"));
828 PetscFunctionReturn(0);
838 PetscReal (*pos_arr)[3] = NULL;
839 PetscReal (*vel_arr)[3] = NULL;
840 Vec position_vec = NULL;
841 Vec analytical_vec = NULL;
842 const PetscScalar *analytical_arr = NULL;
844 PetscFunctionBeginUser;
851 PetscCall(DMSwarmGetField(user->
swarm,
"position", NULL, NULL, (
void *)&pos_arr));
852 pos_arr[0][0] = 0.5 * PETSC_PI; pos_arr[0][1] = 0.0; pos_arr[0][2] = 0.0;
853 pos_arr[1][0] = 0.0; pos_arr[1][1] = 0.5 * PETSC_PI; pos_arr[1][2] = 0.0;
854 PetscCall(DMSwarmRestoreField(user->
swarm,
"position", NULL, NULL, (
void *)&pos_arr));
856 PetscCall(DMSwarmCreateGlobalVectorFromField(user->
swarm,
"position", &position_vec));
857 PetscCall(VecDuplicate(position_vec, &analytical_vec));
858 PetscCall(VecCopy(position_vec, analytical_vec));
861 PetscCall(DMSwarmGetField(user->
swarm,
"velocity", NULL, NULL, (
void *)&vel_arr));
862 PetscCall(VecGetArrayRead(analytical_vec, &analytical_arr));
863 for (PetscInt particle = 0; particle < 2; ++particle) {
864 vel_arr[particle][0] = PetscRealPart(analytical_arr[3 * particle + 0]);
865 vel_arr[particle][1] = PetscRealPart(analytical_arr[3 * particle + 1]);
866 vel_arr[particle][2] = PetscRealPart(analytical_arr[3 * particle + 2]);
868 PetscCall(VecRestoreArrayRead(analytical_vec, &analytical_arr));
869 PetscCall(DMSwarmRestoreField(user->
swarm,
"velocity", NULL, NULL, (
void *)&vel_arr));
871 PetscCall(VecDestroy(&analytical_vec));
872 PetscCall(DMSwarmDestroyGlobalVectorFromField(user->
swarm,
"position", &position_vec));
875 PetscFunctionReturn(0);
885 char tmpdir[PETSC_MAX_PATH_LEN];
886 char metrics_path[PETSC_MAX_PATH_LEN];
887 PetscReal *positions = NULL;
888 PetscReal *psi = NULL;
889 PetscInt *cell_ids = NULL;
890 PetscInt *status = NULL;
891 PetscInt particle = 0;
893 PetscFunctionBeginUser;
897 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
910 PetscCall(DMSwarmGetField(user->
swarm,
"position", NULL, NULL, (
void **)&positions));
911 PetscCall(DMSwarmGetField(user->
swarm,
"DMSwarm_CellID", NULL, NULL, (
void **)&cell_ids));
912 PetscCall(DMSwarmGetField(user->
swarm,
"DMSwarm_location_status", NULL, NULL, (
void **)&status));
913 PetscCall(DMSwarmGetField(user->
swarm,
"Psi", NULL, NULL, (
void **)&psi));
915 for (PetscInt k = 0; k < 3; ++k) {
916 for (PetscInt j = 0; j < 3; ++j) {
917 for (PetscInt i = 0; i < 3; ++i) {
918 positions[3 * particle + 0] = (i + 0.5) / 4.0;
919 positions[3 * particle + 1] = (j + 0.5) / 4.0;
920 positions[3 * particle + 2] = (k + 0.5) / 4.0;
921 cell_ids[3 * particle + 0] = i;
922 cell_ids[3 * particle + 1] = j;
923 cell_ids[3 * particle + 2] = k;
931 PetscCall(DMSwarmRestoreField(user->
swarm,
"Psi", NULL, NULL, (
void **)&psi));
932 PetscCall(DMSwarmRestoreField(user->
swarm,
"DMSwarm_location_status", NULL, NULL, (
void **)&status));
933 PetscCall(DMSwarmRestoreField(user->
swarm,
"DMSwarm_CellID", NULL, NULL, (
void **)&cell_ids));
934 PetscCall(DMSwarmRestoreField(user->
swarm,
"position", NULL, NULL, (
void **)&positions));
939 PetscCall(PetscSNPrintf(metrics_path,
sizeof(metrics_path),
"%s/scatter_metrics.csv", simCtx->
log_dir));
942 "Scatter metrics CSV header should include relative_L2_error"));
944 "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",
945 "Scatter metrics CSV should record the expected constant-field zero-error row"));
949 PetscFunctionReturn(0);
959 PetscInt print_interval = 1;
962 PetscFunctionBeginUser;
965 PetscCall(
PicurvAssertBool((PetscBool)(strstr(captured,
"Position (x,y,z)") != NULL),
966 "LOG_PARTICLE_FIELDS should print the particle table header"));
967 PetscCall(
PicurvAssertBool((PetscBool)(strstr(captured,
"Weights (a1,a2,a3)") != NULL),
968 "LOG_PARTICLE_FIELDS should print the weight-column header"));
970 PetscFunctionReturn(0);
983 PetscFunctionBeginUser;
986 PetscCall(
PicurvAssertBool((PetscBool)(strstr(captured,
"Particle states at step 4") != NULL),
987 "EmitParticleConsoleSnapshot should print the step banner"));
988 PetscCall(
PicurvAssertBool((PetscBool)(strstr(captured,
"Position (x,y,z)") != NULL),
989 "EmitParticleConsoleSnapshot should reuse the particle table output"));
991 PetscFunctionReturn(0);
1001 char tmpdir[PETSC_MAX_PATH_LEN];
1002 char metrics_path[PETSC_MAX_PATH_LEN];
1004 PetscFunctionBeginUser;
1007 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
1019 PetscCall(PetscSNPrintf(metrics_path,
sizeof(metrics_path),
"%s/Particle_Metrics.log", simCtx->
log_dir));
1020 PetscCall(
PicurvAssertFileExists(metrics_path,
"LOG_PARTICLE_METRICS should write Particle_Metrics.log"));
1021 PetscCall(
AssertFileContains(metrics_path,
"Timestep Metrics",
"Particle metrics log should include the caller-provided stage label"));
1022 PetscCall(
AssertFileContains(metrics_path,
"Occupied Cells",
"Particle metrics log should include the metrics table header"));
1023 PetscCall(
AssertFileContains(metrics_path,
"Lost Total",
"Particle metrics log should include the cumulative-loss column"));
1024 PetscCall(
AssertFileContains(metrics_path,
"| 1 | 7 | 2",
"Particle metrics log should record both per-step and cumulative loss values"));
1027 PetscFunctionReturn(0);
1037 char tmpdir[PETSC_MAX_PATH_LEN];
1038 char metrics_path[PETSC_MAX_PATH_LEN];
1040 PetscFunctionBeginUser;
1043 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
1067 PetscCall(PetscSNPrintf(metrics_path,
sizeof(metrics_path),
"%s/search_metrics.csv", simCtx->
log_dir));
1069 PetscCall(
AssertFileContains(metrics_path,
"search_attempts",
"Search metrics CSV header should include search_attempts"));
1070 PetscCall(
AssertFileContains(metrics_path,
"search_population",
"Search metrics CSV header should include search_population"));
1071 PetscCall(
AssertFileContains(metrics_path,
"max_particle_pass_depth",
"Search metrics CSV header should include max_particle_pass_depth"));
1072 PetscCall(
AssertFileContains(metrics_path,
"search_work_index",
"Search metrics CSV header should include search_work_index"));
1073 PetscCall(
AssertFileContains(metrics_path,
"re_search_fraction",
"Search metrics CSV header should include re_search_fraction"));
1074 PetscCall(
AssertFileContains(metrics_path,
"lost_cumulative",
"Search metrics CSV header should include the cumulative-loss column"));
1075 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"));
1078 PetscFunctionReturn(0);
1088 char captured[8192];
1091 PetscFunctionBeginUser;
1093 PetscCall(VecSet(user->
P, 7.0));
1094 PetscCall(DMGlobalToLocalBegin(user->
da, user->
P, INSERT_VALUES, user->
lP));
1095 PetscCall(DMGlobalToLocalEnd(user->
da, user->
P, INSERT_VALUES, user->
lP));
1097 PetscCall(
PicurvAssertBool((PetscBool)(strstr(captured,
"Field Anatomy Log: [P]") != NULL),
1098 "LOG_FIELD_ANATOMY should print the requested field name"));
1099 PetscCall(
PicurvAssertBool((PetscBool)(strstr(captured,
"Layout: [Cell-Centered]") != NULL),
1100 "LOG_FIELD_ANATOMY should report the inferred data layout"));
1102 PetscFunctionReturn(0);
1111 char tmpdir[PETSC_MAX_PATH_LEN];
1112 char timestep_path[PETSC_MAX_PATH_LEN];
1113 char summary_path[PETSC_MAX_PATH_LEN];
1114 static char selected_name[] =
"FlowSolver";
1115 char *selected_funcs[] = {selected_name};
1117 PetscFunctionBeginUser;
1118 PetscCall(PetscMemzero(&simCtx,
sizeof(simCtx)));
1120 PetscCall(PetscStrncpy(simCtx.
log_dir, tmpdir,
sizeof(simCtx.
log_dir)));
1145 PetscCall(PetscSNPrintf(summary_path,
sizeof(summary_path),
"%s/ProfilingSummary_Solver.log", simCtx.
log_dir));
1149 "profiling timestep summary should contain the CSV header"));
1151 "profiling timestep summary should log selected functions"));
1153 "profiling timestep summary should omit unselected functions in selected mode"));
1155 "profiling final summary should include its table banner"));
1157 "profiling final summary should include selected functions"));
1159 "profiling final summary should include total-time entries for unselected functions"));
1161 PetscFunctionReturn(0);
1170 char tmpdir[PETSC_MAX_PATH_LEN];
1171 char memory_path[PETSC_MAX_PATH_LEN];
1173 PetscFunctionBeginUser;
1174 PetscCall(PetscMemzero(&simCtx,
sizeof(simCtx)));
1176 PetscCall(PetscStrncpy(simCtx.
log_dir, tmpdir,
sizeof(simCtx.
log_dir)));
1184 PetscCall(PetscMemorySetGetMaximumUsage());
1191 "runtime memory log should contain readable column labels"));
1193 "runtime memory log should contain a step row"));
1195 "runtime memory log should contain a final row"));
1197 "runtime memory log should record final reason"));
1204 "disabled runtime memory log should not create a file"));
1206 PetscFunctionReturn(0);
1216 char tmpdir[PETSC_MAX_PATH_LEN];
1217 char log_path[PETSC_MAX_PATH_LEN];
1223 PetscReal ***nvert = NULL;
1224 PetscReal mean_speed = NAN;
1225 PetscReal mean_speed_ref = NAN;
1226 PetscReal mean_speed_abs = NAN;
1227 PetscReal p_abs = NAN;
1228 PetscInt has_reference_1 = 0;
1229 PetscInt has_reference_2 = 0;
1231 PetscFunctionBeginUser;
1234 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
1243 PetscCall(DMDAVecGetArray(user->
da, user->
Nvert, &nvert));
1244 nvert[1][1][1] = 1.0;
1245 PetscCall(DMDAVecRestoreArray(user->
da, user->
Nvert, &nvert));
1246 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &ucat));
1247 ucat[1][1][1].
x = 999.0;
1248 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &ucat));
1257 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &ucat));
1258 ucat[1][1][1].
x = 999.0;
1259 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &ucat));
1262 PetscCall(PetscSNPrintf(log_path,
sizeof(log_path),
"%s/solution_convergence.log", simCtx->
log_dir));
1274 PetscCall(
PicurvAssertBool((PetscBool)(strcmp(mode,
"steady_deterministic") == 0),
1275 "steady solution convergence row should record the mode name"));
1277 "the first steady solution-convergence row should be a warmup row"));
1279 "steady solution convergence should compare against the previous solved step"));
1281 "steady solution convergence should mask IBM-marked solid cells"));
1283 "steady solution convergence should report the previous-step mean speed"));
1285 "steady solution convergence should report mean-speed drift"));
1287 "steady solution convergence pressure drift should be gauge invariant"));
1291 PetscFunctionReturn(0);
1301 char tmpdir[PETSC_MAX_PATH_LEN];
1302 char log_path[PETSC_MAX_PATH_LEN];
1307 PetscInt has_reference_1 = 0;
1308 PetscInt has_reference_2 = 0;
1309 PetscInt has_reference_3 = 0;
1310 PetscInt phase_step_1 = -1;
1311 PetscInt phase_step_2 = -1;
1312 PetscInt phase_step_3 = -1;
1313 PetscReal mean_speed_ref_2 = NAN;
1314 PetscReal mean_speed_abs_2 = NAN;
1316 PetscFunctionBeginUser;
1319 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
1343 PetscCall(PetscSNPrintf(log_path,
sizeof(log_path),
"%s/solution_convergence.log", simCtx->
log_dir));
1344 PetscCall(
PicurvAssertFileExists(log_path,
"periodic solution-convergence logging should write the log"));
1358 "the first periodic phase visit should log warmup without a reference"));
1360 "the first periodic cycle should fully warm up before comparisons begin"));
1362 "the repeated periodic phase visit should compare against the stored reference"));
1364 "periodic solution convergence should log the current phase slot"));
1366 "periodic solution convergence should log distinct phase slots during warmup"));
1368 "periodic solution convergence should reuse the same phase slot on later cycles"));
1370 "periodic solution convergence should report the stored phase-aligned reference"));
1372 "periodic solution convergence should report the phase-aligned drift"));
1376 PetscFunctionReturn(0);
1386 char tmpdir[PETSC_MAX_PATH_LEN];
1387 char log_path[PETSC_MAX_PATH_LEN];
1390 PetscReal mean_speed_window = NAN;
1391 PetscReal mean_speed_window_prev = NAN;
1392 PetscReal mean_speed_window_abs = NAN;
1393 PetscReal mean_speed_rms_window = NAN;
1394 PetscReal mean_ke_window = NAN;
1395 PetscReal mean_ke_window_prev = NAN;
1396 PetscReal mean_ke_window_abs = NAN;
1397 PetscReal mean_ke_rms_window_abs = NAN;
1398 PetscInt has_reference = 0;
1399 const PetscReal speed_samples[4] = {1.0, 3.0, 2.0, 4.0};
1401 PetscFunctionBeginUser;
1404 PetscCall(PetscStrncpy(simCtx->
log_dir, tmpdir,
sizeof(simCtx->
log_dir)));
1409 for (PetscInt step = 0; step < 4; ++step) {
1410 simCtx->
step = step + 1;
1411 simCtx->
ti = 0.1 * (PetscReal)(step + 1);
1416 PetscCall(PetscSNPrintf(log_path,
sizeof(log_path),
"%s/solution_convergence.log", simCtx->
log_dir));
1417 PetscCall(
PicurvAssertFileExists(log_path,
"statistical solution-convergence logging should write the log"));
1421 PetscCall(
LogGetColumnReal(header, row,
"spd_win_prev", &mean_speed_window_prev));
1422 PetscCall(
LogGetColumnReal(header, row,
"spd_win_abs", &mean_speed_window_abs));
1423 PetscCall(
LogGetColumnReal(header, row,
"spd_rms_win", &mean_speed_rms_window));
1425 PetscCall(
LogGetColumnReal(header, row,
"ke_win_prev", &mean_ke_window_prev));
1426 PetscCall(
LogGetColumnReal(header, row,
"ke_win_abs", &mean_ke_window_abs));
1427 PetscCall(
LogGetColumnReal(header, row,
"ke_rms_abs", &mean_ke_rms_window_abs));
1430 "statistical solution convergence should emit adjacent-window drift once two windows exist"));
1432 "statistical solution convergence should report the current mean-speed window"));
1434 "statistical solution convergence should report the previous mean-speed window"));
1436 "statistical solution convergence should report mean-speed window drift"));
1438 "statistical solution convergence should report current mean-speed RMS"));
1440 "statistical solution convergence should report the current kinetic-energy window"));
1442 "statistical solution convergence should report the previous kinetic-energy window"));
1444 "statistical solution convergence should report kinetic-energy window drift"));
1446 "statistical solution convergence should report RMS kinetic-energy drift"));
1450 PetscFunctionReturn(0);
1458 PetscErrorCode ierr;
1480 (void)setenv(
"LOG_LEVEL",
"INFO", 1);
1482 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv logging tests");
1487 ierr =
PicurvRunTests(
"unit-logging", cases,
sizeof(cases) /
sizeof(cases[0]));
1495 ierr = PetscFinalize();
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
PetscErrorCode CalculateParticleCountPerCell(UserCtx *user)
Counts particles in each cell of the DMDA 'da' and stores the result in user->ParticleCount.
PetscErrorCode ScatterAllParticleFieldsToEulerFields(UserCtx *user)
Scatters a predefined set of particle fields to their corresponding Eulerian fields.
Logging utilities and macros for PETSc-based applications.
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
PetscErrorCode LOG_PARTICLE_METRICS(UserCtx *user, const char *stageName)
Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.
const char * BCHandlerTypeToString(BCHandlerType handler_type)
Converts a BCHandlerType enum to its string representation.
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
const char * FieldInitializationToString(PetscInt FieldInitialization)
Helper function to convert FieldInitialization to a string representation.
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
PetscErrorCode LOG_INTERPOLATION_ERROR(UserCtx *user)
Logs the interpolation error between the analytical and computed solutions.
PetscBool ShouldEmitPeriodicParticleConsoleSnapshot(const SimCtx *simCtx, PetscInt completed_step)
Returns whether a particle console snapshot should be emitted for the.
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
PetscErrorCode FreeAllowedFunctions(char **funcs, PetscInt n)
Free an array previously returned by LoadAllowedFunctionsFromFile().
PetscBool IsParticleConsoleSnapshotEnabled(const SimCtx *simCtx)
Returns whether periodic particle console snapshots are enabled.
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
PetscErrorCode EmitParticleConsoleSnapshot(UserCtx *user, SimCtx *simCtx, PetscInt step)
Emits one particle console snapshot into the main solver log.
PetscErrorCode ProfilingFinalize(SimCtx *simCtx)
the profiling excercise and build a profiling summary which is then printed to a log file.
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
PetscErrorCode LOG_FIELD_MIN_MAX(UserCtx *user, const char *fieldName)
Computes and logs the local and global min/max values of a 3-component vector field.
void PrintProgressBar(PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime)
Prints a progress bar to the console.
PetscErrorCode LOG_FIELD_ANATOMY(UserCtx *user, const char *field_name, const char *stage_name)
Logs the anatomy of a specified field at key boundary locations, respecting the solver's specific gri...
PetscErrorCode RuntimeMemoryLogSample(SimCtx *simCtx, PetscInt step, const char *event, const char *reason)
Append a reduced runtime memory sample to the configured memory log.
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
PetscErrorCode ProfilingLogTimestepSummary(SimCtx *simCtx, PetscInt step)
Logs the performance summary for the current timestep and resets timers.
PetscErrorCode LOG_FACE_DISTANCES(PetscReal *d)
Prints the signed distances to each face of the cell.
PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx *user, PetscInt printInterval)
Prints particle fields in a table that automatically adjusts its column widths.
void _ProfilingEnd(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_END.
const char * BCTypeToString(BCType type)
Helper function to convert BCType enum to a string representation.
PetscErrorCode CalculateAdvancedParticleMetrics(UserCtx *user)
Computes advanced particle statistics and stores them in SimCtx.
const char * ParticleLocationStatusToString(ParticleLocationStatus level)
A function that outputs the name of the current level in the ParticleLocation enum.
PetscErrorCode LOG_SCATTER_METRICS(UserCtx *user)
Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.
PetscErrorCode LOG_SOLUTION_CONVERGENCE(SimCtx *simCtx)
Logs physical solution-convergence metrics once per completed timestep.
PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user)
Logs continuity metrics for a single block to a file.
PetscErrorCode LOG_SEARCH_METRICS(UserCtx *user)
Writes compact runtime search metrics to CSV and optionally to console.
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
@ LOG_INFO
Informational messages about program execution.
const char * LESModelToString(LESModelType LESFlag)
Helper function to convert LES Flag to a string representation.
PetscErrorCode LOG_CELL_VERTICES(const Cell *cell, PetscMPIInt rank)
Prints the coordinates of a cell's vertices.
PetscErrorCode ProfilingResetTimestepCounters(void)
Resets per-timestep profiling counters for the next solver step.
const char * MomentumSolverTypeToString(MomentumSolverType SolverFlag)
Helper function to convert Momentum Solver flag to a string representation.
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Helper function to convert ParticleInitialization to a string representation.
void _ProfilingStart(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.
Context for a dual-purpose KSP monitor.
PetscErrorCode InitializeSolutionConvergenceState(SimCtx *simCtx)
Allocates any runtime storage required by solution-convergence logging.
static PetscErrorCode TestParticleConsoleSnapshotCadence(void)
Tests periodic particle console snapshot enablement and cadence.
static PetscErrorCode SetUniformScalarField(UserCtx *user, Vec field, PetscReal value)
Fills one scalar field with a uniform constant state.
static PetscErrorCode TestFieldAnatomyLogging(void)
Tests stdout field-anatomy logging on the corrected production-like DM fixture.
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 InvokeParticleConsoleSnapshot(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts EmitParticleConsoleSnapshot() to the generic stdout-capture callback shape.
static PetscErrorCode TestParticleConsoleSnapshotLogging(void)
Tests console snapshot logging against the public periodic-snapshot helper.
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 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 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 TestGetLogLevelFromEnvironment(void)
Tests that log level selection honors the environment variable.
int main(int argc, char **argv)
Runs the unit-logging PETSc test binary.
static PetscErrorCode TestLoggingContinuityAndFieldDiagnostics(void)
Tests continuity, min/max, and anatomy logging helpers on minimal runtime fixtures.
PetscErrorCode(* CapturedLoggingFn)(UserCtx *user, SimCtx *simCtx, void *ctx)
static PetscErrorCode TestSolutionConvergenceStatisticalLogging(void)
Tests statistical solution-convergence sliding-window metrics.
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 InvokeFieldAnatomyLog(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts LOG_FIELD_ANATOMY() to the generic stdout-capture callback shape.
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 SeedLoggingParticleFixture(SimCtx **simCtx_out, UserCtx **user_out)
Creates a small particle-bearing runtime fixture used by logging tests.
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 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 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 CsvFindColumnIndex(const char *header, const char *column_name, PetscInt *index_out)
Returns the zero-based column index for one CSV header field.
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 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 AssertFileContains(const char *path, const char *needle, const char *context)
Asserts that one text file contains a required substring.
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 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 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 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 InvokeParticleFieldLog(UserCtx *user, SimCtx *simCtx, void *ctx)
Adapts LOG_PARTICLE_FIELDS() to the generic stdout-capture callback shape.
static PetscErrorCode TestRuntimeMemoryLogHelpers(void)
Tests runtime memory log header, step rows, final rows, and disabled mode.
PetscErrorCode PicurvMakeTempDir(char *path, size_t path_len)
Creates a unique temporary directory for one test case.
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvCreateSwarmPair(UserCtx *user, PetscInt nlocal, const char *post_field_name)
Creates matched solver and post-processing swarms for tests.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
PetscErrorCode PicurvAssertFileExists(const char *path, const char *context)
Asserts that a filesystem path exists as a readable file.
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
PetscErrorCode PicurvRemoveTempDir(const char *path)
Recursively removes a temporary directory created by PicurvMakeTempDir.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
PetscBool profilingFinalSummary
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
PetscInt64 searchLocatedCount
PetscInt64 searchLostCount
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
PetscInt64 boundaryClampCount
PetscInt particlesLostLastStep
PetscInt64 traversalStepsSum
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
PetscInt64 searchPopulation
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
char profilingTimestepMode[32]
@ MOMENTUM_SOLVER_EXPLICIT_RK
PetscInt solutionConvergencePeriodSteps
PetscInt64 bboxGuessFallbackCount
VerificationScalarConfig verificationScalar
PetscInt64 bboxGuessSuccessCount
char log_dir[PETSC_MAX_PATH_LEN]
PetscInt64 maxParticlePassDepth
PetscInt64 maxTraversalSteps
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
char ** profilingSelectedFuncs
PetscInt solutionConvergenceWindowSteps
PetscInt particlesLostCumulative
PetscInt nProfilingSelectedFuncs
PetscInt particlesMigratedLastStep
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
PetscInt particleConsoleOutputFreq
SearchMetricsState searchMetrics
PetscInt migrationPassesLastStep
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
SolutionConvergenceMode solutionConvergenceMode
PetscInt64 searchAttempts
PetscInt64 maxTraversalFailCount
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
PetscReal particleLoadImbalance
Defines the vertices of a single hexahedral grid cell.
A 3D point or vector with PetscScalar components.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.