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

Public interface for data input/output routines. More...

#include "variables.h"
#include "logging.h"
#include "Boundaries.h"
Include dependency graph for io.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

PetscErrorCode ReadGridGenerationInputs (UserCtx *user)
 Parses command-line options for a programmatically generated grid for a SINGLE block.
 
PetscErrorCode PopulateFinestUserGridResolutionFromOptions (UserCtx *finest_users, PetscInt nblk)
 Parses grid resolution arrays (-im, -jm, -km) once and applies them to all finest-grid blocks.
 
PetscErrorCode ReadGridFile (UserCtx *user)
 Sets grid dimensions from a file for a SINGLE block using a one-time read cache.
 
PetscErrorCode VerifyPathExistence (const char *path, PetscBool is_dir, PetscBool is_optional, const char *description, PetscBool *exists)
 A parallel-safe helper to verify the existence of a generic file or directory path.
 
PetscBool ShouldWriteDataOutput (const SimCtx *simCtx, PetscInt completed_step)
 Returns whether full field/restart output should be written for the.
 
PetscErrorCode WriteCheckpointBundle (SimCtx *simCtx, const char *reason)
 Write and atomically publish one complete checkpoint bundle.
 
PetscErrorCode ReadSimulationFields (UserCtx *user, PetscInt ti)
 Reads binary field data for velocity, pressure, and other required vectors.
 
PetscErrorCode RestoreFieldStatisticsState (SimCtx *simCtx, PetscInt ti)
 Restores field-statistics window state and accumulators from a checkpoint.
 
PetscErrorCode ReadFieldData (UserCtx *user, const char *field_name, Vec field_vec, const char *ext)
 Reads data for a specific field from a file into the provided vector.
 
PetscErrorCode WriteFieldData (UserCtx *user, const char *field_name, Vec field_vec, const char *ext)
 Writes data from a specific PETSc vector to a file.
 
PetscErrorCode WriteSimulationFields (UserCtx *user, const char *checkpoint_directory)
 Writes simulation fields to files.
 
PetscErrorCode WriteSwarmField (UserCtx *user, const char *field_name, const char *ext)
 Writes data from a specific field in a PETSc Swarm to a file.
 
PetscErrorCode WriteSwarmIntField (UserCtx *user, const char *field_name, const char *ext)
 Writes integer data from a specific PETSc Swarm field to a file.
 
PetscErrorCode WriteAllSwarmFields (UserCtx *user, const char *checkpoint_directory)
 Writes a predefined set of PETSc Swarm fields to files.
 
PetscInt ReadDataFileToArray (const char *filename, double **data_out, PetscInt *Nout, MPI_Comm comm)
 Reads a simple ASCII data file containing one numeric value per line.
 
PetscInt CreateVTKFileFromMetadata (const char *filename, const VTKMetaData *meta, MPI_Comm comm)
 Creates a VTK file from prepared metadata and field payloads.
 
PetscErrorCode VecToArrayOnRank0 (Vec inVec, PetscInt *N, double **arrayOut)
 Gathers the contents of a distributed PETSc Vec into a single array on rank 0.
 
PetscErrorCode SwarmFieldToArrayOnRank0 (DM swarm, const char *field_name, PetscInt *n_total_particles, PetscInt *n_components, PetscDataType *field_type_out, void **gathered_array)
 Gathers any DMSwarm field from all ranks to a single, contiguous array on rank 0.
 
PetscErrorCode ReadSwarmField (UserCtx *user, const char *field_name, const char *ext)
 Reads data from a file into a specified field of a PETSc DMSwarm.
 
PetscErrorCode ReadSwarmIntField (UserCtx *user, const char *field_name, const char *ext)
 Reads integer swarm data by using ReadFieldData and casting the result.
 
PetscErrorCode ReadAllSwarmFields (UserCtx *user, PetscInt ti)
 Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.
 
PetscErrorCode ReadCheckpointParticleCount (UserCtx *user, PetscInt ti, PetscInt *particle_count)
 Read the particle count from a validated committed checkpoint.
 
PetscErrorCode ReadPositionsFromFile (PetscInt timeIndex, UserCtx *user, double **coordsArray, PetscInt *Ncoords)
 Reads coordinate data (for particles) from file into a PETSc Vec, then gathers it to rank 0.
 
PetscErrorCode ReadFieldDataToRank0 (PetscInt timeIndex, const char *fieldName, UserCtx *user, double **scalarArray, PetscInt *Nscalars)
 Reads a named field from file into a PETSc Vec, then gathers it to rank 0.
 
PetscErrorCode DisplayBanner (SimCtx *simCtx)
 Displays a structured banner summarizing the simulation configuration.
 
PetscErrorCode StringToBCFace (const char *str, BCFace *face_out)
 Converts a face-token string (e.g., "-Xi", "+Eta") to the internal BCFace enum.
 
PetscErrorCode StringToBCType (const char *str, BCType *type_out)
 Converts a mathematical BC type string (e.g., "PERIODIC", "WALL") to BCType.
 
PetscErrorCode StringToBCHandlerType (const char *str, BCHandlerType *handler_out)
 Converts a BC handler token (implementation strategy) to BCHandlerType.
 
PetscErrorCode ValidateBCHandlerForBCType (BCType type, BCHandlerType handler)
 Validates that a selected handler is compatible with a mathematical BC type.
 
void FreeBC_ParamList (BC_Param *head)
 Frees an entire linked list of boundary-condition parameters.
 
PetscErrorCode GetBCParamReal (BC_Param *params, const char *key, PetscReal *value_out, PetscBool *found)
 Searches a BC_Param linked list for a key and returns its value as a double.
 
PetscErrorCode GetBCParamBool (BC_Param *params, const char *key, PetscBool *value_out, PetscBool *found)
 Searches a BC_Param linked list for a key and returns its value as a bool.
 
PetscErrorCode GetDrivenSeamFluxFlag (BC_Param *params, PetscBool *value_out, PetscBool *found)
 Read the driven-flow seam-flux flag, accepting its deprecated apply_trim spelling.
 
PetscErrorCode ParseAllBoundaryConditions (UserCtx *user, const char *bcs_input_filename)
 Parses the boundary conditions file to configure the type, handler, and any associated parameters for all 6 global faces of the domain.
 
PetscErrorCode DeterminePeriodicity (SimCtx *simCtx)
 Scans all block-specific boundary condition files to determine a globally consistent periodicity for each dimension, reusing the core type parser.
 
void TrimWhitespace (char *str)
 Removes leading and trailing ASCII whitespace from a mutable string.
 
PetscErrorCode ParsePostProcessingSettings (SimCtx *simCtx)
 Initializes post-processing settings from a config file and command-line overrides.
 
PetscErrorCode ParseScalingInformation (SimCtx *simCtx)
 Parses physical scaling parameters from command-line options.
 

Detailed Description

Public interface for data input/output routines.

This header declares functions responsible for parsing grid geometry information, either from command-line options for programmatically generated grids or by reading the header of a grid definition file.

Definition in file io.h.

Function Documentation

◆ ReadGridGenerationInputs()

PetscErrorCode ReadGridGenerationInputs ( UserCtx user)

Parses command-line options for a programmatically generated grid for a SINGLE block.

This function reads all per-block array options related to grid geometry, such as dimensions (-im), domain bounds (-xMins), and stretching ratios (-rxs). It then populates the fields of the provided UserCtx struct using its internal block index user->_this.

Parameters
userPointer to the UserCtx for a specific block. The function will populate the geometric fields (IM, Min_X, rx, etc.) within this struct.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Parses command-line options for a programmatically generated grid for a SINGLE block.

Local to this translation unit.

Definition at line 447 of file io.c.

448{
449 PetscErrorCode ierr;
450 SimCtx *simCtx = user->simCtx;
451 PetscInt nblk = simCtx->block_number;
452 PetscInt block_index = user->_this;
453 PetscBool found;
454
455 // Temporary arrays to hold the parsed values for ALL blocks
456 PetscInt *IMs = NULL, *JMs = NULL, *KMs = NULL, *cgrids = NULL;
457 PetscReal *xMins = NULL, *xMaxs = NULL, *rxs = NULL;
458 PetscReal *yMins = NULL, *yMaxs = NULL, *rys = NULL;
459 PetscReal *zMins = NULL, *zMaxs = NULL, *rzs = NULL;
460
461 PetscFunctionBeginUser;
463
464 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Reading generated grid inputs for block %d.\n", simCtx->rank, block_index);
465
466 if (block_index >= nblk) {
467 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Block index %d is out of range for nblk=%d", block_index, nblk);
468 }
469
470 // --- Allocate temporary storage for all array options ---
471 ierr = PetscMalloc4(nblk, &IMs, nblk, &JMs, nblk, &KMs, nblk, &cgrids); CHKERRQ(ierr);
472 ierr = PetscMalloc6(nblk, &xMins, nblk, &xMaxs, nblk, &rxs, nblk, &yMins, nblk, &yMaxs, nblk, &rys); CHKERRQ(ierr);
473 ierr = PetscMalloc3(nblk, &zMins, nblk, &zMaxs, nblk, &rzs); CHKERRQ(ierr);
474
475 // --- Set default values for the temporary arrays ---
476 for (PetscInt i = 0; i < nblk; ++i) {
477 IMs[i] = 10; JMs[i] = 10; KMs[i] = 10; cgrids[i] = 0;
478 xMins[i] = 0.0; xMaxs[i] = 1.0; rxs[i] = 1.0;
479 yMins[i] = 0.0; yMaxs[i] = 1.0; rys[i] = 1.0;
480 zMins[i] = 0.0; zMaxs[i] = 1.0; rzs[i] = 1.0;
481 }
482
483 // --- Parse the array options from the command line / control file ---
484 PetscInt count;
485 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-im", IMs, &count, &found); CHKERRQ(ierr);
486 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-jm", JMs, &count, &found); CHKERRQ(ierr);
487 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-km", KMs, &count, &found); CHKERRQ(ierr);
488 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-xMins", xMins, &count, &found); CHKERRQ(ierr);
489 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-xMaxs", xMaxs, &count, &found); CHKERRQ(ierr);
490 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-rxs", rxs, &count, &found); CHKERRQ(ierr);
491 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-yMins", yMins, &count, &found); CHKERRQ(ierr);
492 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-yMaxs", yMaxs, &count, &found); CHKERRQ(ierr);
493 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-rys", rys, &count, &found); CHKERRQ(ierr);
494 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-zMins", zMins, &count, &found); CHKERRQ(ierr);
495 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-zMaxs", zMaxs, &count, &found); CHKERRQ(ierr);
496 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-rzs", rzs, &count, &found); CHKERRQ(ierr);
497 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-cgrids", cgrids, &count, &found); CHKERRQ(ierr);
498
499 // --- Assign the parsed values to the specific UserCtx struct passed in ---
500 user->IM = IMs[block_index];
501 user->JM = JMs[block_index];
502 user->KM = KMs[block_index];
503 user->Min_X = xMins[block_index];
504 user->Max_X = xMaxs[block_index];
505 user->rx = rxs[block_index];
506 user->Min_Y = yMins[block_index];
507 user->Max_Y = yMaxs[block_index];
508 user->ry = rys[block_index];
509 user->Min_Z = zMins[block_index];
510 user->Max_Z = zMaxs[block_index];
511 user->rz = rzs[block_index];
512 user->cgrid = cgrids[block_index];
513
514 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d grid generation inputs set: IM=%d, JM=%d, KM=%d\n",
515 simCtx->rank, block_index, user->IM, user->JM, user->KM);
516 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d bounds: X=[%.2f, %.2f], Y=[%.2f, %.2f], Z=[%.2f, %.2f]\n",
517 simCtx->rank, block_index, user->Min_X, user->Max_X, user->Min_Y, user->Max_Y, user->Min_Z, user->Max_Z);
518
519 // --- Clean up temporary storage ---
520 ierr = PetscFree4(IMs, JMs, KMs, cgrids); CHKERRQ(ierr);
521 ierr = PetscFree6(xMins, xMaxs, rxs, yMins, yMaxs, rys); CHKERRQ(ierr);
522 ierr = PetscFree3(zMins, zMaxs, rzs); CHKERRQ(ierr);
523
525 PetscFunctionReturn(0);
526}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:859
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:850
PetscMPIInt rank
Definition variables.h:698
PetscInt cgrid
Definition variables.h:926
PetscInt block_number
Definition variables.h:790
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
PetscReal Min_X
Definition variables.h:921
PetscInt KM
Definition variables.h:920
PetscInt _this
Definition variables.h:924
PetscReal ry
Definition variables.h:925
PetscReal Max_Y
Definition variables.h:921
PetscReal rz
Definition variables.h:925
PetscInt JM
Definition variables.h:920
PetscReal Min_Z
Definition variables.h:921
PetscReal Max_X
Definition variables.h:921
PetscReal Min_Y
Definition variables.h:921
PetscInt IM
Definition variables.h:920
PetscReal rx
Definition variables.h:925
PetscReal Max_Z
Definition variables.h:921
The master context for the entire simulation.
Definition variables.h:695
Here is the caller graph for this function:

◆ PopulateFinestUserGridResolutionFromOptions()

PetscErrorCode PopulateFinestUserGridResolutionFromOptions ( UserCtx finest_users,
PetscInt  nblk 
)

Parses grid resolution arrays (-im, -jm, -km) once and applies them to all finest-grid blocks.

This helper centralizes one-time resolution ingestion for analytical grid setup. It fills IM/JM/KM in each element of the finest-level UserCtx array.

Parameters
finest_usersPointer to the finest-level UserCtx array (length nblk).
nblkNumber of blocks in the finest-level array.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Parses grid resolution arrays (-im, -jm, -km) once and applies them to all finest-grid blocks.

Local to this translation unit.

Definition at line 532 of file io.c.

533{
534 PetscErrorCode ierr;
535 PetscBool found;
536 PetscInt *IMs = NULL, *JMs = NULL, *KMs = NULL;
537 SimCtx *simCtx = NULL;
538
539 PetscFunctionBeginUser;
540
541 if (!finest_users) {
542 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "finest_users cannot be NULL.");
543 }
544 if (nblk <= 0) {
545 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nblk must be positive. Got %d.", nblk);
546 }
547 simCtx = finest_users[0].simCtx;
548
549 ierr = PetscMalloc3(nblk, &IMs, nblk, &JMs, nblk, &KMs); CHKERRQ(ierr);
550 for (PetscInt i = 0; i < nblk; ++i) {
551 IMs[i] = 10; JMs[i] = 10; KMs[i] = 10;
552 }
553
554 PetscInt count;
555 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-im", IMs, &count, &found); CHKERRQ(ierr);
556 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-jm", JMs, &count, &found); CHKERRQ(ierr);
557 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-km", KMs, &count, &found); CHKERRQ(ierr);
558
559 for (PetscInt bi = 0; bi < nblk; ++bi) {
560 finest_users[bi].IM = IMs[bi];
561 finest_users[bi].JM = JMs[bi];
562 finest_users[bi].KM = KMs[bi];
563 if (simCtx) {
565 "Rank %d: Preloaded analytical grid resolution for block %d: IM=%d, JM=%d, KM=%d\n",
566 simCtx->rank, bi, finest_users[bi].IM, finest_users[bi].JM, finest_users[bi].KM);
567 }
568 }
569
570 ierr = PetscFree3(IMs, JMs, KMs); CHKERRQ(ierr);
571 PetscFunctionReturn(0);
572}
Here is the caller graph for this function:

◆ ReadGridFile()

PetscErrorCode ReadGridFile ( UserCtx user)

Sets grid dimensions from a file for a SINGLE block using a one-time read cache.

This function uses a static-variable pattern to ensure the grid file header is read only once, collectively, by all processes on the first call. Subsequent calls simply retrieve the pre-loaded and broadcasted data for the specified block.

Parameters
userPointer to the UserCtx for a specific block. This function will populate the IM, JM, and KM fields.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Sets grid dimensions from a file for a SINGLE block using a one-time read cache.

Local to this translation unit.

Definition at line 581 of file io.c.

582{
583 PetscErrorCode ierr;
584 SimCtx *simCtx = user->simCtx;
585 PetscInt block_index = user->_this;
586
587 PetscFunctionBeginUser;
589
590 // --- One-Time Read and Broadcast Logic ---
592 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "First call to ReadGridFile. Reading and broadcasting grid file header from '%s'...\n", simCtx->grid_file);
593 PetscMPIInt rank = simCtx->rank;
594 PetscInt nblk = simCtx->block_number;
595
596 if (rank == 0) {
597 FILE *fd = fopen(simCtx->grid_file, "r");
598 if (!fd) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file: %s", simCtx->grid_file);
599
600 // Read and validate the canonical PICGRID header.
601 char firstTok[32] = {0};
602 if (fscanf(fd, "%31s", firstTok) != 1)
603 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Empty grid file: %s", simCtx->grid_file);
604 if (strcmp(firstTok, "PICGRID") != 0)
605 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
606 "Grid file %s must begin with the canonical PICGRID header.", simCtx->grid_file);
607 if (fscanf(fd, "%d", &g_nblk_from_file) != 1)
608 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Expected number of blocks after \"PICGRID\" in %s", simCtx->grid_file);
609 if (g_nblk_from_file != nblk) {
610 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Mismatch: -nblk is %d but grid file specifies %d blocks.", nblk, g_nblk_from_file);
611 }
612
613 ierr = PetscMalloc3(nblk, &g_IMs_from_file, nblk, &g_JMs_from_file, nblk, &g_KMs_from_file); CHKERRQ(ierr);
614 for (PetscInt i = 0; i < nblk; ++i) {
615 if (fscanf(fd, "%d %d %d\n", &g_IMs_from_file[i], &g_JMs_from_file[i], &g_KMs_from_file[i]) != 3) {
616 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Expected 3 integers for block %d in %s", i, simCtx->grid_file);
617 }
618 }
619 fclose(fd);
620 }
621
622 // Broadcast nblk to verify (optional, good practice)
623 ierr = MPI_Bcast(&g_nblk_from_file, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
624
625 // Allocate on other ranks before receiving the broadcast
626 if (rank != 0) {
627 ierr = PetscMalloc3(nblk, &g_IMs_from_file, nblk, &g_JMs_from_file, nblk, &g_KMs_from_file); CHKERRQ(ierr);
628 }
629
630 // Broadcast the data arrays
631 ierr = MPI_Bcast(g_IMs_from_file, nblk, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
632 ierr = MPI_Bcast(g_JMs_from_file, nblk, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
633 ierr = MPI_Bcast(g_KMs_from_file, nblk, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
634
635 g_file_has_been_read = PETSC_TRUE;
636 LOG_ALLOW(GLOBAL, LOG_INFO, "Grid file header read and broadcast complete.\n");
637 }
638
639 // --- Per-Block Assignment Logic (runs on every call) ---
640 user->IM = g_IMs_from_file[block_index];
641 user->JM = g_JMs_from_file[block_index];
642 user->KM = g_KMs_from_file[block_index];
643
644 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Set file inputs for Block %d: IM=%d, JM=%d, KM=%d\n",
645 simCtx->rank, block_index, user->IM, user->JM, user->KM);
646
648 PetscFunctionReturn(0);
649}
static PetscInt * g_IMs_from_file
Caches the IM dimensions for all blocks read from the grid file.
Definition io.c:36
static PetscInt g_nblk_from_file
Stores the number of blocks read from the grid file.
Definition io.c:34
static PetscBool g_file_has_been_read
A flag to ensure the grid file is read only once.
Definition io.c:42
static PetscInt * g_KMs_from_file
Caches the KM dimensions for all blocks read from the grid file.
Definition io.c:40
static PetscInt * g_JMs_from_file
Caches the JM dimensions for all blocks read from the grid file.
Definition io.c:38
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:253
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
char grid_file[PETSC_MAX_PATH_LEN]
Definition variables.h:795
Here is the caller graph for this function:

◆ VerifyPathExistence()

PetscErrorCode VerifyPathExistence ( const char *  path,
PetscBool  is_dir,
PetscBool  is_optional,
const char *  description,
PetscBool *  exists 
)

A parallel-safe helper to verify the existence of a generic file or directory path.

This function centralizes the logic for checking arbitrary paths. Only Rank 0 performs the filesystem check, and the result is broadcast to all other processes. This ensures collective and synchronized decision-making across all ranks. It is intended for configuration files, source directories, etc., where the path is known completely.

Parameters
[in]pathThe full path to the file or directory to check.
[in]is_dirPETSC_TRUE if checking for a directory, PETSC_FALSE for a file.
[in]is_optionalPETSC_TRUE if the path is optional (results in a warning), PETSC_FALSE if mandatory (results in an error).
[in]descriptionA user-friendly description of the path for logging (e.g., "Grid file").
[out]existsThe result of the check (identical on all ranks).
Returns
PetscErrorCode

A parallel-safe helper to verify the existence of a generic file or directory path.

Local to this translation unit.

Definition at line 1128 of file io.c.

1129{
1130 PetscErrorCode ierr;
1131 PetscMPIInt rank;
1132 MPI_Comm comm = PETSC_COMM_WORLD;
1133
1134 PetscFunctionBeginUser;
1135 ierr = MPI_Comm_rank(comm, &rank); CHKERRQ(ierr);
1136
1137 if (rank == 0) {
1138 if (is_dir) {
1139 ierr = PetscTestDirectory(path, 'r', exists); CHKERRQ(ierr);
1140 } else {
1141 ierr = PetscTestFile(path, 'r', exists); CHKERRQ(ierr);
1142 }
1143
1144 if (!(*exists)) {
1145 if (is_optional) {
1146 LOG_ALLOW(GLOBAL, LOG_WARNING, "Optional %s not found at: %s (using defaults/ignoring).\n", description, path);
1147 } else {
1148 LOG_ALLOW(GLOBAL, LOG_ERROR, "Mandatory %s not found at: %s\n", description, path);
1149 }
1150 } else {
1151 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Found %s: %s\n", description, path);
1152 }
1153 }
1154
1155 // Broadcast the result from Rank 0
1156 PetscMPIInt exists_int = (rank == 0) ? (PetscMPIInt)(*exists) : 0;
1157 ierr = MPI_Bcast(&exists_int, 1, MPI_INT, 0, comm); CHKERRMPI(ierr);
1158 *exists = (PetscBool)exists_int;
1159
1160 // Collective error for mandatory files
1161 if (!(*exists) && !is_optional) {
1162 SETERRQ(comm, PETSC_ERR_FILE_OPEN, "Mandatory %s not found. Rank 0 expected it at '%s'. Check path and permissions.", description, path);
1163 }
1164
1165 PetscFunctionReturn(0);
1166}
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
Here is the caller graph for this function:

◆ ShouldWriteDataOutput()

PetscBool ShouldWriteDataOutput ( const SimCtx simCtx,
PetscInt  completed_step 
)

Returns whether full field/restart output should be written for the.

completed timestep.

Parameters
simCtxSimulation context controlling the operation.
completed_stepCompleted step index used by the decision helper.
Returns
PetscBool indicating the result of ShouldWriteDataOutput().

Returns whether full field/restart output should be written for the.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
ShouldWriteDataOutput()

Definition at line 432 of file io.c.

433{
434 if (!simCtx) {
435 return PETSC_FALSE;
436 }
437 return (PetscBool)(simCtx->tiout > 0 && completed_step > 0 && completed_step % simCtx->tiout == 0);
438}
PetscInt tiout
Definition variables.h:707
Here is the caller graph for this function:

◆ WriteCheckpointBundle()

PetscErrorCode WriteCheckpointBundle ( SimCtx simCtx,
const char *  reason 
)

Write and atomically publish one complete checkpoint bundle.

Parameters
[in,out]simCtxSimulation context owning all enabled checkpoint state.
[in]reasonStable lifecycle reason such as initial, cadence, final, or signal.
Returns
Zero on success or a PETSc/MPI/filesystem error.

Write and atomically publish one complete checkpoint bundle.

Definition at line 2530 of file io.c.

2531{
2532 UserCtx *user = NULL;
2533 char checkpoints_root[PETSC_MAX_PATH_LEN];
2534 char final_directory[PETSC_MAX_PATH_LEN];
2535 char temporary_directory[PETSC_MAX_PATH_LEN];
2536 char nested_directory[PETSC_MAX_PATH_LEN];
2537 char commit_path[PETSC_MAX_PATH_LEN];
2538 char geometry_digest[65] = "";
2539 char manifest_digest[65] = "";
2540 PetscBool final_exists = PETSC_FALSE;
2541 PetscInt particle_count = 0;
2542 PetscMPIInt writer_pid = 0;
2543
2544 PetscFunctionBeginUser;
2545 PetscCheck(simCtx != NULL && reason != NULL && reason[0] != '\0',
2546 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
2547 "Simulation context and checkpoint reason are required.");
2548 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
2549 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
2550 "Finest-level fields must exist before checkpoint output.");
2551
2552 PetscCall(PetscSNPrintf(checkpoints_root, sizeof(checkpoints_root), "%s/%s",
2554 PetscCall(FormatCheckpointStepDirectory(simCtx->output_dir, simCtx->step,
2555 final_directory, sizeof(final_directory)));
2556 PetscCall(PetscTestDirectory(final_directory, 'r', &final_exists));
2557 if (final_exists) {
2558 PetscReal saved_time = 0.0;
2559 PetscCall(ValidateCheckpointBundle(simCtx, user, final_directory, simCtx->step,
2560 &saved_time, NULL, NULL, NULL, NULL));
2561 PetscCheck(PetscAbsReal(saved_time - simCtx->ti) <=
2562 10.0 * PETSC_MACHINE_EPSILON * PetscMax(1.0, PetscAbsReal(simCtx->ti)),
2563 PETSC_COMM_WORLD, PETSC_ERR_FILE_UNEXPECTED,
2564 "Committed checkpoint step %" PetscInt_FMT " has time %.17g, current state has time %.17g.",
2565 simCtx->step, (double)saved_time, (double)simCtx->ti);
2566 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Checkpoint step %d is already committed; skipping duplicate write.\n",
2567 simCtx->step);
2568 PetscFunctionReturn(0);
2569 }
2570
2571 if (simCtx->rank == 0) writer_pid = (PetscMPIInt)getpid();
2572 PetscCallMPI(MPI_Bcast(&writer_pid, 1, MPI_INT, 0, PETSC_COMM_WORLD));
2573 PetscCall(PetscSNPrintf(temporary_directory, sizeof(temporary_directory),
2574 "%s/.step_%0*" PetscInt_FMT ".incomplete.%d",
2575 checkpoints_root, PICURV_CHECKPOINT_STEP_WIDTH,
2576 simCtx->step, (int)writer_pid));
2577 PetscCall(CreateCheckpointDirectoryCollective(simCtx, checkpoints_root));
2578 PetscCall(CreateCheckpointDirectoryCollective(simCtx, temporary_directory));
2579 PetscCall(PetscSNPrintf(nested_directory, sizeof(nested_directory), "%s/%s",
2580 temporary_directory, PICURV_EULERIAN_DIRECTORY));
2581 PetscCall(CreateCheckpointDirectoryCollective(simCtx, nested_directory));
2582 for (PetscInt block = 0; block < simCtx->block_number; ++block) {
2583 PetscCall(PetscSNPrintf(nested_directory, sizeof(nested_directory),
2584 "%s/%s/block_%04" PetscInt_FMT,
2585 temporary_directory, PICURV_EULERIAN_DIRECTORY, block));
2586 PetscCall(CreateCheckpointDirectoryCollective(simCtx, nested_directory));
2587 }
2588 if (simCtx->np > 0) {
2589 PetscCall(PetscSNPrintf(nested_directory, sizeof(nested_directory), "%s/%s",
2590 temporary_directory, PICURV_PARTICLE_DIRECTORY));
2591 PetscCall(CreateCheckpointDirectoryCollective(simCtx, nested_directory));
2592 PetscCall(DMSwarmGetSize(user->swarm, &particle_count));
2593 }
2594 if (FieldStatisticsIsActive(simCtx)) {
2595 PetscCall(FormatStatisticsPath(temporary_directory, -1, -1, NULL,
2596 nested_directory, sizeof(nested_directory)));
2597 PetscCall(CreateCheckpointDirectoryCollective(simCtx, nested_directory));
2598 for (PetscInt window = 0; window < simCtx->fieldStatisticsWindowCount; ++window) {
2599 PetscCall(FormatStatisticsPath(temporary_directory, window, -1, NULL,
2600 nested_directory, sizeof(nested_directory)));
2601 PetscCall(CreateCheckpointDirectoryCollective(simCtx, nested_directory));
2602 for (PetscInt block = 0; block < simCtx->block_number; ++block) {
2603 PetscCall(FormatStatisticsPath(temporary_directory, window, block, NULL,
2604 nested_directory, sizeof(nested_directory)));
2605 PetscCall(CreateCheckpointDirectoryCollective(simCtx, nested_directory));
2606 }
2607 }
2608 }
2609
2610 PetscCall(ComputeCheckpointGeometrySHA256(simCtx, user, geometry_digest));
2611 for (PetscInt block = 0; block < simCtx->block_number; ++block) {
2612 PetscCall(WriteSimulationFields(&user[block], temporary_directory));
2613 }
2614 if (simCtx->np > 0) PetscCall(WriteAllSwarmFields(user, temporary_directory));
2615 for (PetscInt block = 0; block < simCtx->block_number; ++block) {
2616 PetscCall(WriteStatisticsFields(&user[block], temporary_directory));
2617 }
2618 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
2619
2620 PetscCall(WriteCheckpointManifest(simCtx, user, temporary_directory, reason,
2621 geometry_digest, particle_count, manifest_digest));
2622 if (simCtx->rank == 0) {
2623 FILE *commit_file = NULL;
2624
2625 PetscCall(PetscSNPrintf(commit_path, sizeof(commit_path), "%s/COMMITTED", temporary_directory));
2626 commit_file = fopen(commit_path, "w");
2627 PetscCheck(commit_file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
2628 "Unable to create checkpoint commit marker '%s'.", commit_path);
2629 PetscCheck(fprintf(commit_file, "%s\n", manifest_digest) > 0 &&
2630 fflush(commit_file) == 0 && fsync(fileno(commit_file)) == 0,
2631 PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
2632 "Unable to write checkpoint commit marker '%s'.", commit_path);
2633 PetscCheck(fclose(commit_file) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
2634 "Unable to close checkpoint commit marker '%s'.", commit_path);
2635 PetscCheck(rename(temporary_directory, final_directory) == 0,
2636 PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
2637 "Unable to commit checkpoint '%s': %s", final_directory, strerror(errno));
2638 }
2639 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
2641 "Committed checkpoint step %d at t=%.17g (%s): %s\n",
2642 simCtx->step, (double)simCtx->ti, reason, final_directory);
2643 PetscFunctionReturn(0);
2644}
#define PICURV_CHECKPOINT_STEP_WIDTH
Definition io.c:27
#define PICURV_CHECKPOINTS_DIRECTORY
Definition io.c:23
PetscErrorCode WriteAllSwarmFields(UserCtx *user, const char *checkpoint_directory)
Internal helper implementation: WriteAllSwarmFields().
Definition io.c:2196
static PetscErrorCode FormatStatisticsPath(const char *root, PetscInt window, PetscInt block, const char *payload_name, char *path, size_t path_size)
Format any level of the statistics subtree, from the root down to one payload.
Definition io.c:99
static PetscErrorCode ValidateCheckpointBundle(SimCtx *simCtx, UserCtx *user, const char *checkpoint_directory, PetscInt expected_step, PetscReal *physical_time, PetscInt *particle_count, PetscBool *particles_saved, PetscBool *les_saved, PetscBool *rans_saved)
Validate a committed bundle and return selected authoritative metadata.
Definition io.c:252
#define PICURV_PARTICLE_DIRECTORY
Definition io.c:25
static PetscErrorCode FormatCheckpointStepDirectory(const char *root, PetscInt step, char *path, size_t path_size)
Format the canonical directory name for one completed step.
Definition io.c:204
PetscErrorCode WriteSimulationFields(UserCtx *user, const char *checkpoint_directory)
Implementation of WriteSimulationFields().
Definition io.c:2002
static PetscErrorCode CreateCheckpointDirectoryCollective(const SimCtx *simCtx, const char *path)
Create one directory on rank zero and report failures collectively.
Definition io.c:232
static PetscErrorCode ComputeCheckpointGeometrySHA256(SimCtx *simCtx, UserCtx *user, char digest_hex[65])
Compute and cache a rank-count-independent hash of the active grid geometry.
Definition io.c:155
static PetscErrorCode WriteStatisticsFields(UserCtx *user, const char *checkpoint_directory)
Write every window's accumulator payloads for one block into a bundle.
Definition io.c:2034
#define PICURV_EULERIAN_DIRECTORY
Definition io.c:24
static PetscErrorCode WriteCheckpointManifest(SimCtx *simCtx, UserCtx *user, const char *checkpoint_directory, const char *reason, const char *geometry_digest, PetscInt particle_count, char manifest_digest[65])
Write the complete manifest after every payload has closed successfully.
Definition io.c:2282
PetscBool FieldStatisticsIsActive(const struct SimCtx *simCtx)
Reports whether this run has live field-statistics state.
PetscInt fieldStatisticsWindowCount
Definition variables.h:770
UserCtx * user
Definition variables.h:571
UserMG usermg
Definition variables.h:852
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:717
PetscInt np
Definition variables.h:827
PetscInt mglevels
Definition variables.h:578
PetscInt step
Definition variables.h:703
MGCtx * mgctx
Definition variables.h:581
PetscReal ti
Definition variables.h:704
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:

◆ ReadSimulationFields()

PetscErrorCode ReadSimulationFields ( UserCtx user,
PetscInt  ti 
)

Reads binary field data for velocity, pressure, and other required vectors.

Validates one committed checkpoint bundle and reads every enabled Eulerian checkpoint field through the field catalog.

Parameters
[in,out]userPointer to the UserCtx structure containing the simulation context.
[in]tiCheckpoint step resolved below the configured source root.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads binary field data for velocity, pressure, and other required vectors.

Local to this translation unit.

Definition at line 1463 of file io.c.

1464{
1465 SimCtx *simCtx = user->simCtx;
1466 const char *source_path = NULL;
1467 char checkpoint_directory[PETSC_MAX_PATH_LEN];
1468 PetscReal checkpoint_time = 0.0;
1469 PetscBool particles_saved = PETSC_FALSE;
1470 PetscBool les_saved = PETSC_FALSE;
1471 PetscBool rans_saved = PETSC_FALSE;
1472
1473 PetscFunctionBeginUser;
1474 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1475 source_path = simCtx->pps->source_dir;
1476 } else if(simCtx->exec_mode == EXEC_MODE_SOLVER){
1477 source_path = simCtx->restart_dir;
1478 } else{
1479 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Invalid execution mode for reading simulation fields.");
1480 }
1481
1482 PetscCall(ResolveCheckpointStepDirectory(source_path, ti,
1483 checkpoint_directory, sizeof(checkpoint_directory)));
1484 PetscCall(ValidateCheckpointBundle(simCtx, user - user->_this,
1485 checkpoint_directory, ti, &checkpoint_time, NULL,
1486 &particles_saved, &les_saved, &rans_saved));
1487 PetscCheck(!(simCtx->np > 0 && !strcmp(simCtx->particleRestartMode, "load")) || particles_saved,
1488 PETSC_COMM_WORLD, PETSC_ERR_FILE_UNEXPECTED,
1489 "Particle restart_mode=load was requested, but checkpoint step %" PetscInt_FMT
1490 " contains no particle state.", ti);
1491 if (simCtx->exec_mode == EXEC_MODE_SOLVER && user->_this == 0) {
1492 simCtx->ti = checkpoint_time;
1493 if (ti == simCtx->StartStep) simCtx->StartTime = checkpoint_time;
1494 PetscCall(RestoreDrivenFluxTarget(simCtx, user, checkpoint_directory));
1495 }
1496
1497 LOG_ALLOW(GLOBAL, LOG_INFO, "Reading Eulerian checkpoint fields for block %d from '%s'.\n",
1498 user->_this, checkpoint_directory);
1499 PetscCall(PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
1500 "%s/%s/block_%04" PetscInt_FMT,
1501 checkpoint_directory, PICURV_EULERIAN_DIRECTORY, user->_this));
1502 simCtx->current_io_directory = simCtx->_io_context_buffer;
1503
1504 for (PetscInt raw_id = 0; raw_id < FIELD_ID_COUNT; ++raw_id) {
1505 const FieldDescriptor *descriptor = NULL;
1506 FieldView view;
1507
1508 PetscCall(FieldGetDescriptor((FieldId)raw_id, &descriptor));
1509 if (!CheckpointFieldIsEnabled(simCtx, descriptor)) continue;
1510 if ((descriptor->availability & FIELD_AVAILABILITY_PARTICLES) &&
1511 (!particles_saved || strcmp(simCtx->particleRestartMode, "load"))) continue;
1512 if ((descriptor->availability & FIELD_AVAILABILITY_LES) && !les_saved) continue;
1513 if ((descriptor->availability & FIELD_AVAILABILITY_RANS) && !rans_saved) continue;
1514 if ((descriptor->availability & FIELD_AVAILABILITY_TURBULENCE) &&
1515 !((simCtx->les && les_saved) || (simCtx->rans && rans_saved))) continue;
1516 PetscCall(FieldGetView(user, descriptor->id, &view));
1517 PetscCall(ReadFieldData(user, descriptor->canonical_name, view.global_vec, "dat"));
1518 if (view.local_vec) PetscCall(UpdateLocalGhosts(user, descriptor->id));
1519 }
1520 if (simCtx->rans) {
1521 PetscCall(VecCopy(user->K_Omega, user->K_Omega_o));
1522 PetscCall(UpdateLocalGhosts(user, FIELD_ID_K_OMEGA_O));
1523 }
1524 simCtx->restartHistoryAvailable = PETSC_TRUE;
1525 simCtx->current_io_directory = NULL;
1526 PetscFunctionReturn(0);
1527}
@ FIELD_AVAILABILITY_RANS
@ FIELD_AVAILABILITY_LES
@ FIELD_AVAILABILITY_PARTICLES
@ FIELD_AVAILABILITY_TURBULENCE
unsigned int availability
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Resolve the existing DM and global/local vectors for one field.
const char * canonical_name
PetscErrorCode FieldGetDescriptor(FieldId field_id, const FieldDescriptor **descriptor)
Return immutable metadata for a valid field identifier.
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_K_OMEGA_O
@ FIELD_ID_COUNT
Immutable metadata for one field identity.
Non-owning runtime objects resolved for one field and UserCtx.
static PetscErrorCode RestoreDrivenFluxTarget(SimCtx *simCtx, UserCtx *user, const char *checkpoint_directory)
Restore a latched driven-flow flux target from a checkpoint manifest.
Definition io.c:1412
PetscErrorCode ReadFieldData(UserCtx *user, const char *field_name, Vec field_vec, const char *ext)
Internal helper implementation: ReadFieldData().
Definition io.c:1174
static PetscErrorCode ResolveCheckpointStepDirectory(const char *source_root, PetscInt step, char *path, size_t path_size)
Resolve either an exact bundle or a run/output root to one step bundle.
Definition io.c:215
static PetscBool CheckpointFieldIsEnabled(const SimCtx *simCtx, const FieldDescriptor *descriptor)
Return whether a catalogued field belongs in the current checkpoint.
Definition io.c:72
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1838
PetscInt rans
Definition variables.h:821
PetscReal StartTime
Definition variables.h:709
Vec K_Omega_o
Definition variables.h:982
Vec K_Omega
Definition variables.h:982
PetscInt StartStep
Definition variables.h:705
char * current_io_directory
Definition variables.h:720
char particleRestartMode[16]
Definition variables.h:833
char source_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:598
PostProcessParams * pps
Definition variables.h:890
@ EXEC_MODE_SOLVER
Definition variables.h:668
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:669
char _io_context_buffer[PETSC_MAX_PATH_LEN]
Definition variables.h:719
PetscInt les
Definition variables.h:821
ExecutionMode exec_mode
Definition variables.h:714
PetscBool restartHistoryAvailable
Definition variables.h:723
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:716
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RestoreFieldStatisticsState()

PetscErrorCode RestoreFieldStatisticsState ( SimCtx simCtx,
PetscInt  ti 
)

Restores field-statistics window state and accumulators from a checkpoint.

Resumes every configured window from the bundle at ti when continuation was requested, per 7. Checkpoints, Restart, and Continuation. Window scalars come from the bundle manifest and accumulator payloads through the same natural-ordering vector reader Eulerian fields use, so a restart on a different MPI rank count restores identical state.

Does nothing when statistics are disabled, no window is configured, or continuation was not requested. Anything else is fatal rather than silently zeroed: a window count mismatch, a renamed window, a changed definition hash, a requested end earlier than the represented span, or missing state.

Parameters
[in,out]simCtxSimulation context carrying the windows and accumulators.
[in]tiStep whose committed bundle supplies the state.
Returns
Zero on success, or a PETSc error when continuation cannot be honored.

Restores field-statistics window state and accumulators from a checkpoint.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
RestoreFieldStatisticsState()

Definition at line 1667 of file io.c.

1668{
1669 UserCtx *user = NULL;
1670 PetscOptions options = NULL;
1671 char checkpoint_directory[PETSC_MAX_PATH_LEN];
1672 char metadata_path[PETSC_MAX_PATH_LEN];
1673 const char *source_path = NULL;
1674 PetscInt saved_window_count = 0;
1675 PetscReal checkpoint_time = 0.0;
1676 PetscBool found = PETSC_FALSE;
1677
1678 PetscFunctionBeginUser;
1680 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL.");
1681 if (!FieldStatisticsIsActive(simCtx)) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
1682 if (!simCtx->fieldStatisticsContinue) {
1684 "Statistics continuation was not requested; %d window(s) start from zero.\n",
1687 PetscFunctionReturn(0);
1688 }
1689
1690 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1691 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
1692 "Finest-level fields must exist before statistics state is restored.");
1693 source_path = (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) ? simCtx->pps->source_dir
1694 : simCtx->restart_dir;
1695 PetscCheck(source_path != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
1696 "No checkpoint source directory is set for the current execution mode.");
1697 PetscCall(ResolveCheckpointStepDirectory(source_path, ti,
1698 checkpoint_directory, sizeof(checkpoint_directory)));
1699 PetscCall(ValidateCheckpointBundle(simCtx, user, checkpoint_directory, ti,
1700 &checkpoint_time, NULL, NULL, NULL, NULL));
1701 PetscCall(PetscSNPrintf(metadata_path, sizeof(metadata_path), "%s/checkpoint.meta",
1702 checkpoint_directory));
1703
1704 PetscCall(PetscOptionsCreate(&options));
1705 PetscCall(PetscOptionsInsertFile(PETSC_COMM_WORLD, options, metadata_path, PETSC_TRUE));
1706 PetscCall(PetscOptionsGetInt(options, NULL, "-checkpoint_statistics_window_count",
1707 &saved_window_count, &found));
1708 /* Missing state for a requested continuation is fatal and never silently
1709 * zeroed: resuming from zero would report a converged average built from a
1710 * fraction of the samples its metadata claims. */
1711 PetscCheck(found && saved_window_count == simCtx->fieldStatisticsWindowCount,
1712 PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP,
1713 "Statistics continuation requested, but checkpoint '%s' holds %" PetscInt_FMT
1714 " window(s) and this run configures %" PetscInt_FMT ".",
1715 checkpoint_directory, found ? saved_window_count : 0,
1716 simCtx->fieldStatisticsWindowCount);
1717
1718 for (PetscInt window = 0; window < simCtx->fieldStatisticsWindowCount; ++window) {
1719 PetscCall(ReadStatisticsWindowState(options, window, metadata_path, checkpoint_time,
1720 simCtx->dt, simCtx->exec_mode,
1721 &simCtx->fieldStatisticsWindows[window]));
1722 }
1723 PetscCall(PetscOptionsDestroy(&options));
1724
1725 for (PetscInt block = 0; block < simCtx->block_number; ++block) {
1726 PetscCheck(user[block].fieldStatisticsStorage != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
1727 "Statistics accumulators were not allocated for block %" PetscInt_FMT ".", block);
1728 for (PetscInt window = 0; window < simCtx->fieldStatisticsWindowCount; ++window) {
1729 const PicurvWindowDefinition *definition = &simCtx->fieldStatisticsWindows[window].definition;
1730 const PicurvWindowStorage *storage = &user[block].fieldStatisticsStorage[window];
1731 PetscInt payload_count = 0;
1732
1733 PetscCall(FormatStatisticsPath(checkpoint_directory, window, block, NULL,
1734 simCtx->_io_context_buffer,
1735 sizeof(simCtx->_io_context_buffer)));
1736 simCtx->current_io_directory = simCtx->_io_context_buffer;
1737 PetscCall(PicurvWindowStoragePayloadCount(storage, &payload_count));
1738 for (PetscInt index = 0; index < payload_count; ++index) {
1740
1741 PetscCall(PicurvWindowStoragePayload(&user[block], definition, storage, index, &payload));
1742 PetscCall(ReadFieldData(&user[block], payload.name, payload.vec, "dat"));
1743 }
1744 }
1745 simCtx->current_io_directory = NULL;
1746 }
1747
1748 for (PetscInt window = 0; window < simCtx->fieldStatisticsWindowCount; ++window) {
1749 const PicurvWindow *state = &simCtx->fieldStatisticsWindows[window];
1750
1752 "Statistics window '%s' continued from '%s': state %s, %d sample(s), "
1753 "total weight %.6g, represented time %.6g, restart segment %d.\n",
1754 state->definition.name, checkpoint_directory,
1756 (double)state->total_weight, (double)state->represented_time,
1757 state->restart_count);
1758 }
1760 PetscFunctionReturn(0);
1761}
static PetscErrorCode ReadStatisticsWindowState(PetscOptions options, PetscInt window, const char *metadata_path, PetscReal checkpoint_time, PetscReal step_size, ExecutionMode exec_mode, PicurvWindow *state)
Restore one window's scalar bookkeeping from a validated manifest.
Definition io.c:1533
Vec vec
Borrowed accumulator vector; never owned by the caller.
PetscErrorCode PicurvWindowStoragePayload(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt index, PicurvStatisticsPayload *payload)
Resolves one enumerated payload of a window's storage.
char name[96]
File basename, no extension.
PetscErrorCode PicurvWindowStoragePayloadCount(const PicurvWindowStorage *storage, PetscInt *count)
Reports how many checkpointable vectors one window's storage holds.
One checkpointable accumulator vector, resolved by enumeration index.
Independent accumulator state for one window on one block.
PetscInt sample_count
PicurvWindowState state
PetscInt restart_count
Restart segments this state descends from.
PetscReal total_weight
const char * PicurvWindowStateName(PicurvWindowState state)
Returns a stable human-readable name for a window state.
PicurvWindowDefinition definition
PetscReal represented_time
Physical time the window covers.
Runtime state of one window.
The scientifically immutable definition of one window.
PetscReal dt
Definition variables.h:710
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:771
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:962
PetscBool fieldStatisticsContinue
Definition variables.h:776
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadFieldData()

PetscErrorCode ReadFieldData ( UserCtx user,
const char *  field_name,
Vec  field_vec,
const char *  ext 
)

Reads data for a specific field from a file into the provided vector.

This function uses the field name to construct the file path and reads the data from the corresponding file into the provided PETSc vector.

Parameters
[in]userPointer to the UserCtx structure containing simulation context.
[in]field_nameName of the field (e.g., "ufield", "vfield", "pfield").
[out]field_vecPETSc vector to store the field data.
[in]extFile extension (e.g., "dat").
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads data for a specific field from a file into the provided vector.

Local to this translation unit.

Definition at line 1174 of file io.c.

1178{
1179 PetscErrorCode ierr;
1180 char filename[PETSC_MAX_PATH_LEN];
1181 MPI_Comm comm;
1182 PetscMPIInt rank,size;
1183 SimCtx *simCtx = user->simCtx;
1184
1185
1186 PetscFunctionBeginUser;
1188
1189 if(!simCtx->current_io_directory){
1190 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "I/O context directory was not set before calling ReadFieldData().");
1191 }
1192
1193
1194 ierr = PetscObjectGetComm((PetscObject)field_vec,&comm);CHKERRQ(ierr);
1195 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1196 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1197
1198 const char *source_path = NULL;
1199 source_path = simCtx->current_io_directory;
1200
1201 if(!source_path){
1202 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "source_path was not set for the current execution mode.");
1203 }
1204 ierr = PetscSNPrintf(filename, sizeof(filename), "%s/%s.%s",
1205 source_path, field_name, ext); CHKERRQ(ierr);
1206
1208 "Attempting to read <%s> on rank %d/%d\n",
1209 filename,(int)rank,(int)size);
1210
1211 /* ======================================================================
1212 * 1. SERIAL JOB – just hand the Vec to VecLoad()
1213 * ==================================================================== */
1214 if(size==1)
1215 {
1216 PetscViewer viewer;
1217 PetscBool found;
1218 Vec temp_vec;
1219 PetscInt expectedSize,loadedSize;
1220
1221 ierr = PetscTestFile(filename,'r',&found);CHKERRQ(ierr);
1222 if(!found) SETERRQ(comm,PETSC_ERR_FILE_OPEN,
1223 "Restart/Source file not found: %s",filename);
1224
1225 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr);
1226// ---- START MODIFICATION ----
1227 // DO NOT load directly into field_vec, as this can resize it, which is
1228 // illegal for DMSwarm "view" vectors. Instead, load into a temporary vector.
1229 ierr = VecCreate(PETSC_COMM_SELF, &temp_vec); CHKERRQ(ierr);
1230 ierr = VecLoad(temp_vec,viewer);CHKERRQ(ierr);
1231 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1232
1233 // Sanity check: ensure the file size matches the expected vector size.
1234 ierr = VecGetSize(field_vec, &expectedSize);CHKERRQ(ierr);
1235 ierr = VecGetSize(temp_vec, &loadedSize);CHKERRQ(ierr);
1236 if (loadedSize != expectedSize) {
1237 SETERRQ(comm,PETSC_ERR_FILE_UNEXPECTED,
1238 "File %s holds %d entries – expected %d for field '%s'",
1239 filename, loadedSize, expectedSize, field_name);
1240 }
1241
1242 // Now, safely copy the data from the temporary vector to the final destination.
1243 ierr = VecCopy(temp_vec, field_vec);CHKERRQ(ierr);
1244
1245 // Clean up the temporary vector.
1246 ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
1247
1248 // ---- END MODIFICATION ----
1249
1250 /* create EMPTY sequential Vec – VecLoad() will size it correctly */
1251 /*
1252 ierr = VecCreate(PETSC_COMM_SELF,&seq_vec);CHKERRQ(ierr);
1253 ierr = VecSetType(seq_vec,VECSEQ);CHKERRQ(ierr);
1254
1255 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,
1256 FILE_MODE_READ,&viewer);CHKERRQ(ierr);
1257
1258 ierr = VecLoad(field_vec,viewer);CHKERRQ(ierr);
1259 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1260 */
1262 "Loaded <%s> (serial path)\n",filename);
1263
1265 PetscFunctionReturn(0);
1266 }
1267
1268 /* ======================================================================
1269 * 2. PARALLEL JOB
1270 * ==================================================================== */
1271 PetscInt globalSize;
1272 ierr = VecGetSize(field_vec,&globalSize);CHKERRQ(ierr);
1273
1274 DM dm = NULL;
1275 const char *dmtype = NULL;
1276 Vec nat = NULL; /* Natural-ordered vector for DMDA */
1277
1278 /* -------------------- rank-0 : read the sequential file -------------- */
1279 Vec seq_vec = NULL; /* only valid on rank-0 */
1280 const PetscScalar *seqArray = NULL; /* borrowed pointer on rank-0 only */
1281
1282 if(rank==0)
1283 {
1284 PetscViewer viewer;
1285 PetscBool found;
1286
1287 ierr = PetscTestFile(filename,'r',&found);CHKERRQ(ierr);
1288 if(!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,
1289 "Restart file not found: %s",filename);
1290
1291 /* create EMPTY sequential Vec – VecLoad() will size it correctly */
1292 ierr = VecCreate(PETSC_COMM_SELF,&seq_vec);CHKERRQ(ierr);
1293 ierr = VecSetType(seq_vec,VECSEQ);CHKERRQ(ierr);
1294
1295 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,
1296 FILE_MODE_READ,&viewer);CHKERRQ(ierr);
1297 ierr = VecLoad(seq_vec,viewer);CHKERRQ(ierr);
1298 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1299
1300 /* size sanity-check */
1301 PetscInt loaded;
1302 ierr = VecGetSize(seq_vec,&loaded);CHKERRQ(ierr);
1303 if(loaded != globalSize)
1304 SETERRQ(comm,PETSC_ERR_FILE_UNEXPECTED,
1305 "File %s holds %d entries – expected %d",
1306 filename,loaded,globalSize);
1307
1308 /* borrow array for later Bcast */
1309 ierr = VecGetArrayRead(seq_vec,&seqArray);CHKERRQ(ierr);
1310
1312 "Rank 0 successfully loaded <%s>\n",filename);
1313 }
1314
1315 /* -------------------- Check if this is a DMDA vector ----------------- */
1316 ierr = VecGetDM(field_vec, &dm); CHKERRQ(ierr);
1317 if (dm) { ierr = DMGetType(dm, &dmtype); CHKERRQ(ierr); }
1318
1319 if (dmtype && !strcmp(dmtype, DMDA)) {
1320 /* ==================================================================
1321 * DMDA PATH: File is in natural ordering, need to convert to global
1322 * ================================================================== */
1323
1324 /* Create natural vector */
1325 ierr = DMDACreateNaturalVector(dm, &nat); CHKERRQ(ierr);
1326
1327 /* Scatter from rank 0's seq_vec to all ranks' natural vector */
1328 VecScatter scatter;
1329 Vec nat_seq = NULL; /* Sequential natural vector on rank 0 */
1330
1331 ierr = VecScatterCreateToZero(nat, &scatter, &nat_seq); CHKERRQ(ierr);
1332
1333 /* Reverse scatter: from rank 0 to all ranks */
1334 ierr = VecScatterBegin(scatter, (rank == 0 ? seq_vec : nat_seq), nat,
1335 INSERT_VALUES, SCATTER_REVERSE); CHKERRQ(ierr);
1336 ierr = VecScatterEnd(scatter, (rank == 0 ? seq_vec : nat_seq), nat,
1337 INSERT_VALUES, SCATTER_REVERSE); CHKERRQ(ierr);
1338
1339 /* Convert natural → global ordering */
1340 ierr = DMDANaturalToGlobalBegin(dm, nat, INSERT_VALUES, field_vec); CHKERRQ(ierr);
1341 ierr = DMDANaturalToGlobalEnd(dm, nat, INSERT_VALUES, field_vec); CHKERRQ(ierr);
1342
1343 /* Cleanup */
1344 ierr = VecScatterDestroy(&scatter); CHKERRQ(ierr);
1345 ierr = VecDestroy(&nat_seq); CHKERRQ(ierr);
1346 ierr = VecDestroy(&nat); CHKERRQ(ierr);
1347
1348 } else {
1349 /* ==================================================================
1350 * NON-DMDA PATH: Use broadcast and direct copy (assumes global ordering)
1351 * ================================================================== */
1352
1353 PetscScalar *buffer = NULL;
1354 if (rank == 0) {
1355 buffer = (PetscScalar *)seqArray;
1356 } else {
1357 ierr = PetscMalloc1(globalSize, &buffer); CHKERRQ(ierr);
1358 }
1359
1360 ierr = MPI_Bcast(buffer, (int)globalSize, MPIU_SCALAR, 0, comm); CHKERRQ(ierr);
1361
1362 /* Copy slice based on ownership range */
1363 PetscInt rstart, rend, loc;
1364 PetscScalar *locArray;
1365
1366 ierr = VecGetOwnershipRange(field_vec, &rstart, &rend); CHKERRQ(ierr);
1367 loc = rend - rstart;
1368
1369 ierr = VecGetArray(field_vec, &locArray); CHKERRQ(ierr);
1370 ierr = PetscMemcpy(locArray, buffer + rstart, loc * sizeof(PetscScalar)); CHKERRQ(ierr);
1371 ierr = VecRestoreArray(field_vec, &locArray); CHKERRQ(ierr);
1372
1373 if (rank != 0) {
1374 ierr = PetscFree(buffer); CHKERRQ(ierr);
1375 }
1376 }
1377
1378 /* -------------------- tidy up ---------------------------------------- */
1379 if (rank == 0) {
1380 ierr = VecRestoreArrayRead(seq_vec, &seqArray); CHKERRQ(ierr);
1381 ierr = VecDestroy(&seq_vec); CHKERRQ(ierr);
1382 }
1383
1385 "Loaded <%s> (parallel path)\n",filename);
1386
1388 PetscFunctionReturn(0);
1389}
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:33
Here is the caller graph for this function:

◆ WriteFieldData()

PetscErrorCode WriteFieldData ( UserCtx user,
const char *  field_name,
Vec  field_vec,
const char *  ext 
)

Writes data from a specific PETSc vector to a file.

This function uses the field name to construct the file path and writes the data from the provided PETSc vector to the corresponding file.

Parameters
[in]userPointer to the UserCtx structure containing simulation context.
[in]field_nameName of the field (e.g., "ufield", "vfield", "pfield").
[in]field_vecPETSc vector containing the field data to write.
[in]extFile extension (e.g., "dat").
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Writes data from a specific PETSc vector to a file.

Local to this translation unit.

Definition at line 1947 of file io.c.

1951{
1952 MPI_Comm comm;
1953 PetscMPIInt rank;
1954 Vec sequential_vec = NULL;
1955 char filename[PETSC_MAX_PATH_LEN];
1956 SimCtx *simCtx=user->simCtx;
1957
1958 PetscFunctionBeginUser;
1960
1961 if(!simCtx->current_io_directory){
1962 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "I/O context directory was not set before calling WriteFieldData().");
1963 }
1964
1965 /* ------------------------------------------------------------ */
1966 /* Basic communicator information */
1967 /* ------------------------------------------------------------ */
1968 PetscCall(PetscObjectGetComm((PetscObject)field_vec,&comm));
1969 PetscCallMPI(MPI_Comm_rank(comm,&rank));
1970
1971 PetscCall(PetscSNPrintf(filename, sizeof(filename), "%s/%s.%s",
1972 simCtx->current_io_directory, field_name, ext));
1973
1974 PetscCall(GatherVectorToRankZero(field_vec, &sequential_vec));
1975 if (rank == 0) {
1976 PetscViewer viewer;
1977 PetscReal vmin, vmax;
1978
1979 PetscCall(VecMin(sequential_vec, NULL, &vmin));
1980 PetscCall(VecMax(sequential_vec, NULL, &vmax));
1982 " <%s> range = [%.4e … %.4e]\n",
1983 field_name,(double)vmin,(double)vmax);
1984 PetscCall(PetscViewerBinaryOpen(PETSC_COMM_SELF, filename, FILE_MODE_WRITE, &viewer));
1985 PetscCall(PetscViewerBinarySetSkipInfo(viewer, PETSC_TRUE));
1986 PetscCall(VecView(sequential_vec, viewer));
1987 PetscCall(PetscViewerDestroy(&viewer));
1988 LOG_ALLOW(GLOBAL, LOG_INFO, "Wrote <%s>\n", filename);
1989 }
1990 PetscCall(VecDestroy(&sequential_vec));
1991
1993 PetscFunctionReturn(0);
1994}
static PetscErrorCode GatherVectorToRankZero(Vec field_vec, Vec *sequential_vec)
Gather a vector in decomposition-independent natural ordering onto rank zero.
Definition io.c:124
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteSimulationFields()

PetscErrorCode WriteSimulationFields ( UserCtx user,
const char *  checkpoint_directory 
)

Writes simulation fields to files.

This function writes contravariant velocity, Cartesian velocity, pressure, and node state fields to their respective binary files. It also conditionally writes LES and RANS model fields when those models are enabled.

Parameters
[in]userPointer to the UserCtx structure containing simulation context.
[in]checkpoint_directoryRoot of the in-progress checkpoint bundle.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Writes simulation fields to files.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
WriteSimulationFields()

Definition at line 2002 of file io.c.

2003{
2004 SimCtx *simCtx = user->simCtx;
2005
2006 PetscFunctionBeginUser;
2007 PetscCheck(checkpoint_directory != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
2008 "Checkpoint destination cannot be NULL.");
2009 PetscCall(PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
2010 "%s/%s/block_%04" PetscInt_FMT,
2011 checkpoint_directory, PICURV_EULERIAN_DIRECTORY, user->_this));
2012 simCtx->current_io_directory = simCtx->_io_context_buffer;
2013
2014 if (simCtx->les) {
2015 PetscCall(CopyOwnedLocalScalarToGlobal(user->da, user->lCs, user->CS));
2016 PetscCall(CopyOwnedLocalScalarToGlobal(user->da, user->lNu_t, user->Nu_t));
2017 }
2018 for (PetscInt raw_id = 0; raw_id < FIELD_ID_COUNT; ++raw_id) {
2019 const FieldDescriptor *descriptor = NULL;
2020 FieldView view;
2021
2022 PetscCall(FieldGetDescriptor((FieldId)raw_id, &descriptor));
2023 if (!CheckpointFieldIsEnabled(simCtx, descriptor)) continue;
2024 PetscCall(FieldGetView(user, descriptor->id, &view));
2025 PetscCall(WriteFieldData(user, descriptor->canonical_name, view.global_vec, "dat"));
2026 }
2027 simCtx->current_io_directory = NULL;
2028 PetscFunctionReturn(0);
2029}
static PetscErrorCode CopyOwnedLocalScalarToGlobal(DM dm, Vec local_vec, Vec global_vec)
Copies the owned entries of a ghosted scalar DMDA vector to its global vector.
Definition io.c:51
PetscErrorCode WriteFieldData(UserCtx *user, const char *field_name, Vec field_vec, const char *ext)
Internal helper implementation: WriteFieldData().
Definition io.c:1947
Vec lCs
Definition variables.h:982
Vec lNu_t
Definition variables.h:982
Vec Nu_t
Definition variables.h:982
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteSwarmField()

PetscErrorCode WriteSwarmField ( UserCtx user,
const char *  field_name,
const char *  ext 
)

Writes data from a specific field in a PETSc Swarm to a file.

This function retrieves the Swarm from the UserCtx (i.e., user->swarm) and creates a global PETSc vector from the specified Swarm field. It then calls the existing WriteFieldData() function to handle the actual I/O operation. After writing the data, the function destroys the temporary global vector to avoid memory leaks.

Parameters
[in]userPointer to the UserCtx structure containing simulation context and the PetscSwarm (as user->swarm).
[in]field_nameName of the Swarm field to be written (e.g., "my_field").
[in]extFile extension (e.g., "dat", "bin").
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.
Note
Compatible with PETSc 3.14.4.

Writes data from a specific field in a PETSc Swarm to a file.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
WriteSwarmField()

Definition at line 2076 of file io.c.

2077{
2078 PetscErrorCode ierr;
2079 Vec fieldVec;
2080 DM swarm;
2081
2082 PetscFunctionBeginUser; /* PETSc macro indicating start of function */
2083
2084 /*
2085 * 1) Retrieve the PetscSwarm from the user context.
2086 * Ensure user->swarm is initialized and not NULL.
2087 */
2088 swarm = user->swarm;
2089
2090 /*
2091 * 2) Create a global vector from the specified swarm field.
2092 * This function is available in PETSc 3.14.4.
2093 * It provides a read/write "view" of the swarm field as a global Vec.
2094 */
2096 "Attempting to create global vector from field: %s\n",
2097 field_name);
2098 ierr = DMSwarmCreateGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
2099
2100 /*
2101 * 3) Use your existing WriteFieldData() to write the global vector to a file.
2102 * The field name, time index, and extension are passed along for naming.
2103 */
2105 "Calling WriteFieldData for field: %s\n",
2106 field_name);
2107 ierr = WriteFieldData(user, field_name, fieldVec, ext);CHKERRQ(ierr);
2108
2109 /*
2110 * 4) Destroy the global vector once the data is successfully written.
2111 * This step is crucial for avoiding memory leaks.
2112 * DMSwarmDestroyGlobalVectorFromField() is also available in PETSc 3.14.4.
2113 */
2115 "Destroying the global vector for field: %s\n",
2116 field_name);
2117 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
2118
2119 /* Log and return success. */
2121 "Successfully wrote swarm data for field: %s\n",
2122 field_name);
2123
2124 PetscFunctionReturn(0); /* PETSc macro indicating end of function */
2125}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteSwarmIntField()

PetscErrorCode WriteSwarmIntField ( UserCtx user,
const char *  field_name,
const char *  ext 
)

Writes integer data from a specific PETSc Swarm field to a file.

This function is designed for swarm fields that store integer data (e.g., DMSwarm_CellID), which cannot be converted to a standard PETSc Vec of PetscScalars. It accesses the raw data pointer for the field on each rank using DMSwarmGetField(), writes the local data to a rank-specific binary file, and then restores the field access.

Parameters
[in]userPointer to the UserCtx structure containing the PetscSwarm.
[in]field_nameName of the integer Swarm field to be written.
[in]extFile extension (e.g., "dat", "bin").
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Writes integer data from a specific PETSc Swarm field to a file.

Local to this translation unit.

Definition at line 2131 of file io.c.

2132{
2133 PetscErrorCode ierr;
2134 DM swarm = user->swarm;
2135 Vec temp_vec; // Temporary Vec to hold casted data
2136 PetscInt nlocal, nglobal,bs,i;
2137 PetscDataType field_type;
2138 void *field_array_void;
2139 PetscScalar *scalar_array; // Pointer to the temporary Vec's scalar data
2140
2141 PetscFunctionBeginUser;
2142
2143 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Casting '%s' to Vec for writing.\n", field_name);
2144
2145 // Get the swarm field properties
2146 ierr = DMSwarmGetLocalSize(swarm, &nlocal); CHKERRQ(ierr);
2147 ierr = DMSwarmGetSize(swarm, &nglobal); CHKERRQ(ierr);
2148 ierr = DMSwarmGetField(swarm, field_name, &bs, &field_type, &field_array_void); CHKERRQ(ierr);
2149 PetscCheck(field_type == PETSC_INT || field_type == PETSC_INT64,
2150 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
2151 "Swarm field '%s' must use PETSC_INT or PETSC_INT64 for integer output, not %s.",
2152 field_name, PetscDataTypes[field_type]);
2153
2154 // Create Temporary parallel Vec wit the CORRECT layout
2155 ierr = VecCreate(PETSC_COMM_WORLD, &temp_vec); CHKERRQ(ierr);
2156 ierr = VecSetType(temp_vec, VECMPI); CHKERRQ(ierr);
2157 ierr = VecSetSizes(temp_vec, nlocal*bs, nglobal*bs); CHKERRQ(ierr);
2158 ierr = VecSetUp(temp_vec); CHKERRQ(ierr);
2159
2160 // Defining Vector field to mandatory field 'position'
2161 DMSwarmVectorDefineField(swarm,ParticleFieldName(PARTICLE_FIELD_ID_POSITION));
2162
2163 ierr = VecGetArray(temp_vec, &scalar_array); CHKERRQ(ierr);
2164
2165 if (field_type == PETSC_INT64) {
2166 PetscInt64 *int64_array = (PetscInt64 *)field_array_void;
2167 // Perform the cast from PetscInt64 to PetscScalar
2168 for (i = 0; i < nlocal*bs; i++) {
2169 scalar_array[i] = (PetscScalar)int64_array[i];
2170 }
2171 }else{
2172 PetscInt *int_array = (PetscInt *)field_array_void;
2173 //Perform the cast from PetscInt to PetscScalar
2174 for (i = 0; i < nlocal*bs; i++) {
2175 scalar_array[i] = (PetscScalar)int_array[i];
2176 }
2177 }
2178
2179 // Restore access to both arrays
2180 ierr = VecRestoreArray(temp_vec, &scalar_array); CHKERRQ(ierr);
2181 ierr = DMSwarmRestoreField(swarm, field_name, &bs, NULL, &field_array_void); CHKERRQ(ierr);
2182
2183 // Call your existing writer with the temporary, populated Vec
2184 ierr = WriteFieldData(user, field_name, temp_vec, ext); CHKERRQ(ierr);
2185
2186 // Clean up
2187 ierr = VecDestroy(&temp_vec); CHKERRQ(ierr);
2188
2189 PetscFunctionReturn(0);
2190}
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_POSITION
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteAllSwarmFields()

PetscErrorCode WriteAllSwarmFields ( UserCtx user,
const char *  checkpoint_directory 
)

Writes a predefined set of PETSc Swarm fields to files.

This function iterates through checkpoint-capable particle catalog entries and delegates each payload to the existing generic swarm writer.

This function will only execute if particles are enabled in the simulation (i.e., user->simCtx->np > 0 and user->swarm is not NULL).

Parameters
[in]userPointer to the UserCtx structure containing the simulation context and the PetscSwarm.
[in]checkpoint_directoryRoot of the in-progress checkpoint bundle.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Writes a predefined set of PETSc Swarm fields to files.

Local to this translation unit.

Definition at line 2196 of file io.c.

2197{
2198 SimCtx *simCtx = user->simCtx;
2199
2200 PetscFunctionBeginUser;
2201
2202 // If no swarm is configured or there are no particles, do nothing and return.
2203 if (!user->swarm || simCtx->np <= 0) {
2204 PetscFunctionReturn(0);
2205 }
2206
2207 PetscCheck(checkpoint_directory != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
2208 "Checkpoint destination cannot be NULL.");
2209 PetscCall(PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
2210 "%s/%s", checkpoint_directory, PICURV_PARTICLE_DIRECTORY));
2211 simCtx->current_io_directory = simCtx->_io_context_buffer;
2212
2213 for (PetscInt raw_id = 0; raw_id < PARTICLE_FIELD_ID_COUNT; ++raw_id) {
2214 const ParticleFieldDescriptor *descriptor = NULL;
2215
2216 PetscCall(ParticleFieldGetDescriptor((ParticleFieldId)raw_id, &descriptor));
2217 if (!(descriptor->capabilities & PARTICLE_FIELD_CAPABILITY_CHECKPOINT)) continue;
2218 if (descriptor->data_type == PETSC_INT || descriptor->data_type == PETSC_INT64) {
2219 PetscCall(WriteSwarmIntField(user, descriptor->canonical_name, "dat"));
2220 } else {
2221 PetscCall(WriteSwarmField(user, descriptor->canonical_name, "dat"));
2222 }
2223 }
2224
2225 simCtx->current_io_directory = NULL;
2226
2227 PetscFunctionReturn(0);
2228}
PetscErrorCode WriteSwarmIntField(UserCtx *user, const char *field_name, const char *ext)
Internal helper implementation: WriteSwarmIntField().
Definition io.c:2131
PetscErrorCode WriteSwarmField(UserCtx *user, const char *field_name, const char *ext)
Implementation of WriteSwarmField().
Definition io.c:2076
ParticleFieldId
Compile-time identity for a persistent solver-particle field.
@ PARTICLE_FIELD_ID_COUNT
@ PARTICLE_FIELD_CAPABILITY_CHECKPOINT
PetscErrorCode ParticleFieldGetDescriptor(ParticleFieldId field_id, const ParticleFieldDescriptor **descriptor)
Return immutable metadata for a valid particle field ID.
Immutable metadata for one persistent particle field.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadDataFileToArray()

PetscInt ReadDataFileToArray ( const char *  filename,
double **  data_out,
PetscInt *  Nout,
MPI_Comm  comm 
)

Reads a simple ASCII data file containing one numeric value per line.

This helper performs rank-0 file I/O, broadcasts the parsed result to the rest of the communicator, and returns a replicated array on every rank.

Parameters
filenamePath to the input data file.
data_outOutput pointer to the allocated scalar array.
NoutOutput pointer storing the number of values read.
commMPI communicator used for the coordinated read/broadcast sequence.
Returns
Integer value produced by ReadDataFileToArray().

Reads a simple ASCII data file containing one numeric value per line.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
ReadDataFileToArray()

Definition at line 3286 of file io.c.

3290{
3291 /* STEP 0: Prepare local variables & log function entry */
3292 PetscMPIInt rank, size;
3293 PetscErrorCode ierr;
3294 FILE *fp = NULL;
3295 PetscInt N = 0; /* number of lines/values read on rank 0 */
3296 double *array = NULL; /* pointer to local array on each rank */
3297 PetscInt fileExistsFlag = 0; /* 0 = doesn't exist, 1 = does exist */
3298
3300 "Start reading from file: %s\n",
3301 filename);
3302
3303 /* Basic error checking: data_out, Nout must be non-null. */
3304 if (!filename || !data_out || !Nout) {
3306 "Null pointer argument provided.\n");
3307 return 1;
3308 }
3309
3310 /* Determine rank/size for coordinating I/O. */
3311 MPI_Comm_rank(comm, &rank);
3312 MPI_Comm_size(comm, &size);
3313
3314 /* STEP 1: On rank 0, check if file can be opened. */
3315 if (!rank) {
3316 fp = fopen(filename, "r");
3317 if (fp) {
3318 fileExistsFlag = 1;
3319 fclose(fp);
3320 }
3321 }
3322
3323 /* STEP 2: Broadcast file existence to all ranks. */
3324 // In ReadDataFileToArray:
3325 ierr = MPI_Bcast(&fileExistsFlag, 1, MPI_INT, 0, comm); CHKERRQ(ierr);
3326
3327 if (!fileExistsFlag) {
3328 /* If file does not exist, log & return. */
3329 if (!rank) {
3331 "File '%s' not found.\n",
3332 filename);
3333 }
3334 return 2;
3335 }
3336
3337 /* STEP 3: Rank 0 re-opens and reads the file, counting lines, etc. */
3338 if (!rank) {
3339 fp = fopen(filename, "r");
3340 if (!fp) {
3342 "File '%s' could not be opened for reading.\n",
3343 filename);
3344 return 3;
3345 }
3346
3347 /* (3a) Count lines first. */
3348 {
3349 char line[256];
3350 while (fgets(line, sizeof(line), fp)) {
3351 N++;
3352 }
3353 }
3354
3356 "File '%s' has %d lines.\n",
3357 filename, N);
3358
3359 /* (3b) Allocate array on rank 0. */
3360 array = (double*)malloc(N * sizeof(double));
3361 if (!array) {
3362 fclose(fp);
3364 "malloc failed for array.\n");
3365 return 4;
3366 }
3367
3368 /* (3c) Rewind & read values into array. */
3369 rewind(fp);
3370 {
3371 PetscInt i = 0;
3372 char line[256];
3373 while (fgets(line, sizeof(line), fp)) {
3374 double val;
3375 if (sscanf(line, "%lf", &val) == 1) {
3376 array[i++] = val;
3377 }
3378 }
3379 }
3380 fclose(fp);
3381
3383 "Successfully read %d values from '%s'.\n",
3384 N, filename);
3385 }
3386
3387 /* STEP 4: Broadcast the integer N to all ranks. */
3388 ierr = MPI_Bcast(&N, 1, MPI_INT, 0, comm); CHKERRQ(ierr);
3389
3390 /* STEP 5: Each rank allocates an array to receive the broadcast if rank>0. */
3391 if (rank) {
3392 array = (double*)malloc(N * sizeof(double));
3393 if (!array) {
3395 "malloc failed on rank %d.\n",
3396 rank);
3397 return 5;
3398 }
3399 }
3400
3401 /* STEP 6: Broadcast the actual data from rank 0 to all. */
3402 ierr = MPI_Bcast(array, N, MPI_DOUBLE, 0, comm); CHKERRQ(ierr);
3403
3404 /* STEP 7: Assign outputs on all ranks. */
3405 *data_out = array;
3406 *Nout = N;
3407
3409 "Done. Provided array of length=%d to all ranks.\n",
3410 N);
3411 return 0; /* success */
3412}

◆ CreateVTKFileFromMetadata()

PetscInt CreateVTKFileFromMetadata ( const char *  filename,
const VTKMetaData meta,
MPI_Comm  comm 
)

Creates a VTK file from prepared metadata and field payloads.

This helper dispatches to the structured-grid or polydata writer based on the metadata contents and emits the assembled VTK file on the requested communicator.

Parameters
filenamePath to the output VTK file.
metaVTK metadata describing the output geometry and field payloads.
commMPI communicator used by the write operation.
Returns
Integer value produced by CreateVTKFileFromMetadata().

Creates a VTK file from prepared metadata and field payloads.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/vtk_io.h.

See also
CreateVTKFileFromMetadata()

Definition at line 149 of file vtk_io.c.

150{
151 PetscMPIInt rank;
152 MPI_Comm_rank(comm, &rank);
153 PetscErrorCode ierr = 0;
154
155 if (!rank) {
156 char tmp_filename[PETSC_MAX_PATH_LEN];
157 FILE *fp = NULL;
158
159 ierr = PetscSNPrintf(tmp_filename, sizeof(tmp_filename), "%s.tmp", filename);CHKERRQ(ierr);
160 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank 0 writing combined VTK file '%s'.\n", filename);
161 fp = fopen(tmp_filename, "wb");
162 if (!fp) {
163 LOG_ALLOW(GLOBAL, LOG_ERROR, "fopen failed for %s.\n", tmp_filename);
164 return PETSC_ERR_FILE_OPEN;
165 }
166
167 PetscInt boffset = 0;
168
169 ierr = WriteVTKFileHeader(fp, meta, &boffset);
170 if (ierr) {
171 fclose(fp);
172 remove(tmp_filename);
173 return ierr;
174 }
175
176 if (meta->coords) {
177 ierr = WriteVTKAppendedBlock(fp, meta->coords, 3 * meta->npoints, sizeof(PetscScalar));
178 if (ierr) {
179 fclose(fp);
180 remove(tmp_filename);
181 return ierr;
182 }
183 }
184
185 for (PetscInt i = 0; i < meta->num_point_data_fields; i++) {
186 const VTKFieldInfo *field = &meta->point_data_fields[i];
187 if (field->data) {
188 ierr = WriteVTKAppendedBlock(fp, field->data, field->num_components * meta->npoints, sizeof(PetscScalar));
189 if (ierr) {
190 fclose(fp);
191 remove(tmp_filename);
192 return ierr;
193 }
194 }
195 }
196 if (meta->fileType == VTK_POLYDATA) {
197 if (meta->connectivity) {
198 ierr = WriteVTKAppendedBlock(fp, meta->connectivity, meta->npoints, sizeof(PetscInt));
199 if (ierr) {
200 fclose(fp);
201 remove(tmp_filename);
202 return ierr;
203 }
204 }
205 if (meta->offsets) {
206 ierr = WriteVTKAppendedBlock(fp, meta->offsets, meta->npoints, sizeof(PetscInt));
207 if (ierr) {
208 fclose(fp);
209 remove(tmp_filename);
210 return ierr;
211 }
212 }
213 }
214 ierr = WriteVTKFileFooter(fp, meta);
215 if (ierr) {
216 fclose(fp);
217 remove(tmp_filename);
218 return ierr;
219 }
220 if (fclose(fp) != 0) {
221 remove(tmp_filename);
222 return PETSC_ERR_FILE_WRITE;
223 }
224 if (rename(tmp_filename, filename) != 0) {
225 remove(tmp_filename);
226 return PETSC_ERR_FILE_WRITE;
227 }
228 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank 0 finished writing VTK file '%s'.\n", filename);
229 }
230 return 0;
231}
PetscInt npoints
Definition variables.h:656
PetscInt num_components
Definition variables.h:643
PetscInt num_point_data_fields
Definition variables.h:659
PetscInt * connectivity
Definition variables.h:660
PetscInt * offsets
Definition variables.h:661
VTKFileType fileType
Definition variables.h:654
PetscScalar * data
Definition variables.h:644
PetscScalar * coords
Definition variables.h:657
VTKFieldInfo point_data_fields[20]
Definition variables.h:658
@ VTK_POLYDATA
Definition variables.h:650
Stores all necessary information for a single data array in a VTK file.
Definition variables.h:641
static PetscErrorCode WriteVTKFileFooter(FILE *fp, const VTKMetaData *meta)
Close a VTK XML document after all appended data have been written.
Definition vtk_io.c:132
static PetscErrorCode WriteVTKAppendedBlock(FILE *fp, const void *data, PetscInt num_elements, size_t element_size)
Write one binary data block in VTK appended-data format.
Definition vtk_io.c:21
static PetscErrorCode WriteVTKFileHeader(FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
Open a VTK XML document and write its file-level header.
Definition vtk_io.c:119
Here is the call graph for this function:
Here is the caller graph for this function:

◆ VecToArrayOnRank0()

PetscErrorCode VecToArrayOnRank0 ( Vec  inVec,
PetscInt *  N,
double **  arrayOut 
)

Gathers the contents of a distributed PETSc Vec into a single array on rank 0.

Parameters
[in]inVecThe input (possibly distributed) Vec.
[out]NThe global size of the vector.
[out]arrayOutOn rank 0, points to the newly allocated array holding all data. On other ranks, it is set to NULL.
Returns
PetscErrorCode Return 0 on success, nonzero on failure.

Gathers the contents of a distributed PETSc Vec into a single array on rank 0.

Local to this translation unit.

Definition at line 2650 of file io.c.

2651{
2652 MPI_Comm comm;
2653 PetscMPIInt rank;
2654 Vec sequential_vec = NULL;
2655
2656 PetscFunctionBeginUser;
2657 PetscCheck(inVec != NULL && N != NULL && arrayOut != NULL,
2658 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
2659 "Vector, size output, and array output are required.");
2660 PetscCall(PetscObjectGetComm((PetscObject)inVec, &comm));
2661 PetscCallMPI(MPI_Comm_rank(comm, &rank));
2662 PetscCall(VecGetSize(inVec, N));
2663 *arrayOut = NULL;
2664
2665 PetscCall(GatherVectorToRankZero(inVec, &sequential_vec));
2666 if (rank == 0) {
2667 const PetscScalar *values = NULL;
2668 PetscInt local_size = 0;
2669
2670 PetscCall(VecGetLocalSize(sequential_vec, &local_size));
2671 PetscCall(PetscMalloc1(local_size, arrayOut));
2672 PetscCall(VecGetArrayRead(sequential_vec, &values));
2673 for (PetscInt index = 0; index < local_size; ++index) {
2674 (*arrayOut)[index] = (double)PetscRealPart(values[index]);
2675 }
2676 PetscCall(VecRestoreArrayRead(sequential_vec, &values));
2677 }
2678 PetscCall(VecDestroy(&sequential_vec));
2679 PetscFunctionReturn(0);
2680}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SwarmFieldToArrayOnRank0()

PetscErrorCode SwarmFieldToArrayOnRank0 ( DM  swarm,
const char *  field_name,
PetscInt *  n_total_particles,
PetscInt *  n_components,
PetscDataType *  field_type_out,
void **  gathered_array 
)

Gathers any DMSwarm field from all ranks to a single, contiguous array on rank 0.

This is a generic, type-aware version of SwarmFieldToArrayOnRank0. It is a COLLECTIVE operation.

Parameters
[in]swarmThe DMSwarm to gather from.
[in]field_nameThe name of the field to gather.
[out]n_total_particlesTotal number of particles in the global swarm on every rank.
[out]n_componentsNumber of components for the field on every rank.
[out]field_type_outPETSc storage type for the field on all ranks.
[out]gathered_arrayOn rank 0, a newly allocated array containing the full, gathered data; NULL elsewhere. The caller is responsible for freeing this memory and for casting it to the correct type.
Returns
PetscErrorCode

Gathers any DMSwarm field from all ranks to a single, contiguous array on rank 0.

Local to this translation unit.

Definition at line 2686 of file io.c.

2689{
2690 PetscErrorCode ierr;
2691 PetscMPIInt rank, size;
2692 PetscInt nlocal, nglobal, bs;
2693 PetscDataType field_type;
2694 void *local_array_void;
2695 size_t element_size = 0;
2696
2697 PetscFunctionBeginUser;
2698
2699 PetscCheck(swarm != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "DMSwarm cannot be NULL.");
2700 PetscCheck(field_name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Swarm field name cannot be NULL.");
2701 PetscCheck(n_total_particles != NULL && n_components != NULL && field_type_out != NULL && gathered_array != NULL,
2702 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
2703 "Swarm gather output pointers cannot be NULL.");
2704
2705 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2706 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
2707
2708 // All ranks get swarm properties to determine send/receive counts
2709 ierr = DMSwarmGetLocalSize(swarm, &nlocal); CHKERRQ(ierr);
2710 ierr = DMSwarmGetSize(swarm, &nglobal); CHKERRQ(ierr);
2711 ierr = DMSwarmGetField(swarm, field_name, &bs, &field_type, &local_array_void); CHKERRQ(ierr);
2712
2713 // Determine the size of one element of the field's data type
2714 if (field_type == PETSC_INT64) element_size = sizeof(PetscInt64);
2715 else if (field_type == PETSC_INT) element_size = sizeof(PetscInt);
2716 else if (field_type == PETSC_REAL) element_size = sizeof(PetscReal);
2717#if defined(PETSC_USE_COMPLEX)
2718 else if (field_type == PETSC_SCALAR) element_size = sizeof(PetscScalar);
2719#endif
2720 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,
2721 "Swarm field '%s' uses unsupported gathered data type %s.",
2722 field_name, PetscDataTypes[field_type]);
2723
2724 *field_type_out = field_type;
2725 *n_total_particles = nglobal;
2726 *n_components = bs;
2727 *gathered_array = NULL;
2728
2729 if (size == 1) { // Serial case is a simple copy
2730 if (rank == 0) {
2731 ierr = PetscMalloc(nglobal * bs * element_size, gathered_array); CHKERRQ(ierr);
2732 ierr = PetscMemcpy(*gathered_array, local_array_void, nglobal * bs * element_size); CHKERRQ(ierr);
2733 }
2734 } else { // Parallel case: use MPI_Gatherv
2735 PetscInt *recvcounts = NULL, *displs = NULL;
2736 if (rank == 0) {
2737 ierr = PetscMalloc1(size, &recvcounts); CHKERRQ(ierr);
2738 ierr = PetscMalloc1(size, &displs); CHKERRQ(ierr);
2739 }
2740 PetscInt sendcount = nlocal * bs;
2741
2742 // Gather the number of elements (not bytes) from each rank
2743 ierr = MPI_Gather(&sendcount, 1, MPIU_INT, recvcounts, 1, MPIU_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
2744
2745 if (rank == 0) {
2746 displs[0] = 0;
2747 // Convert counts and calculate displacements in terms of BYTES
2748 for (PetscMPIInt i = 0; i < size; i++) recvcounts[i] *= element_size;
2749 for (PetscMPIInt i = 1; i < size; i++) displs[i] = displs[i-1] + recvcounts[i-1];
2750
2751 ierr = PetscMalloc(nglobal * bs * element_size, gathered_array); CHKERRQ(ierr);
2752 }
2753
2754 // Use Gatherv with MPI_BYTE to handle any data type generically
2755 ierr = MPI_Gatherv(local_array_void, nlocal * bs * element_size, MPI_BYTE,
2756 *gathered_array, recvcounts, displs, MPI_BYTE,
2757 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
2758
2759 if (rank == 0) {
2760 ierr = PetscFree(recvcounts); CHKERRQ(ierr);
2761 ierr = PetscFree(displs); CHKERRQ(ierr);
2762 }
2763 }
2764
2765 ierr = DMSwarmRestoreField(swarm, field_name, &bs, NULL, &local_array_void); CHKERRQ(ierr);
2766
2767 PetscFunctionReturn(0);
2768}
Here is the caller graph for this function:

◆ ReadSwarmField()

PetscErrorCode ReadSwarmField ( UserCtx user,
const char *  field_name,
const char *  ext 
)

Reads data from a file into a specified field of a PETSc DMSwarm.

This function is the counterpart to WriteSwarmField(). It creates a global PETSc vector that references the specified DMSwarm field, uses ReadFieldData() to read the data from a file, and then destroys the global vector reference.

Parameters
[in]userPointer to the UserCtx structure (containing user->swarm).
[in]field_nameName of the DMSwarm field to read into (must be previously declared/allocated).
[in]extFile extension (e.g., "dat" or "bin").
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.
Note
Compatible with PETSc 3.14.x.

Reads data from a file into a specified field of a PETSc DMSwarm.

Local to this translation unit.

Definition at line 1767 of file io.c.

1768{
1769 PetscErrorCode ierr;
1770 DM swarm;
1771 Vec fieldVec;
1772
1773 PetscFunctionBegin;
1774
1775 swarm = user->swarm;
1776
1777 LOG_ALLOW(GLOBAL,LOG_DEBUG," ReadSwarmField Begins \n");
1778
1779 /* 2) Create a global vector that references the specified Swarm field. */
1780 ierr = DMSwarmCreateGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
1781
1782 LOG_ALLOW(GLOBAL,LOG_DEBUG," Vector created from Field \n");
1783
1784 /* 3) Use the ReadFieldData() function to read data into fieldVec. */
1785 ierr = ReadFieldData(user, field_name, fieldVec, ext);CHKERRQ(ierr);
1786
1787 /* 4) Destroy the global vector reference. */
1788 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
1789
1790 PetscFunctionReturn(0);
1791}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadSwarmIntField()

PetscErrorCode ReadSwarmIntField ( UserCtx user,
const char *  field_name,
const char *  ext 
)

Reads integer swarm data by using ReadFieldData and casting the result.

This function is the counterpart to WriteSwarmIntField. It reads a file containing floating-point data (that was originally integer) into a temporary Vec and then casts it back to the integer swarm field. It works by:

  1. Creating a temporary parallel Vec.
  2. Calling the standard ReadFieldData() to populate this Vec.
  3. Accessing the local data of both the Vec and the swarm field.
  4. Populating the swarm's integer field by casting each PetscScalar back to a PetscInt.
  5. Destroying the temporary Vec.
Parameters
[in]userPointer to the UserCtx structure.
[in]field_nameName of the integer Swarm field to be read.
[in]extFile extension.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads integer swarm data by using ReadFieldData and casting the result.

Local to this translation unit.

Definition at line 1797 of file io.c.

1798{
1799 PetscErrorCode ierr;
1800 DM swarm = user->swarm;
1801 Vec temp_vec;
1802 PetscInt nlocal, nglobal, bs, i;
1803 PetscDataType field_type;
1804 const PetscScalar *scalar_array; // Read-only pointer from the temp Vec
1805 void *field_array_void;
1806
1807
1808 PetscFunctionBeginUser;
1809
1810 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Reading '%s' via temporary Vec.\n", field_name);
1811
1812 // Get the properties of the swarm field to determine the expected layout
1813 ierr = DMSwarmGetLocalSize(swarm, &nlocal); CHKERRQ(ierr);
1814 ierr = DMSwarmGetSize(swarm, &nglobal); CHKERRQ(ierr);
1815 // We get the block size but not the data pointer yet
1816 ierr = DMSwarmGetField(swarm, field_name, &bs, &field_type, NULL); CHKERRQ(ierr);
1817 ierr = DMSwarmRestoreField(swarm, field_name, &bs, NULL, NULL); CHKERRQ(ierr);
1818 PetscCheck(field_type == PETSC_INT || field_type == PETSC_INT64,
1819 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
1820 "Swarm field '%s' must use PETSC_INT or PETSC_INT64 for integer restart input, not %s.",
1821 field_name, PetscDataTypes[field_type]);
1822
1823 // Create a temporary Vec with the CORRECT layout to receive the data
1824 ierr = VecCreate(PETSC_COMM_WORLD, &temp_vec); CHKERRQ(ierr);
1825 ierr = VecSetType(temp_vec, VECMPI); CHKERRQ(ierr);
1826 ierr = VecSetSizes(temp_vec, nlocal * bs, nglobal * bs); CHKERRQ(ierr);
1827 ierr = VecSetBlockSize(temp_vec, bs); CHKERRQ(ierr);
1828 ierr = VecSetUp(temp_vec); CHKERRQ(ierr);
1829
1830 // Call your existing reader to populate the temporary Vec
1831 ierr = ReadFieldData(user, field_name, temp_vec, ext); CHKERRQ(ierr);
1832
1833 // Get local pointers
1834 ierr = VecGetArrayRead(temp_vec, &scalar_array); CHKERRQ(ierr);
1835 ierr = DMSwarmGetField(swarm, field_name, NULL, NULL, &field_array_void); CHKERRQ(ierr);
1836
1837 // Perform the cast back, using the correct loop size (nlocal * bs)
1838 if (field_type == PETSC_INT64) {
1839 PetscInt64 *int64_array = (PetscInt64 *)field_array_void;
1840 for (i = 0; i < nlocal * bs; i++) {
1841 int64_array[i] = (PetscInt64)scalar_array[i];
1842 }
1843 } else {
1844 PetscInt *int_array = (PetscInt *)field_array_void;
1845 for (i = 0; i < nlocal * bs; i++) {
1846 int_array[i] = (PetscInt)scalar_array[i];
1847 }
1848 }
1849
1850 // Restore access
1851 ierr = DMSwarmRestoreField(swarm, field_name, NULL, NULL, &field_array_void); CHKERRQ(ierr);
1852 ierr = VecRestoreArrayRead(temp_vec, &scalar_array); CHKERRQ(ierr);
1853
1854 // 6. Clean up
1855 ierr = VecDestroy(&temp_vec); CHKERRQ(ierr);
1856
1857 PetscFunctionReturn(0);
1858}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadAllSwarmFields()

PetscErrorCode ReadAllSwarmFields ( UserCtx user,
PetscInt  ti 
)

Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.

This function is analogous to ReadSimulationFields() but targets a DMSwarm. Each Swarm field is read from a separate file using ReadSwarmField().

Parameters
[in,out]userPointer to the UserCtx structure containing the DMSwarm (user->swarm).
[in]tiTime index for constructing the file name.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.

Local to this translation unit.

Definition at line 1864 of file io.c.

1865{
1866 PetscInt nGlobal;
1867 SimCtx *simCtx = user->simCtx;
1868 const char *source_path = NULL;
1869 char checkpoint_directory[PETSC_MAX_PATH_LEN];
1870
1871 PetscFunctionBeginUser;
1872 PetscCall(DMSwarmGetSize(user->swarm, &nGlobal));
1873 LOG_ALLOW(GLOBAL, LOG_INFO, "Reading DMSwarm fields for timestep %d (swarm size is %d).\n", ti, nGlobal);
1874
1875 if (nGlobal == 0) {
1876 LOG_ALLOW(GLOBAL, LOG_INFO, "Swarm is empty for timestep %d. Nothing to read.\n", ti);
1877 PetscFunctionReturn(0);
1878 }
1879
1880 // First, determine the top-level source directory based on the execution mode.
1881 if (simCtx->exec_mode == EXEC_MODE_SOLVER) {
1882 source_path = simCtx->restart_dir;
1883 } else if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
1884 source_path = simCtx->pps->source_dir;
1885 } else {
1886 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "Invalid execution mode for reading simulation fields.");
1887 }
1888
1889 PetscCall(ResolveCheckpointStepDirectory(source_path, ti,
1890 checkpoint_directory, sizeof(checkpoint_directory)));
1891 PetscCall(PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
1892 "%s/%s", checkpoint_directory, PICURV_PARTICLE_DIRECTORY));
1893 simCtx->current_io_directory = simCtx->_io_context_buffer;
1894
1895 for (PetscInt raw_id = 0; raw_id < PARTICLE_FIELD_ID_COUNT; ++raw_id) {
1896 const ParticleFieldDescriptor *descriptor = NULL;
1897
1898 PetscCall(ParticleFieldGetDescriptor((ParticleFieldId)raw_id, &descriptor));
1899 if (!(descriptor->capabilities & PARTICLE_FIELD_CAPABILITY_CHECKPOINT)) continue;
1900 if (descriptor->data_type == PETSC_INT || descriptor->data_type == PETSC_INT64) {
1901 PetscCall(ReadSwarmIntField(user, descriptor->canonical_name, "dat"));
1902 } else {
1903 PetscCall(ReadSwarmField(user, descriptor->canonical_name, "dat"));
1904 }
1905 }
1906
1907 simCtx->current_io_directory = NULL;
1908
1909 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished reading DMSwarm fields for timestep %d.\n", ti);
1910 PetscFunctionReturn(0);
1911}
PetscErrorCode ReadSwarmField(UserCtx *user, const char *field_name, const char *ext)
Internal helper implementation: ReadSwarmField().
Definition io.c:1767
PetscErrorCode ReadSwarmIntField(UserCtx *user, const char *field_name, const char *ext)
Internal helper implementation: ReadSwarmIntField().
Definition io.c:1797
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadCheckpointParticleCount()

PetscErrorCode ReadCheckpointParticleCount ( UserCtx user,
PetscInt  ti,
PetscInt *  particle_count 
)

Read the particle count from a validated committed checkpoint.

Parameters
[in,out]userSimulation context and active grid used for validation.
[in]tiCheckpoint step resolved below the configured source root.
[out]particle_countNumber of particles recorded by the bundle.
Returns
Zero on success or a checkpoint-validation error.

Read the particle count from a validated committed checkpoint.

Definition at line 1914 of file io.c.

1915{
1916 SimCtx *simCtx = NULL;
1917 const char *source_path = NULL;
1918 char checkpoint_directory[PETSC_MAX_PATH_LEN];
1919 PetscBool particles_saved = PETSC_FALSE;
1920
1921 PetscFunctionBeginUser;
1922 PetscCheck(user != NULL && particle_count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
1923 "Simulation context and particle-count output are required.");
1924 simCtx = user->simCtx;
1925 if (simCtx->exec_mode == EXEC_MODE_SOLVER) source_path = simCtx->restart_dir;
1926 else if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) source_path = simCtx->pps->source_dir;
1927 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
1928 "Invalid execution mode for reading checkpoint particle metadata.");
1929
1930 PetscCall(ResolveCheckpointStepDirectory(source_path, ti,
1931 checkpoint_directory, sizeof(checkpoint_directory)));
1932 PetscCall(ValidateCheckpointBundle(simCtx, user - user->_this,
1933 checkpoint_directory, ti, NULL, particle_count,
1934 &particles_saved, NULL, NULL));
1935 PetscCheck(particles_saved, PETSC_COMM_WORLD, PETSC_ERR_FILE_UNEXPECTED,
1936 "Checkpoint step %" PetscInt_FMT " contains no particle state.", ti);
1937 PetscFunctionReturn(0);
1938}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadPositionsFromFile()

PetscErrorCode ReadPositionsFromFile ( PetscInt  timeIndex,
UserCtx user,
double **  coordsArray,
PetscInt *  Ncoords 
)

Reads coordinate data (for particles) from file into a PETSc Vec, then gathers it to rank 0.

This function uses ReadFieldData to fill a PETSc Vec with coordinate data, then leverages VecToArrayOnRank0 to gather that data into a contiguous array (valid on rank 0 only).

Parameters
[in]timeIndexThe time index used to construct file names.
[in]userPointer to the user context.
[out]coordsArrayOn rank 0, will point to a newly allocated array holding the coordinates.
[out]NcoordsOn rank 0, the length of coordsArray. On other ranks, 0.
Returns
PetscErrorCode Returns 0 on success, or non-zero on failures.

Reads coordinate data (for particles) from file into a PETSc Vec, then gathers it to rank 0.

Local to this translation unit.

Definition at line 3418 of file io.c.

3422{
3423 PetscFunctionBeginUser;
3424
3425 PetscErrorCode ierr;
3426 Vec coordsVec;
3427
3428 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating coords Vec.\n");
3429 ierr = VecCreate(PETSC_COMM_WORLD, &coordsVec);CHKERRQ(ierr);
3430 ierr = VecSetFromOptions(coordsVec);CHKERRQ(ierr);
3431
3432 // For example: "position" is the name of the coordinate data
3433 ierr = ReadFieldData(user, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), coordsVec, "dat");
3434 if (ierr) {
3436 "Error reading position data (ti=%d).\n",
3437 timeIndex);
3438 PetscFunctionReturn(ierr);
3439 }
3440
3441 LOG_ALLOW(GLOBAL, LOG_DEBUG, "ReadPositions - Gathering coords Vec to rank 0.\n");
3442 ierr = VecToArrayOnRank0(coordsVec, Ncoords, coordsArray);CHKERRQ(ierr);
3443
3444 ierr = VecDestroy(&coordsVec);CHKERRQ(ierr);
3445
3447 "Successfully gathered coordinates. Ncoords=%d.\n", *Ncoords);
3448 PetscFunctionReturn(0);
3449}
PetscErrorCode VecToArrayOnRank0(Vec inVec, PetscInt *N, double **arrayOut)
Internal helper implementation: VecToArrayOnRank0().
Definition io.c:2650
Here is the call graph for this function:

◆ ReadFieldDataToRank0()

PetscErrorCode ReadFieldDataToRank0 ( PetscInt  timeIndex,
const char *  fieldName,
UserCtx user,
double **  scalarArray,
PetscInt *  Nscalars 
)

Reads a named field from file into a PETSc Vec, then gathers it to rank 0.

This function wraps ReadFieldData and VecToArrayOnRank0 into a single step. The gathered data is stored in scalarArray on rank 0, with its length in Nscalars.

Parameters
[in]timeIndexThe time index used to construct file names.
[in]fieldNameName of the field to be read (e.g., "velocity").
[in]userPointer to the user context.
[out]scalarArrayOn rank 0, a newly allocated array holding the field data.
[out]NscalarsOn rank 0, length of scalarArray. On other ranks, 0.
Returns
PetscErrorCode Returns 0 on success, or non-zero on failures.

Reads a named field from file into a PETSc Vec, then gathers it to rank 0.

Local to this translation unit.

Definition at line 3456 of file io.c.

3461{
3462 PetscFunctionBeginUser;
3463
3464 PetscErrorCode ierr;
3465 Vec fieldVec;
3466
3467 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating field Vec.\n");
3468 ierr = VecCreate(PETSC_COMM_WORLD, &fieldVec);CHKERRQ(ierr);
3469 ierr = VecSetFromOptions(fieldVec);CHKERRQ(ierr);
3470
3471 ierr = ReadFieldData(user, fieldName, fieldVec, "dat");
3472 if (ierr) {
3474 "Error reading field '%s' (ti=%d).\n",
3475 fieldName, timeIndex);
3476 PetscFunctionReturn(ierr);
3477 }
3478
3479 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Gathering field Vec to rank 0.\n");
3480 ierr = VecToArrayOnRank0(fieldVec, Nscalars, scalarArray);CHKERRQ(ierr);
3481
3482 ierr = VecDestroy(&fieldVec);CHKERRQ(ierr);
3483
3485 "Successfully gathered field '%s'. Nscalars=%d.\n",
3486 fieldName, *Nscalars);
3487 PetscFunctionReturn(0);
3488}
Here is the call graph for this function:

◆ DisplayBanner()

PetscErrorCode DisplayBanner ( SimCtx simCtx)

Displays a structured banner summarizing the simulation configuration.

This function prints effective key simulation parameters to standard output on MPI rank 0. It retrieves global domain bounds and block metadata from simCtx, and suppresses settings that do not apply to the selected mode. For example, Initial Pseudo-CFL (Courant) appears only for the Dual Time Picard–Jameson RK momentum solver; it is not a Newton–Krylov control. The report also identifies active logging, profiling, runtime-memory, and solution-convergence modes so the startup log records the effective observability contract.

Parameters
[in]simCtxPointer to the master simulation context.
Returns
PetscErrorCode Returns 0 on success.

Displays a structured banner summarizing the simulation configuration.

Reports only configuration that applies to the selected run mode. In particular, pseudo-CFL is a Dual Time Picard–Jameson RK control and is deliberately omitted for explicit and Newton–Krylov momentum solves.

Definition at line 2776 of file io.c.

2777{
2778 PetscErrorCode ierr;
2779 PetscMPIInt rank;
2780 Cmpnts global_min_coords, global_max_coords;
2781 PetscReal StartTime;
2782 PetscInt StartStep,StepsToRun,total_num_particles;
2783 PetscMPIInt num_mpi_procs;
2784 const char *log_level_name;
2785 const char *convergence_mode_name;
2786
2787 // SimCtx *simCtx = user->simCtx;
2788 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
2789 num_mpi_procs = simCtx->size;
2790 StartTime = simCtx->StartTime;
2791 StartStep = simCtx->StartStep;
2792 StepsToRun = simCtx->StepsToRun;
2793 total_num_particles = simCtx->np;
2794 BoundingBox *bboxlist_on_rank0 = simCtx->bboxlist;
2795
2796
2797 PetscFunctionBeginUser;
2798
2799 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "DisplayBanner - UserCtx pointer is NULL.");
2800 switch (get_log_level()) {
2801 case LOG_ERROR: log_level_name = "ERROR"; break;
2802 case LOG_WARNING: log_level_name = "WARNING"; break;
2803 case LOG_INFO: log_level_name = "INFO"; break;
2804 case LOG_DEBUG: log_level_name = "DEBUG"; break;
2805 case LOG_TRACE: log_level_name = "TRACE"; break;
2806 case LOG_VERBOSE: log_level_name = "VERBOSE"; break;
2807 default: log_level_name = "UNKNOWN"; break;
2808 }
2809 switch (simCtx->solutionConvergenceMode) {
2810 case SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC: convergence_mode_name = "STEADY_DETERMINISTIC"; break;
2811 case SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC: convergence_mode_name = "PERIODIC_DETERMINISTIC"; break;
2812 case SOLUTION_CONVERGENCE_STATISTICAL_STEADY: convergence_mode_name = "STATISTICAL_STEADY"; break;
2813 case SOLUTION_CONVERGENCE_TRANSIENT: convergence_mode_name = "TRANSIENT"; break;
2814 default: convergence_mode_name = "UNKNOWN"; break;
2815 }
2816 global_min_coords = user->bbox.min_coords;
2817 global_max_coords = user->bbox.max_coords;
2818 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2819
2820 if (rank == 0) {
2821 // If global_domain_bbox is not pre-populated in UserCtx, compute it here from bboxlist_on_rank0
2822 // This assumes bboxlist_on_rank0 is valid and contains all local bounding boxes on rank 0.
2823 if (bboxlist_on_rank0 && num_mpi_procs > 0) {
2824 global_min_coords = bboxlist_on_rank0[0].min_coords;
2825 global_max_coords = bboxlist_on_rank0[0].max_coords;
2826 for (PetscMPIInt p = 1; p < num_mpi_procs; ++p) {
2827 global_min_coords.x = PetscMin(global_min_coords.x, bboxlist_on_rank0[p].min_coords.x);
2828 global_min_coords.y = PetscMin(global_min_coords.y, bboxlist_on_rank0[p].min_coords.y);
2829 global_min_coords.z = PetscMin(global_min_coords.z, bboxlist_on_rank0[p].min_coords.z);
2830 global_max_coords.x = PetscMax(global_max_coords.x, bboxlist_on_rank0[p].max_coords.x);
2831 global_max_coords.y = PetscMax(global_max_coords.y, bboxlist_on_rank0[p].max_coords.y);
2832 global_max_coords.z = PetscMax(global_max_coords.z, bboxlist_on_rank0[p].max_coords.z);
2833 }
2834 // Optionally store this in user->global_domain_bbox if it's useful elsewhere
2835 // user->global_domain_bbox.min_coords = global_min_coords;
2836 // user->global_domain_bbox.max_coords = global_max_coords;
2837 } else {
2838 // Fallback or warning if bboxlist is not available for global calculation
2839 LOG_ALLOW(LOCAL, LOG_WARNING, "(Rank 0) - bboxlist not provided or num_mpi_procs <=0; using user->bbox for domain bounds.\n");
2840 // global_min_coords = user->bbox.min_coords; // Use local bbox of rank 0 as fallback
2841 // global_max_coords = user->bbox.max_coords;
2842 }
2843
2844 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); CHKERRQ(ierr);
2845 ierr = PetscPrintf(PETSC_COMM_SELF, "=============================================================\n"); CHKERRQ(ierr);
2846 ierr = PetscPrintf(PETSC_COMM_SELF, " CASE SUMMARY \n"); CHKERRQ(ierr);
2847 ierr = PetscPrintf(PETSC_COMM_SELF, "=============================================================\n"); CHKERRQ(ierr);
2848 ierr = PetscPrintf(PETSC_COMM_SELF, " Grid Points : %d X %d X %d\n", user->IM, user->JM, user->KM); CHKERRQ(ierr);
2849 ierr = PetscPrintf(PETSC_COMM_SELF, " Cells : %d X %d X %d\n", user->IM - 1, user->JM - 1, user->KM - 1); CHKERRQ(ierr);
2850 ierr = PetscPrintf(PETSC_COMM_SELF, " Global Domain Bounds (X) : %.6f to %.6f\n", (double)global_min_coords.x, (double)global_max_coords.x); CHKERRQ(ierr);
2851 ierr = PetscPrintf(PETSC_COMM_SELF, " Global Domain Bounds (Y) : %.6f to %.6f\n", (double)global_min_coords.y, (double)global_max_coords.y); CHKERRQ(ierr);
2852 ierr = PetscPrintf(PETSC_COMM_SELF, " Global Domain Bounds (Z) : %.6f to %.6f\n", (double)global_min_coords.z, (double)global_max_coords.z); CHKERRQ(ierr);
2853 ierr = PetscPrintf(PETSC_COMM_SELF, " Periodic Axes (BC-derived) : I=%s, J=%s, K=%s\n",
2854 simCtx->i_periodic ? "YES" : "NO",
2855 simCtx->j_periodic ? "YES" : "NO",
2856 simCtx->k_periodic ? "YES" : "NO"); CHKERRQ(ierr);
2857 for (PetscInt axis = 0; axis < 3; axis++) {
2858 if (!user->periodic_translation_valid[axis]) continue;
2859 ierr = PetscPrintf(PETSC_COMM_SELF,
2860 " Periodic %c Translation : (%.6e, %.6e, %.6e)\n",
2861 "IJK"[axis],
2862 (double)user->periodic_translation[axis].x,
2863 (double)user->periodic_translation[axis].y,
2864 (double)user->periodic_translation[axis].z); CHKERRQ(ierr);
2865 }
2866 if (total_num_particles > 0 &&
2867 (simCtx->i_periodic || simCtx->j_periodic || simCtx->k_periodic)) {
2868 ierr = PetscPrintf(PETSC_COMM_SELF,
2869 " Particle Periodic Wrapping : UNSUPPORTED (Eulerian periodicity only)\n"); CHKERRQ(ierr);
2870 }
2871 if(strcmp(simCtx->eulerianSource,"load")==0 || strcmp(simCtx->eulerianSource,"solve")==0){
2872 ierr = PetscPrintf(PETSC_COMM_SELF, "-------------------- Boundary Conditions --------------------\n"); CHKERRQ(ierr);
2873 const int face_name_width = 17; // Adjusted for longer names (Zeta,Eta,Xi)
2874 for (PetscInt i_face = 0; i_face < 6; ++i_face) {
2875 BCFace current_face = (BCFace)i_face;
2876 // The BCFaceToString will now return the Xi, Eta, Zeta versions
2877 const char* face_str = BCFaceToString(current_face);
2878 const char* bc_type_str = BCTypeToString(user->boundary_faces[current_face].mathematical_type);
2879 const char* bc_handler_type_str = BCHandlerTypeToString(user->boundary_faces[current_face].handler_type);
2880 if(user->boundary_faces[current_face].mathematical_type == INLET){
2882 Cmpnts inlet_velocity = {0.0,0.0,0.0};
2883 PetscBool found;
2884 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"vx",&inlet_velocity.x,&found); CHKERRQ(ierr);
2885 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"vy",&inlet_velocity.y,&found); CHKERRQ(ierr);
2886 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"vz",&inlet_velocity.z,&found); CHKERRQ(ierr);
2887 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - [%.4f,%.4f,%.4f]\n",
2888 face_name_width, face_str, bc_type_str, bc_handler_type_str,inlet_velocity.x,inlet_velocity.y,inlet_velocity.z); CHKERRQ(ierr);
2889 } else if(user->boundary_faces[current_face].handler_type == BC_HANDLER_INLET_PARABOLIC){
2890 PetscReal v_max = 0.0;
2891 PetscBool found;
2892 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"v_max",&v_max,&found); CHKERRQ(ierr);
2893 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - v_max=%.4f\n",
2894 face_name_width, face_str, bc_type_str, bc_handler_type_str, v_max); CHKERRQ(ierr);
2895 } else if(user->boundary_faces[current_face].handler_type == BC_HANDLER_INLET_PROFILE_FROM_FILE){
2896 const char *source_file = "(missing)";
2897 for (BC_Param *param = user->boundary_faces[current_face].params; param; param = param->next) {
2898 if (strcasecmp(param->key, "source_file") == 0 && param->value) {
2899 source_file = param->value;
2900 break;
2901 }
2902 }
2903 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - source_file=%s\n",
2904 face_name_width, face_str, bc_type_str, bc_handler_type_str, source_file); CHKERRQ(ierr);
2905 }
2907 PetscBool trimflag,foundtrimflag;
2908 ierr = GetDrivenSeamFluxFlag(user->boundary_faces[current_face].params,&trimflag,&foundtrimflag); CHKERRQ(ierr);
2909 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - [from initial state] - %s\n",
2910 face_name_width, face_str, bc_type_str, bc_handler_type_str,trimflag?"Enforce seam flux":"Seam flux not enforced"); CHKERRQ(ierr);
2912 PetscReal flux;
2913 PetscBool trimflag,foundflux,foundtrimflag;
2914 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"target_flux",&flux,&foundflux); CHKERRQ(ierr);
2915 ierr = GetDrivenSeamFluxFlag(user->boundary_faces[current_face].params,&trimflag,&foundtrimflag); CHKERRQ(ierr);
2916 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - [%.4f] - %s\n",
2917 face_name_width, face_str, bc_type_str, bc_handler_type_str,flux,trimflag?"Enforce seam flux":"Seam flux not enforced"); CHKERRQ(ierr);
2918 } else{
2919 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s\n",
2920 face_name_width, face_str, bc_type_str,bc_handler_type_str); CHKERRQ(ierr);
2921 }
2922 }
2923 }
2924 ierr = PetscPrintf(PETSC_COMM_SELF, "-------------------------------------------------------------\n"); CHKERRQ(ierr);
2925 ierr = PetscPrintf(PETSC_COMM_SELF, " Run Mode : %s\n", simCtx->OnlySetup ? "SETUP ONLY" : "Full Simulation"); CHKERRQ(ierr);
2926 ierr = PetscPrintf(PETSC_COMM_SELF, " Start Time : %.4f\n", (double)StartTime); CHKERRQ(ierr);
2927 ierr = PetscPrintf(PETSC_COMM_SELF, " Timestep Size : %.4f\n", (double)simCtx->dt); CHKERRQ(ierr);
2928 ierr = PetscPrintf(PETSC_COMM_SELF, " Starting Step : %d\n", StartStep); CHKERRQ(ierr);
2929 ierr = PetscPrintf(PETSC_COMM_SELF, " Total Steps to Run : %d\n", StepsToRun); CHKERRQ(ierr);
2930 ierr = PetscPrintf(PETSC_COMM_SELF, " Ending Step : %d\n", StartStep + StepsToRun); CHKERRQ(ierr);
2931 if (simCtx->tiout > 0) {
2932 ierr = PetscPrintf(PETSC_COMM_SELF, " Field/Restart Cadence : every %d step(s)\n", simCtx->tiout); CHKERRQ(ierr);
2933 } else {
2934 ierr = PetscPrintf(PETSC_COMM_SELF, " Field/Restart Cadence : DISABLED\n"); CHKERRQ(ierr);
2935 }
2936 /* Recorded whether or not statistics are configured, so a log says plainly
2937 * whether monitoring was active rather than leaving its absence ambiguous. */
2938 if (FieldStatisticsIsActive(simCtx) && simCtx->statisticsConsoleOutputFreq > 0) {
2939 ierr = PetscPrintf(PETSC_COMM_SELF, " Statistics Console Cadence : every %d step(s), %d window(s)\n",
2940 simCtx->statisticsConsoleOutputFreq, simCtx->fieldStatisticsWindowCount); CHKERRQ(ierr);
2941 } else if (FieldStatisticsIsActive(simCtx)) {
2942 ierr = PetscPrintf(PETSC_COMM_SELF, " Statistics Console Cadence : DISABLED (%d window(s) accumulating)\n",
2943 simCtx->fieldStatisticsWindowCount); CHKERRQ(ierr);
2944 } else {
2945 ierr = PetscPrintf(PETSC_COMM_SELF, " Statistics Console Cadence : DISABLED (no window configured)\n"); CHKERRQ(ierr);
2946 }
2947 ierr = PetscPrintf(PETSC_COMM_SELF, " Immersed Boundary : %s\n", simCtx->immersed ? "ENABLED" : "DISABLED"); CHKERRQ(ierr);
2948 if (simCtx->walltimeGuardEnabled) {
2949 ierr = PetscPrintf(
2950 PETSC_COMM_SELF,
2951 " Runtime Walltime Guard : %s (warmup=%d, multiplier=%.2f, min=%.1f s, alpha=%.2f)\n",
2952 simCtx->walltimeGuardActive ? "ENABLED" : "CONFIGURED BUT INACTIVE",
2953 simCtx->walltimeGuardWarmupSteps,
2954 (double)simCtx->walltimeGuardMultiplier,
2955 (double)simCtx->walltimeGuardMinSeconds,
2956 (double)simCtx->walltimeGuardEstimatorAlpha
2957 ); CHKERRQ(ierr);
2958 } else {
2959 ierr = PetscPrintf(PETSC_COMM_SELF, " Runtime Walltime Guard : DISABLED\n"); CHKERRQ(ierr);
2960 }
2961 ierr = PetscPrintf(PETSC_COMM_SELF, " Console Log Level : %s\n", log_level_name); CHKERRQ(ierr);
2962 ierr = PetscPrintf(PETSC_COMM_SELF, " Profiling Timestep Output : %s\n", simCtx->profilingTimestepMode); CHKERRQ(ierr);
2963 ierr = PetscPrintf(PETSC_COMM_SELF, " Profiling Final Summary : %s\n", simCtx->profilingFinalSummary ? "ENABLED" : "DISABLED"); CHKERRQ(ierr);
2964 if (simCtx->runtimeMemoryLogEnabled) {
2965 ierr = PetscPrintf(PETSC_COMM_SELF, " Runtime Memory Log : ENABLED (%s)\n", simCtx->runtimeMemoryLogFile); CHKERRQ(ierr);
2966 } else {
2967 ierr = PetscPrintf(PETSC_COMM_SELF, " Runtime Memory Log : DISABLED\n"); CHKERRQ(ierr);
2968 }
2969 ierr = PetscPrintf(PETSC_COMM_SELF, " Solution Convergence Log : %s\n",
2970 simCtx->solutionConvergenceEnabled ? "ENABLED" : "DISABLED"); CHKERRQ(ierr);
2971 ierr = PetscPrintf(PETSC_COMM_SELF, " Number of MPI Processes : %d\n", num_mpi_procs); CHKERRQ(ierr);
2972 ierr = PetscPrintf(PETSC_COMM_WORLD," Number of Particles : %d\n", total_num_particles); CHKERRQ(ierr);
2973 if (simCtx->np > 0) {
2974 const char *particle_init_str = ParticleInitializationToString(simCtx->ParticleInitialization);
2975
2976 if (simCtx->particleConsoleOutputFreq > 0) {
2977 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Console Cadence : every %d step(s)\n", simCtx->particleConsoleOutputFreq); CHKERRQ(ierr);
2978 } else {
2979 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Console Cadence : DISABLED\n"); CHKERRQ(ierr);
2980 }
2981 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Log Row Sampling : every %d particle(s)\n", simCtx->LoggingFrequency); CHKERRQ(ierr);
2982 if (simCtx->StartStep > 0) {
2983 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Restart Mode : %s\n", simCtx->particleRestartMode); CHKERRQ(ierr);
2984 }
2985 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Initialization Mode: %s\n", particle_init_str); CHKERRQ(ierr);
2986 ierr = PetscPrintf(PETSC_COMM_SELF, " Interpolation Method : %s\n",
2987 simCtx->interpolationMethod == INTERP_TRILINEAR ? "Trilinear (direct cell-center)" : "CornerAveraged (legacy)"); CHKERRQ(ierr);
2990 if (user->inletFaceDefined) {
2991 ierr = PetscPrintf(PETSC_COMM_SELF, " Particles Initialized At : %s (Enum Val: %d)\n", BCFaceToString(user->identifiedInletBCFace), user->identifiedInletBCFace); CHKERRQ(ierr);
2992 } else {
2993 ierr = PetscPrintf(PETSC_COMM_SELF, " Particles Initialized At : --- (No INLET face identified)\n"); CHKERRQ(ierr);
2994 }
2995 }
2996 }
2997 if(strcmp(simCtx->eulerianSource,"solve")==0 || strcmp(simCtx->eulerianSource,"load")==0){
2998 ierr = PetscPrintf(PETSC_COMM_WORLD," Reynolds Number : %le\n", simCtx->ren); CHKERRQ(ierr);
2999 //ierr = PetscPrintf(PETSC_COMM_WORLD," Von-Neumann Number : %le\n", simCtx->vnn); CHKERRQ(ierr);
3000 if(strcmp(simCtx->eulerianSource,"solve")==0){
3001 //ierr = PetscPrintf(PETSC_COMM_WORLD," Stanton Number : %le\n", simCtx->st); CHKERRQ(ierr);
3002 ierr = PetscPrintf(PETSC_COMM_WORLD," Momentum Equation Solver : %s\n", MomentumSolverTypeToString(simCtx->mom_solver_type)); CHKERRQ(ierr);
3004 ierr = PetscPrintf(PETSC_COMM_WORLD," Initial Pseudo-CFL (Courant): %le\n", simCtx->pseudo_cfl); CHKERRQ(ierr);
3005 ierr = PetscPrintf(PETSC_COMM_WORLD," Pseudo-CFL Range : [%le, %le]\n", simCtx->min_pseudo_cfl, simCtx->max_pseudo_cfl); CHKERRQ(ierr);
3006 ierr = PetscPrintf(PETSC_COMM_WORLD," Pseudo-CFL Adaptation : growth=%le, reduction=%le, backtrack=%s\n",
3008 simCtx->no_pseudo_cfl_backtrack ? "DISABLED" : "ENABLED"); CHKERRQ(ierr);
3009 ierr = PetscPrintf(PETSC_COMM_WORLD," Pseudo-Time Iteration Limit : %d\n", simCtx->mom_max_pseudo_steps); CHKERRQ(ierr);
3010 } else if (simCtx->mom_solver_type == MOMENTUM_SOLVER_NEWTON_KRYLOV) {
3011 ierr = PetscPrintf(PETSC_COMM_WORLD," Newton-Krylov PETSc Controls: SNES/KSP options (mom_nk_*)\n"); CHKERRQ(ierr);
3012 ierr = PetscPrintf(PETSC_COMM_WORLD," Newton-Krylov History Log : %s\n", simCtx->mom_nk_monitor_history ? "ENABLED" : "DISABLED"); CHKERRQ(ierr);
3013 } else if (simCtx->mom_solver_type == MOMENTUM_SOLVER_EXPLICIT_RK) {
3014 ierr = PetscPrintf(PETSC_COMM_WORLD," Pseudo-Time Controller : NOT APPLICABLE\n"); CHKERRQ(ierr);
3015 }
3016 ierr = PetscPrintf(PETSC_COMM_WORLD," Solution Convergence Mode : %s\n", convergence_mode_name); CHKERRQ(ierr);
3018 ierr = PetscPrintf(PETSC_COMM_WORLD," Convergence Period : %d step(s)\n", simCtx->solutionConvergencePeriodSteps); CHKERRQ(ierr);
3020 ierr = PetscPrintf(PETSC_COMM_WORLD," Convergence Window : %d step(s)\n", simCtx->solutionConvergenceWindowSteps); CHKERRQ(ierr);
3021 }
3022 ierr = PetscPrintf(PETSC_COMM_WORLD," Large Eddy Simulation Model : %s\n", LESModelToString(simCtx->les)); CHKERRQ(ierr);
3023 }
3024 if (strcmp(simCtx->eulerianSource, "load") == 0) {
3025 ierr = PetscPrintf(PETSC_COMM_SELF, " Eulerian State Source : load (%s)\n",
3026 simCtx->restart_dir); CHKERRQ(ierr);
3027 } else if (simCtx->StartStep > 0) {
3028 ierr = PetscPrintf(PETSC_COMM_SELF, " Eulerian State Source : restart step %d (%s)\n",
3029 simCtx->StartStep, simCtx->restart_dir); CHKERRQ(ierr);
3030 } else {
3031 const char* field_init_str = InitialConditionModeToString(simCtx->initialConditionMode);
3032 ierr = PetscPrintf(PETSC_COMM_SELF, " Eulerian State Source : initial condition (%s)\n",
3033 field_init_str); CHKERRQ(ierr);
3034 }
3035 if (strcmp(simCtx->eulerianSource, "solve") == 0 && simCtx->StartStep == 0 &&
3037 ierr = PetscPrintf(PETSC_COMM_SELF,
3038 " Constant Velocity (Cart.) : x=%.4f y=%.4f z=%.4f\n",
3039 (double)simCtx->InitialConstantContra.x,
3040 (double)simCtx->InitialConstantContra.y,
3041 (double)simCtx->InitialConstantContra.z); CHKERRQ(ierr);
3042 } else if (strcmp(simCtx->eulerianSource, "solve") == 0 && simCtx->StartStep == 0 &&
3044 ierr = PetscPrintf(PETSC_COMM_SELF,
3045 " Constant Velocity (Curv.) : speed=%.4f direction=%s\n",
3046 (double)simCtx->icVelocityPhysical,
3047 FlowDirectionToString(simCtx->flowDirection)); CHKERRQ(ierr);
3048 } else if (strcmp(simCtx->eulerianSource, "solve") == 0 && simCtx->StartStep == 0 &&
3050 ierr = PetscPrintf(PETSC_COMM_SELF,
3051 " Poiseuille Peak Velocity : speed=%.4f direction=%s\n",
3052 (double)simCtx->icVelocityPhysical,
3053 FlowDirectionToString(simCtx->flowDirection)); CHKERRQ(ierr);
3054 } else if (strcmp(simCtx->eulerianSource, "solve") == 0 && simCtx->StartStep == 0 &&
3056 ierr = PetscPrintf(PETSC_COMM_SELF,
3057 " Initial Velocity File : field=%s directory=%s\n",
3058 simCtx->initialConditionField == IC_FIELD_UCAT ? "Ucat" : "Ucont",
3059 simCtx->initialConditionDirectory); CHKERRQ(ierr);
3060 }
3061 } else if(strcmp(simCtx->eulerianSource,"analytical")==0){
3062 ierr = PetscPrintf(PETSC_COMM_WORLD," Analytical Solution Type : %s\n", simCtx->AnalyticalSolutionType); CHKERRQ(ierr);
3063 }
3064 ierr = PetscPrintf(PETSC_COMM_SELF, "=============================================================\n"); CHKERRQ(ierr);
3065 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); CHKERRQ(ierr);
3066 }
3067 PetscFunctionReturn(0);
3068}
PetscErrorCode GetBCParamReal(BC_Param *params, const char *key, PetscReal *value_out, PetscBool *found)
Internal helper implementation: GetBCParamReal().
Definition io.c:752
PetscErrorCode GetDrivenSeamFluxFlag(BC_Param *params, PetscBool *value_out, PetscBool *found)
Implementation of GetDrivenSeamFluxFlag().
Definition io.c:814
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
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:87
const char * BCTypeToString(BCType type)
Returns the canonical log token for a boundary mathematical type.
Definition logging.c:773
const char * FlowDirectionToString(FlowDirection fd)
Convert a FlowDirection enum value to its YAML token string.
Definition logging.c:705
const char * InitialConditionModeToString(InitialConditionMode mode)
Convert an initial-condition mode to a string representation.
Definition logging.c:689
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
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
PetscReal icVelocityPhysical
Definition variables.h:759
PetscBool mom_nk_monitor_history
Definition variables.h:752
@ INLET
Definition variables.h:290
PetscBool inletFaceDefined
Definition variables.h:932
PetscBool profilingFinalSummary
Definition variables.h:868
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:931
PetscInt statisticsConsoleOutputFreq
Definition variables.h:772
BCFace identifiedInletBCFace
Definition variables.h:933
PetscBool walltimeGuardActive
Definition variables.h:870
PetscReal pseudo_cfl_reduction_factor
Definition variables.h:745
InitialConditionMode initialConditionMode
Definition variables.h:754
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:552
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:555
FlowDirection flowDirection
Definition variables.h:758
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:883
PetscReal min_pseudo_cfl
Definition variables.h:746
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:309
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:308
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:319
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:318
@ BC_HANDLER_INLET_PROFILE_FROM_FILE
Definition variables.h:310
PetscReal ren
Definition variables.h:744
BCHandlerType handler_type
Definition variables.h:369
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:173
PetscBool solutionConvergenceEnabled
Definition variables.h:761
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:884
PetscInt StepsToRun
Definition variables.h:706
char profilingTimestepMode[32]
Definition variables.h:866
PetscInt k_periodic
Definition variables.h:791
PetscBool no_pseudo_cfl_backtrack
Definition variables.h:748
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:172
PetscBool OnlySetup
Definition variables.h:711
@ MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK
Definition variables.h:536
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:535
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:537
PetscInt solutionConvergencePeriodSteps
Definition variables.h:763
PetscScalar x
Definition variables.h:103
InterpolationMethod interpolationMethod
Definition variables.h:832
PetscReal max_pseudo_cfl
Definition variables.h:746
BoundingBox * bboxlist
Definition variables.h:830
BC_Param * params
Definition variables.h:370
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:715
PetscBool walltimeGuardEnabled
Definition variables.h:869
ParticleInitializationType ParticleInitialization
Definition variables.h:831
PetscScalar z
Definition variables.h:103
@ INTERP_TRILINEAR
Definition variables.h:565
PetscInt solutionConvergenceWindowSteps
Definition variables.h:764
PetscReal pseudo_cfl_growth_factor
Definition variables.h:745
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:729
@ 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
PetscInt particleConsoleOutputFreq
Definition variables.h:708
Cmpnts InitialConstantContra
Definition variables.h:757
PetscInt i_periodic
Definition variables.h:791
PetscInt mom_max_pseudo_steps
Definition variables.h:737
PetscScalar y
Definition variables.h:103
@ IC_FIELD_UCAT
Definition variables.h:161
PetscMPIInt size
Definition variables.h:699
Cmpnts periodic_translation[3]
Definition variables.h:927
@ SOLUTION_CONVERGENCE_TRANSIENT
Definition variables.h:547
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:545
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:546
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:544
PetscBool periodic_translation_valid[3]
Definition variables.h:928
BCType mathematical_type
Definition variables.h:368
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:762
InitialConditionField initialConditionField
Definition variables.h:755
BoundingBox bbox
Definition variables.h:922
MomentumSolverType mom_solver_type
Definition variables.h:736
PetscInt immersed
Definition variables.h:726
PetscReal pseudo_cfl
Definition variables.h:744
PetscInt LoggingFrequency
Definition variables.h:857
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:261
PetscInt j_periodic
Definition variables.h:791
A node in a linked list for storing key-value parameters from the bcs.dat file.
Definition variables.h:336
Defines a 3D axis-aligned bounding box.
Definition variables.h:171
A 3D point or vector with PetscScalar components.
Definition variables.h:102
Here is the call graph for this function:
Here is the caller graph for this function:

◆ StringToBCFace()

PetscErrorCode StringToBCFace ( const char *  str,
BCFace face_out 
)

Converts a face-token string (e.g., "-Xi", "+Eta") to the internal BCFace enum.

Parameters
[in]strInput token from configuration.
[out]face_outParsed enum value on success.
Returns
PetscErrorCode 0 on success, non-zero for invalid tokens or null pointers.

Converts a face-token string (e.g., "-Xi", "+Eta") to the internal BCFace enum.

Local to this translation unit.

Definition at line 679 of file io.c.

679 {
680 if (strcasecmp(str, "-Xi") == 0) *face_out = BC_FACE_NEG_X;
681 else if (strcasecmp(str, "+Xi") == 0) *face_out = BC_FACE_POS_X;
682 else if (strcasecmp(str, "-Eta") == 0) *face_out = BC_FACE_NEG_Y;
683 else if (strcasecmp(str, "+Eta") == 0) *face_out = BC_FACE_POS_Y;
684 else if (strcasecmp(str, "-Zeta") == 0) *face_out = BC_FACE_NEG_Z;
685 else if (strcasecmp(str, "+Zeta") == 0) *face_out = BC_FACE_POS_Z;
686 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown face specifier: %s", str);
687 return 0;
688}
@ BC_FACE_NEG_X
Definition variables.h:262
@ BC_FACE_POS_Z
Definition variables.h:264
@ BC_FACE_POS_Y
Definition variables.h:263
@ BC_FACE_NEG_Z
Definition variables.h:264
@ BC_FACE_POS_X
Definition variables.h:262
@ BC_FACE_NEG_Y
Definition variables.h:263
Here is the caller graph for this function:

◆ StringToBCType()

PetscErrorCode StringToBCType ( const char *  str,
BCType type_out 
)

Converts a mathematical BC type string (e.g., "PERIODIC", "WALL") to BCType.

Parameters
[in]strInput token from configuration.
[out]type_outParsed enum value on success.
Returns
PetscErrorCode 0 on success, non-zero for invalid tokens or null pointers.

Converts a mathematical BC type string (e.g., "PERIODIC", "WALL") to BCType.

Local to this translation unit.

Definition at line 694 of file io.c.

694 {
695 if (strcasecmp(str, "WALL") == 0) *type_out = WALL;
696 else if (strcasecmp(str, "SYMMETRY") == 0) *type_out = SYMMETRY;
697 else if (strcasecmp(str, "INLET") == 0) *type_out = INLET;
698 else if (strcasecmp(str, "OUTLET") == 0) *type_out = OUTLET;
699 else if (strcasecmp(str, "PERIODIC") == 0) *type_out = PERIODIC;
700 // ... add other BCTypes here ...
701 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown BC Type string: %s", str);
702 return 0;
703}
@ SYMMETRY
Definition variables.h:288
@ OUTLET
Definition variables.h:289
@ PERIODIC
Definition variables.h:292
@ WALL
Definition variables.h:286
Here is the caller graph for this function:

◆ StringToBCHandlerType()

PetscErrorCode StringToBCHandlerType ( const char *  str,
BCHandlerType handler_out 
)

Converts a BC handler token (implementation strategy) to BCHandlerType.

Parameters
[in]strInput handler token from configuration.
[out]handler_outParsed enum value on success.
Returns
PetscErrorCode 0 on success, non-zero for invalid tokens or null pointers.

Converts a BC handler token (implementation strategy) to BCHandlerType.

Local to this translation unit.

Definition at line 709 of file io.c.

709 {
710 if (strcasecmp(str, "noslip") == 0) *handler_out = BC_HANDLER_WALL_NOSLIP;
711 else if (strcasecmp(str, "constant_velocity") == 0) *handler_out = BC_HANDLER_INLET_CONSTANT_VELOCITY;
712 else if (strcasecmp(str, "conservation") == 0) *handler_out = BC_HANDLER_OUTLET_CONSERVATION;
713 else if (strcasecmp(str, "parabolic") == 0) *handler_out = BC_HANDLER_INLET_PARABOLIC;
714 else if (strcasecmp(str, "prescribed_flow") == 0) *handler_out = BC_HANDLER_INLET_PROFILE_FROM_FILE;
715 else if (strcasecmp(str,"geometric") == 0) *handler_out = BC_HANDLER_PERIODIC_GEOMETRIC;
716 else if (strcasecmp(str,"constant_flux") == 0) *handler_out = BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX;
717 else if (strcasecmp(str,"initial_flux") == 0) *handler_out = BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX;
718 // ... add other BCHandlerTypes here ...
719 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown BC Handler string: %s", str);
720 return 0;
721}
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:316
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:305
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:314
Here is the caller graph for this function:

◆ ValidateBCHandlerForBCType()

PetscErrorCode ValidateBCHandlerForBCType ( BCType  type,
BCHandlerType  handler 
)

Validates that a selected handler is compatible with a mathematical BC type.

Parameters
[in]typeMathematical BC type (e.g., WALL, PERIODIC).
[in]handlerSelected handler implementation enum.
Returns
PetscErrorCode 0 if compatible, non-zero if the combination is invalid.

Validates that a selected handler is compatible with a mathematical BC type.

Local to this translation unit.

Definition at line 727 of file io.c.

727 {
728 switch (type) {
729 case OUTLET:
730 if(handler != BC_HANDLER_OUTLET_CONSERVATION) return PETSC_ERR_ARG_WRONG;
731 break;
732 case WALL:
733 if (handler != BC_HANDLER_WALL_NOSLIP && handler != BC_HANDLER_WALL_MOVING) return PETSC_ERR_ARG_WRONG;
734 break;
735 case INLET:
736 if (handler != BC_HANDLER_INLET_CONSTANT_VELOCITY &&
737 handler != BC_HANDLER_INLET_PARABOLIC &&
738 handler != BC_HANDLER_INLET_PROFILE_FROM_FILE) return PETSC_ERR_ARG_WRONG;
739 break;
740 case PERIODIC:
741 if(handler != BC_HANDLER_PERIODIC_GEOMETRIC && handler != BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX && handler != BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX) return PETSC_ERR_ARG_WRONG;
742 // ... add other validation cases here ...
743 default: break;
744 }
745 return 0; // Combination is valid
746}
@ BC_HANDLER_WALL_MOVING
Definition variables.h:306
Here is the caller graph for this function:

◆ FreeBC_ParamList()

void FreeBC_ParamList ( BC_Param head)

Frees an entire linked list of boundary-condition parameters.

Parameters
[in,out]headHead pointer of the BC_Param list to destroy.

Frees an entire linked list of boundary-condition parameters.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
FreeBC_ParamList()

Definition at line 664 of file io.c.

664 {
665 BC_Param *current = head;
666 while (current != NULL) {
667 BC_Param *next = current->next;
668 PetscFree(current->key);
669 PetscFree(current->value);
670 PetscFree(current);
671 current = next;
672 }
673}
struct BC_Param_s * next
Definition variables.h:339
char * key
Definition variables.h:337
char * value
Definition variables.h:338
Here is the caller graph for this function:

◆ GetBCParamReal()

PetscErrorCode GetBCParamReal ( BC_Param params,
const char *  key,
PetscReal *  value_out,
PetscBool *  found 
)

Searches a BC_Param linked list for a key and returns its value as a double.

Parameters
paramsThe head of the BC_Param linked list.
keyThe key to search for (case-insensitive).
[out]value_outThe found value, converted to a PetscReal.
[out]foundSet to PETSC_TRUE if the key was found, PETSC_FALSE otherwise.
Returns
0 on success.

Searches a BC_Param linked list for a key and returns its value as a double.

Local to this translation unit.

Definition at line 752 of file io.c.

752 {
753 *found = PETSC_FALSE;
754 *value_out = 0.0;
755 if (!key) return 0; // No key to search for
756
757 BC_Param *current = params;
758 while (current) {
759 if (strcasecmp(current->key, key) == 0) {
760 *value_out = atof(current->value);
761 *found = PETSC_TRUE;
762 return 0; // Found it, we're done
763 }
764 current = current->next;
765 }
766 return 0; // It's not an error to not find the key.
767}
Here is the caller graph for this function:

◆ GetBCParamBool()

PetscErrorCode GetBCParamBool ( BC_Param params,
const char *  key,
PetscBool *  value_out,
PetscBool *  found 
)

Searches a BC_Param linked list for a key and returns its value as a bool.

Parameters
paramsThe head of the BC_Param linked list.
keyThe key to search for (case-insensitive).
[out]value_outThe found value, converted to a PetscBool.
[out]foundSet to PETSC_TRUE if the key was found, PETSC_FALSE otherwise.
Returns
0 on success.

Searches a BC_Param linked list for a key and returns its value as a bool.

Local to this translation unit.

Definition at line 773 of file io.c.

773 {
774 *found = PETSC_FALSE;
775 *value_out = PETSC_FALSE;
776 if (!key) return 0; // No key to search for
777
778 BC_Param *current = params;
779 while (current) {
780 if (strcasecmp(current->key, key) == 0) {
781 // Key was found.
782 *found = PETSC_TRUE;
783
784 // Check the value string. Default to FALSE if the value is NULL or doesn't match a "true" string.
785 if (current->value &&
786 (strcasecmp(current->value, "true") == 0 ||
787 strcmp(current->value, "1") == 0 ||
788 strcasecmp(current->value, "yes") == 0))
789 {
790 *value_out = PETSC_TRUE;
791 } else {
792 *value_out = PETSC_FALSE;
793 }
794 return 0; // Found it, we're done
795 }
796 current = current->next;
797 }
798 return 0; // It's not an error to not find the key.
799}
Here is the caller graph for this function:

◆ GetDrivenSeamFluxFlag()

PetscErrorCode GetDrivenSeamFluxFlag ( BC_Param params,
PetscBool *  value_out,
PetscBool *  found 
)

Read the driven-flow seam-flux flag, accepting its deprecated apply_trim spelling.

Parameters
[in]paramsParameter list for the face.
[out]value_outResolved flag value.
[out]foundWhether either spelling was present.
Returns
PetscErrorCode 0 on success.

Read the driven-flow seam-flux flag, accepting its deprecated apply_trim spelling.

The option was originally spelled apply_trim, which said that something was trimmed but not what or why. The canonical name is now enforce_seam_flux. Generated bcs.run files carry the canonical name, but a hand-written or archived one may still use the old spelling, so both are accepted here and the canonical name wins. The argument contract lives with the header declaration in include/io.h.

See also
GetDrivenSeamFluxFlag()

Definition at line 814 of file io.c.

815{
816 PetscErrorCode ierr;
817 PetscFunctionBeginUser;
818
819 ierr = GetBCParamBool(params, "enforce_seam_flux", value_out, found); CHKERRQ(ierr);
820 if (!*found) {
821 ierr = GetBCParamBool(params, "apply_trim", value_out, found); CHKERRQ(ierr);
822 }
823 PetscFunctionReturn(0);
824}
PetscErrorCode GetBCParamBool(BC_Param *params, const char *key, PetscBool *value_out, PetscBool *found)
Internal helper implementation: GetBCParamBool().
Definition io.c:773
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParseAllBoundaryConditions()

PetscErrorCode ParseAllBoundaryConditions ( UserCtx user,
const char *  bcs_input_filename 
)

Parses the boundary conditions file to configure the type, handler, and any associated parameters for all 6 global faces of the domain.

This function performs the following steps:

  1. On MPI rank 0, it reads the specified configuration file line-by-line.
  2. It parses each line for <Face> <Type> <Handler> [param=value]... format.
  3. It validates the parsed strings and stores the configuration, including a linked list of parameters, in a temporary array.
  4. It then serializes this configuration and broadcasts it to all other MPI ranks.
  5. All ranks (including rank 0) then deserialize the broadcasted data to populate their local user->boundary_faces array identically.
  6. It also sets the particle inlet lookup fields in UserCtx.
Parameters
[in,out]userThe main UserCtx struct where the final configuration for all ranks will be stored.
[in]bcs_input_filenameThe path to the boundary conditions configuration file.
Returns
PetscErrorCode 0 on success, error code on failure.

Parses the boundary conditions file to configure the type, handler, and any associated parameters for all 6 global faces of the domain.

Local to this translation unit.

Definition at line 837 of file io.c.

838{
839 PetscErrorCode ierr;
840 PetscMPIInt rank;
841
842 // Temporary storage for rank 0 to build the configuration before broadcasting.
843 BoundaryFaceConfig configs_rank0[6];
844
845 PetscFunctionBeginUser;
847 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
848
849 if (rank == 0) {
850 FILE *file;
851 char line_buffer[1024];
852
853 // Initialize the temporary config array with safe defaults on rank 0.
854 for (int i = 0; i < 6; i++) {
855 configs_rank0[i].face_id = (BCFace)i;
856 configs_rank0[i].mathematical_type = WALL;
857 configs_rank0[i].handler_type = BC_HANDLER_WALL_NOSLIP;
858 configs_rank0[i].params = NULL;
859 configs_rank0[i].handler = NULL; // Handler object is not created here.
860 }
861
862 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing BC configuration from '%s' on rank 0... \n", bcs_input_filename);
863 file = fopen(bcs_input_filename, "r");
864 if (!file) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Could not open BCs file '%s'.", bcs_input_filename);
865
866 while (fgets(line_buffer, sizeof(line_buffer), file)) {
867 char *current_pos = line_buffer;
868 while (isspace((unsigned char)*current_pos)) current_pos++; // Skip leading whitespace
869 if (*current_pos == '#' || *current_pos == '\0' || *current_pos == '\n' || *current_pos == '\r') continue;
870
871 char *face_str = strtok(current_pos, " \t\n\r");
872 char *type_str = strtok(NULL, " \t\n\r");
873 char *handler_str = strtok(NULL, " \t\n\r");
874
875 if (!face_str || !type_str || !handler_str) {
876 LOG_ALLOW(GLOBAL, LOG_WARNING, "Malformed line in bcs.dat, skipping: %s \n", line_buffer);
877 continue;
878 }
879
880 BCFace face_enum;
881 BCType type_enum;
882 BCHandlerType handler_enum;
883 const char* handler_name_for_log;
884
885 // --- Convert strings to enums and validate ---
886 ierr = StringToBCFace(face_str, &face_enum); CHKERRQ(ierr);
887 ierr = StringToBCType(type_str, &type_enum); CHKERRQ(ierr);
888 ierr = StringToBCHandlerType(handler_str, &handler_enum); CHKERRQ(ierr);
889 ierr = ValidateBCHandlerForBCType(type_enum, handler_enum);
890 if (ierr) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Validation failed: Handler '%s' is not valid for Type '%s' on Face '%s'.\n", handler_str, type_str, face_str);
891
892 // Store the core types for the corresponding face
893 configs_rank0[face_enum].mathematical_type = type_enum;
894 configs_rank0[face_enum].handler_type = handler_enum;
895 handler_name_for_log = BCHandlerTypeToString(handler_enum); // Assumes this utility exists
896 LOG_ALLOW(GLOBAL, LOG_DEBUG, " Parsed Face '%s': Type=%s, Handler=%s \n", face_str, type_str, handler_name_for_log);
897
898 // --- Parse optional key=value parameters for this face ---
899 FreeBC_ParamList(configs_rank0[face_enum].params); // Clear any previous (default) params
900 configs_rank0[face_enum].params = NULL;
901 BC_Param **param_next_ptr = &configs_rank0[face_enum].params; // Pointer to the 'next' pointer to build the list
902
903 char* token;
904 while ((token = strtok(NULL, " \t\n\r")) != NULL) {
905 char* equals_ptr = strchr(token, '=');
906 if (!equals_ptr) {
907 LOG_ALLOW(GLOBAL, LOG_WARNING, "Malformed parameter '%s' on face '%s', skipping. \n", token, face_str);
908 continue;
909 }
910
911 *equals_ptr = '\0'; // Temporarily split the string at '=' to separate key and value
912 char* key_str = token;
913 char* value_str = equals_ptr + 1;
914
915 BC_Param *new_param;
916 ierr = PetscMalloc1(1, &new_param); CHKERRQ(ierr);
917 ierr = PetscStrallocpy(key_str, &new_param->key); CHKERRQ(ierr);
918 ierr = PetscStrallocpy(value_str, &new_param->value); CHKERRQ(ierr);
919 new_param->next = NULL;
920
921 *param_next_ptr = new_param;
922 param_next_ptr = &new_param->next;
923 LOG_ALLOW(GLOBAL, LOG_TRACE, " - Found param: [%s] = [%s] \n", new_param->key, new_param->value);
924 }
925 }
926 fclose(file);
927 }
928
929 // =========================================================================
930 // BROADCASTING THE CONFIGURATION FROM RANK 0
931 // =========================================================================
932 // This is a critical step to ensure all processes have the same configuration.
933
934 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "Rank %d broadcasting/receiving BC configuration.\n", rank);
935
936 for (int i = 0; i < 6; i++) {
937 // --- Broadcast simple enums ---
938 if (rank == 0) {
939 user->boundary_faces[i] = configs_rank0[i]; // Rank 0 populates its final struct
940 }
941 ierr = MPI_Bcast(&user->boundary_faces[i].mathematical_type, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
942 ierr = MPI_Bcast(&user->boundary_faces[i].handler_type, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
943
944 // --- Serialize and Broadcast the parameter linked list ---
945 PetscInt n_params = 0;
946 if (rank == 0) { // On rank 0, count the number of parameters to send
947 for (BC_Param *p = user->boundary_faces[i].params; p; p = p->next) n_params++;
948 }
949 ierr = MPI_Bcast(&n_params, 1, MPI_INT, 0, PETSC_COMM_WORLD);CHKERRQ(ierr);
950
951 if (rank != 0) { // Non-root ranks need to receive and build the list
952 FreeBC_ParamList(user->boundary_faces[i].params); // Ensure list is empty before building
953 user->boundary_faces[i].params = NULL;
954 }
955
956 BC_Param **param_next_ptr = &user->boundary_faces[i].params;
957
958 for (int j = 0; j < n_params; j++) {
959 char key_buf[256] = {0}, val_buf[256] = {0};
960 if (rank == 0) {
961 // On rank 0, navigate to the j-th param and copy its data to buffers
962 BC_Param *p = user->boundary_faces[i].params;
963 for (int k = 0; k < j; k++) p = p->next;
964 strncpy(key_buf, p->key, 255);
965 strncpy(val_buf, p->value, 255);
966 }
967
968 ierr = MPI_Bcast(key_buf, 256, MPI_CHAR, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
969 ierr = MPI_Bcast(val_buf, 256, MPI_CHAR, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
970
971 if (rank != 0) {
972 // On non-root ranks, deserialize: create a new node and append it
973 BC_Param *new_param;
974 ierr = PetscMalloc1(1, &new_param); CHKERRQ(ierr);
975 ierr = PetscStrallocpy(key_buf, &new_param->key); CHKERRQ(ierr);
976 ierr = PetscStrallocpy(val_buf, &new_param->value); CHKERRQ(ierr);
977 new_param->next = NULL;
978 *param_next_ptr = new_param;
979 param_next_ptr = &new_param->next;
980 } else {
981 // On rank 0, just advance the pointer for the next iteration
982 param_next_ptr = &((*param_next_ptr)->next);
983 }
984 }
985 user->boundary_faces[i].face_id = (BCFace)i; // Ensure face_id is set on all ranks
986 }
987
988 // --- Set particle inlet lookup fields used by the particle system ---
989 user->inletFaceDefined = PETSC_FALSE;
990 for (int i=0; i<6; i++) {
991
992 if (user->boundary_faces[i].mathematical_type == INLET && !user->inletFaceDefined) {
993 user->inletFaceDefined = PETSC_TRUE;
994 user->identifiedInletBCFace = (BCFace)i;
995 LOG_ALLOW(GLOBAL, LOG_INFO, "Inlet face for particle initialization identified as Face %d.\n", i);
996 break; // Found the first one, stop looking
997 }
998 }
999
1000
1001 if (rank == 0) {
1002 // Rank 0 can now free the linked lists it created for the temporary storage.
1003 // As written, user->boundary_faces was populated directly on rank 0, so no extra free is needed.
1004 // for(int i=0; i<6; i++) FreeBC_ParamList(configs_rank0[i].params); // This would be needed if we used configs_rank0 exclusively
1005 }
1006
1008 PetscFunctionReturn(0);
1009}
PetscErrorCode StringToBCHandlerType(const char *str, BCHandlerType *handler_out)
Internal helper implementation: StringToBCHandlerType().
Definition io.c:709
PetscErrorCode ValidateBCHandlerForBCType(BCType type, BCHandlerType handler)
Internal helper implementation: ValidateBCHandlerForBCType().
Definition io.c:727
PetscErrorCode StringToBCFace(const char *str, BCFace *face_out)
Internal helper implementation: StringToBCFace().
Definition io.c:679
void FreeBC_ParamList(BC_Param *head)
Implementation of FreeBC_ParamList().
Definition io.c:664
PetscErrorCode StringToBCType(const char *str, BCType *type_out)
Internal helper implementation: StringToBCType().
Definition io.c:694
BCType
Defines the general mathematical/physical Category of a boundary.
Definition variables.h:283
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:303
BoundaryCondition * handler
Definition variables.h:371
Holds the complete configuration for one of the six boundary faces.
Definition variables.h:366
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DeterminePeriodicity()

PetscErrorCode DeterminePeriodicity ( SimCtx simCtx)

Scans all block-specific boundary condition files to determine a globally consistent periodicity for each dimension, reusing the core type parser.

This is a lightweight pre-parser intended to be called before DMDA creation. It ensures that the periodicity setting is consistent across all blocks, which is a physical requirement for the domain.

  1. It collectively verifies that the mandatory BCS file for each block exists.
  2. On MPI rank 0, it then iterates through the files.
  3. For each line, it attempts to convert the type string to a BCType enum using the standard StringToBCType helper.
  4. If the conversion is successful AND the type is PERIODIC, it flags the corresponding face.
  5. If the conversion fails (e.g., for "WALL", "INLET", etc.), the error is cleared and the line is simply ignored, as it's not relevant to periodicity.
  6. It validates consistency (e.g., -Xi and +Xi match) and ensures all block files specify the same global periodicity.
  7. It broadcasts the final three flags (as integers 0 or 1) to all MPI ranks.
  8. All ranks update the i_periodic, j_periodic, and k_periodic fields in their SimCtx.
Parameters
[in,out]simCtxThe master SimCtx struct, containing the bcs_files list and where the final periodicity flags will be stored.
Returns
PetscErrorCode 0 on success, error code on failure.

Scans all block-specific boundary condition files to determine a globally consistent periodicity for each dimension, reusing the core type parser.

Local to this translation unit.

Definition at line 1024 of file io.c.

1025{
1026 PetscErrorCode ierr;
1027 PetscMPIInt rank;
1028 PetscInt periodic_flags[3] = {0, 0, 0}; // Index 0:I, 1:J, 2:K
1029
1030 PetscFunctionBeginUser;
1031 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1032
1033 // --- Part 1: Collectively verify all BCS files exist before proceeding ---
1034 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
1035 const char *bcs_filename = simCtx->bcs_files[bi];
1036 if (!bcs_filename) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL, "BCS filename for block %d is not set in SimCtx.", bi);
1037 char desc_buf[256];
1038 PetscBool file_exists;
1039 snprintf(desc_buf, sizeof(desc_buf), "BCS file for block %d", bi);
1040 ierr = VerifyPathExistence(bcs_filename, PETSC_FALSE, PETSC_FALSE, desc_buf, &file_exists); CHKERRQ(ierr);
1041 }
1042
1043 // --- Part 2: Rank 0 does the parsing, since we know all files exist ---
1044 if (rank == 0) {
1045 PetscBool global_is_periodic[3] = {PETSC_FALSE, PETSC_FALSE, PETSC_FALSE};
1046 PetscBool is_set = PETSC_FALSE;
1047
1048 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
1049 const char *bcs_filename = simCtx->bcs_files[bi];
1050 FILE *file = fopen(bcs_filename, "r");
1051
1052 PetscBool face_is_periodic[6] = {PETSC_FALSE};
1053 char line_buffer[1024];
1054
1055 while (fgets(line_buffer, sizeof(line_buffer), file)) {
1056 char *current_pos = line_buffer;
1057 while (isspace((unsigned char)*current_pos)) current_pos++;
1058 if (*current_pos == '#' || *current_pos == '\0' || *current_pos == '\n') continue;
1059
1060 // --- Tokenize the line exactly like the main parser ---
1061 char *face_str = strtok(current_pos, " \t\n\r");
1062 char *type_str = strtok(NULL, " \t\n\r");
1063
1064 // If the line doesn't have at least two tokens, we can't determine the type.
1065 if (!face_str || !type_str) continue;
1066
1067 // --- Perform a direct, non-erroring check on the mathematical type string ---
1068 if (strcasecmp(type_str, "PERIODIC") == 0) {
1069 BCFace face_enum;
1070 // A malformed face string on a periodic line IS a fatal error.
1071 ierr = StringToBCFace(face_str, &face_enum); CHKERRQ(ierr);
1072 face_is_periodic[face_enum] = PETSC_TRUE;
1073 }
1074 // Any other type_str (e.g., "WALL", "INLET") is correctly and silently ignored.
1075 }
1076 fclose(file);
1077
1078 // --- Validate consistency within this file ---
1079 if (face_is_periodic[BC_FACE_NEG_X] != face_is_periodic[BC_FACE_POS_X])
1080 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Inconsistent X-periodicity in file '%s' for block %d. Both -Xi and +Xi must be periodic or neither.", bcs_filename, bi);
1081 if (face_is_periodic[BC_FACE_NEG_Y] != face_is_periodic[BC_FACE_POS_Y])
1082 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Inconsistent Y-periodicity in file '%s' for block %d. Both -Eta and +Eta must be periodic or neither.", bcs_filename, bi);
1083 if (face_is_periodic[BC_FACE_NEG_Z] != face_is_periodic[BC_FACE_POS_Z])
1084 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Inconsistent Z-periodicity in file '%s' for block %d. Both -Zeta and +Zeta must be periodic or neither.", bcs_filename, bi);
1085
1086 PetscBool local_is_periodic[3] = {face_is_periodic[BC_FACE_NEG_X], face_is_periodic[BC_FACE_NEG_Y], face_is_periodic[BC_FACE_NEG_Z]};
1087
1088 // --- Validate consistency across block files ---
1089 if (!is_set) {
1090 global_is_periodic[0] = local_is_periodic[0];
1091 global_is_periodic[1] = local_is_periodic[1];
1092 global_is_periodic[2] = local_is_periodic[2];
1093 is_set = PETSC_TRUE;
1094 } else {
1095 if (global_is_periodic[0] != local_is_periodic[0] || global_is_periodic[1] != local_is_periodic[1] || global_is_periodic[2] != local_is_periodic[2]) {
1096 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
1097 "Periodicity mismatch between blocks. Block 0 requires (I:%d, J:%d, K:%d), but block %d (file '%s') has (I:%d, J:%d, K:%d).",
1098 (int)global_is_periodic[0], (int)global_is_periodic[1], (int)global_is_periodic[2],
1099 bi, bcs_filename,
1100 (int)local_is_periodic[0], (int)local_is_periodic[1], (int)local_is_periodic[2]);
1101 }
1102 }
1103 } // end loop over blocks
1104
1105 periodic_flags[0] = (global_is_periodic[0]) ? 1 : 0;
1106 periodic_flags[1] = (global_is_periodic[1]) ? 1 : 0;
1107 periodic_flags[2] = (global_is_periodic[2]) ? 1 : 0;
1108
1109 LOG_ALLOW(GLOBAL, LOG_INFO, "Global periodicity determined: I-periodic=%d, J-periodic=%d, K-periodic=%d\n",
1110 periodic_flags[0], periodic_flags[1], periodic_flags[2]);
1111 }
1112
1113 // --- Part 3: Broadcast the final flags from rank 0 to all other ranks ---
1114 ierr = MPI_Bcast(periodic_flags, 3, MPIU_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
1115
1116 // --- All ranks now update their SimCtx ---
1117 simCtx->i_periodic = periodic_flags[0];
1118 simCtx->j_periodic = periodic_flags[1];
1119 simCtx->k_periodic = periodic_flags[2];
1120
1121 PetscFunctionReturn(0);
1122}
PetscErrorCode VerifyPathExistence(const char *path, PetscBool is_dir, PetscBool is_optional, const char *description, PetscBool *exists)
Internal helper implementation: VerifyPathExistence().
Definition io.c:1128
char ** bcs_files
Definition variables.h:798
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TrimWhitespace()

void TrimWhitespace ( char *  str)

Removes leading and trailing ASCII whitespace from a mutable string.

Parameters
[in,out]strNUL-terminated string compacted in place.

Removes leading and trailing ASCII whitespace from a mutable string.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
TrimWhitespace()

Definition at line 399 of file io.c.

399 {
400 if (!str) return;
401 if (str[0] == '\0') return;
402
403 char *start = str;
404 // Find the first non-whitespace character
405 while (isspace((unsigned char)*start)) {
406 start++;
407 }
408
409 // Find the end of the string
410 char *end = str + strlen(str) - 1;
411 // Move backwards from the end to find the last non-whitespace character
412 while (end > start && isspace((unsigned char)*end)) {
413 end--;
414 }
415
416 // Null-terminate after the last non-whitespace character
417 *(end + 1) = '\0';
418
419 // If there was leading whitespace, shift the string to the left
420 if (str != start) {
421 memmove(str, start, (end - start) + 2); // +2 to include the new null terminator
422 }
423}
Here is the caller graph for this function:

◆ ParsePostProcessingSettings()

PetscErrorCode ParsePostProcessingSettings ( SimCtx simCtx)

Initializes post-processing settings from a config file and command-line overrides.

This function establishes the configuration for a post-processing run by:

  1. Setting hardcoded default values in the PostProcessParams struct.
  2. Reading a configuration file to override the defaults.
  3. Parsing command-line options (-startTime, -endTime, etc.) which can override both the defaults and the file settings.
Parameters
simCtxThe pointer to the simulation context that contains the postprocessing file and struct.
Returns
PetscErrorCode

Initializes post-processing settings from a config file and command-line overrides.

Local to this translation unit.

Definition at line 3076 of file io.c.

3077{
3078 FILE *file;
3079 char line[1024];
3080 PetscBool startTimeSet, endTimeSet, timeStepSet;
3081
3082 PetscFunctionBeginUser;
3084
3085 if (!simCtx || !simCtx->pps) {
3086 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL, "SimCtx or its pps member is NULL in ParsePostProcessingSettings.");
3087 }
3088
3089 char *configFile = simCtx->PostprocessingControlFile;
3090 PostProcessParams *pps = simCtx->pps;
3091
3092
3093 // --- 1. Set Sane Defaults First ---
3094 pps->startTime = 0;
3095 pps->endTime = 0;
3096 pps->timeStep = 1;
3097 pps->outputParticles = PETSC_FALSE;
3098 pps->particle_output_freq = simCtx->LoggingFrequency; // Default to logging frequency;
3099 strcpy(pps->process_pipeline, "");
3100 strcpy(pps->output_fields_instantaneous, "Ucat,P");
3101 strcpy(pps->output_prefix, "Field");
3102 strcpy(pps->particle_output_prefix,"Particle");
3103 strcpy(pps->particle_fields,"velocity,CellID,weight,pid");
3104 strcpy(pps->particle_pipeline,"");
3105 strncpy(pps->statistics_pipeline, "", MAX_PIPELINE_LENGTH - 1);
3106 strncpy(pps->statistics_output_prefix, "Stats", MAX_FILENAME_LENGTH - 1);
3107 strcpy(pps->particleExt,"dat"); // The input file format for particles.
3108 strcpy(pps->eulerianExt,"dat"); // The input file format for Eulerian fields.
3109 /* A negative source step means "the last step this recipe covers", so a recipe
3110 * that does not name one still derives from a bundle that exists. */
3111 pps->field_statistics_windows[0] = '\0';
3112 strcpy(pps->field_statistics_outputs, "mean,reynolds_stress,rms,tke,flux");
3113 strcpy(pps->field_statistics_formats, "vtk");
3115 pps->reference[0] = pps->reference[1] = pps->reference[2] = 1;
3116 strncpy(pps->source_dir, simCtx->output_dir, sizeof(pps->source_dir) - 1);
3117 pps->source_dir[sizeof(pps->source_dir) - 1] = '\0'; // Ensure null-termination
3118
3119 // --- 2. Parse the Configuration File (overrides defaults) ---
3120 file = fopen(configFile, "r");
3121 if (file) {
3122 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing post-processing config file: %s\n", configFile);
3123 while (fgets(line, sizeof(line), file)) {
3124 char *key, *value, *comment;
3125 comment = strchr(line, '#'); if (comment) *comment = '\0';
3126 TrimWhitespace(line); if (strlen(line) == 0) continue;
3127 key = strtok(line, "="); value = strtok(NULL, "=");
3128 if (key && value) {
3129 TrimWhitespace(key); TrimWhitespace(value);
3130 if (strcmp(key, "startTime") == 0) pps->startTime = atoi(value);
3131 else if (strcmp(key, "endTime") == 0) pps->endTime = atoi(value);
3132 else if (strcmp(key, "timeStep") == 0) pps->timeStep = atoi(value);
3133 else if (strcmp(key, "output_particles") == 0) {
3134 if (strcasecmp(value, "true") == 0) pps->outputParticles = PETSC_TRUE;
3135 }
3136 else if (strcasecmp(key, "process_pipeline") == 0) {
3137 strncpy(pps->process_pipeline, value, MAX_PIPELINE_LENGTH - 1);
3138 pps->process_pipeline[MAX_PIPELINE_LENGTH - 1] = '\0'; // Ensure null-termination
3139 } else if (strcasecmp(key, "field_statistics_windows") == 0) {
3140 strncpy(pps->field_statistics_windows, value, MAX_FIELD_LIST_LENGTH - 1);
3142 } else if (strcasecmp(key, "field_statistics_formats") == 0) {
3143 strncpy(pps->field_statistics_formats, value, MAX_FIELD_LIST_LENGTH - 1);
3145 } else if (strcasecmp(key, "field_statistics_outputs") == 0) {
3146 strncpy(pps->field_statistics_outputs, value, MAX_FIELD_LIST_LENGTH - 1);
3148 } else if (strcasecmp(key, "field_statistics_source_step") == 0) {
3149 pps->field_statistics_source_step = atoi(value);
3150 } else if (strcasecmp(key, "output_fields_instantaneous") == 0) {
3151 strncpy(pps->output_fields_instantaneous, value, MAX_FIELD_LIST_LENGTH - 1);
3153 } else if (strcasecmp(key, "output_prefix") == 0) {
3154 strncpy(pps->output_prefix, value, MAX_FILENAME_LENGTH - 1);
3155 pps->output_prefix[MAX_FILENAME_LENGTH - 1] = '\0';
3156 } else if (strcasecmp(key, "particle_output_prefix") == 0) {
3157 strncpy(pps->particle_output_prefix, value, MAX_FILENAME_LENGTH - 1);
3159 } else if (strcasecmp(key, "particle_fields_instantaneous") == 0) {
3160 strncpy(pps->particle_fields, value, MAX_FIELD_LIST_LENGTH - 1);
3161 pps->particle_fields[MAX_FIELD_LIST_LENGTH - 1] = '\0';
3162 } else if (strcasecmp(key, "particle_pipeline") == 0) {
3163 strncpy(pps->particle_pipeline, value, MAX_PIPELINE_LENGTH - 1);
3164 pps->particle_pipeline[MAX_PIPELINE_LENGTH - 1] = '\0';
3165 } else if (strcasecmp(key, "particle_output_freq") == 0) {
3166 pps->particle_output_freq = atoi(value);
3167 } else if (strcasecmp(key, "statistics_pipeline") == 0) {
3168 strncpy(pps->statistics_pipeline, value, MAX_PIPELINE_LENGTH - 1);
3170 } else if (strcasecmp(key, "statistics_output_prefix") == 0) {
3171 strncpy(pps->statistics_output_prefix, value, MAX_FILENAME_LENGTH - 1);
3173 } else if (strcasecmp(key, "particleExt") == 0) {
3174 strncpy(pps->particleExt, value, sizeof(pps->particleExt) - 1);
3175 pps->particleExt[sizeof(pps->particleExt) - 1] = '\0';
3176 } else if (strcasecmp(key, "eulerianExt") == 0) {
3177 strncpy(pps->eulerianExt, value, sizeof(pps->eulerianExt) - 1);
3178 pps->eulerianExt[sizeof(pps->eulerianExt) - 1] = '\0';
3179 } else if (strcmp(key, "reference_ip") == 0) {pps->reference[0] = atoi(value);
3180 } else if (strcmp(key, "reference_jp") == 0) {pps->reference[1] = atoi(value);
3181 } else if (strcmp(key, "reference_kp") == 0) {pps->reference[2] = atoi(value);
3182 } else if (strcasecmp(key, "source_directory") == 0) {
3183 strncpy(pps->source_dir, value, sizeof(pps->source_dir) - 1);
3184 pps->source_dir[sizeof(pps->source_dir) - 1] = '\0';
3185 } else if (strcasecmp(key, "spectra_signature") == 0) {
3186 /* Spectra are computed by the conductor's Python stage, not here. The
3187 key exists so a change to the spectra recipe reaches the recipe
3188 fingerprint that `--continue` compares; this executable has no use
3189 for it and accepting it silently keeps the log free of a warning
3190 that would appear on every post-processing run. */
3191 } else {
3192 LOG_ALLOW(GLOBAL, LOG_WARNING, "Unknown key '%s' in post-processing config file. Ignoring.\n", key);
3193 }
3194 // Add parsing for pipeline, fields, etc. in later phases
3195 }
3196 }
3197 fclose(file);
3198 } else {
3199 LOG_ALLOW(GLOBAL, LOG_WARNING, "Could not open post-processing config file '%s'. Using defaults and command-line overrides.\n", configFile);
3200 }
3201
3202 // --- 3. Parse Command-Line Options (overrides file settings and defaults) ---
3203 PetscOptionsGetInt(NULL, NULL, "-startTime", &pps->startTime, &startTimeSet);
3204 PetscOptionsGetInt(NULL, NULL, "-endTime", &pps->endTime, &endTimeSet);
3205 PetscOptionsGetInt(NULL, NULL, "-timeStep", &pps->timeStep, &timeStepSet);
3206 PetscOptionsGetBool(NULL, NULL, "-output_particles", &pps->outputParticles, NULL);
3207
3208 if(pps->endTime==-1){
3209 pps->endTime = simCtx->StartStep + simCtx->StepsToRun; // Total steps if endTime is set to -1.
3210 }
3211
3212 // If only startTime is given on command line, run for a single step
3213 if (startTimeSet && !endTimeSet) {
3214 pps->endTime = pps->startTime;
3215 }
3216
3217 LOG_ALLOW(GLOBAL, LOG_INFO, "Post-processing configured to run from t=%d to t=%d with step %d. Particle output: %s.\n",
3218 pps->startTime, pps->endTime, pps->timeStep, pps->outputParticles ? "TRUE" : "FALSE");
3219
3220 LOG_ALLOW(GLOBAL, LOG_INFO, "Process Pipeline: %s\n", pps->process_pipeline);
3221 LOG_ALLOW(GLOBAL, LOG_INFO, "Instantaneous Output Fields: %s\n", pps->output_fields_instantaneous);
3222 LOG_ALLOW(GLOBAL, LOG_INFO, "Output Prefix: %s\n", pps->output_prefix);
3223 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Output Prefix: %s\n", pps->particle_output_prefix);
3224 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Fields: %s\n", pps->particle_fields);
3225 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Pipeline: %s\n", pps->particle_pipeline);
3226 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Output Frequency: %d\n", pps->particle_output_freq);
3227 LOG_ALLOW(GLOBAL, LOG_INFO, "Post input extensions: Eulerian='.%s', Particle='.%s'\n", pps->eulerianExt, pps->particleExt);
3228
3230 PetscFunctionReturn(0);
3231}
void TrimWhitespace(char *str)
Implementation of TrimWhitespace().
Definition io.c:399
char statistics_output_prefix[256]
basename for CSV output, e.g.
Definition variables.h:617
char particle_output_prefix[256]
Definition variables.h:612
char output_prefix[256]
Definition variables.h:609
#define MAX_FIELD_LIST_LENGTH
Definition variables.h:587
#define MAX_PIPELINE_LENGTH
Definition variables.h:586
PetscInt reference[3]
Definition variables.h:634
PetscInt timeStep
Definition variables.h:603
#define MAX_FILENAME_LENGTH
Definition variables.h:588
char statistics_pipeline[1024]
e.g.
Definition variables.h:616
char field_statistics_formats[1024]
Comma-separated formats: vtk for derived fields, csv for the convergence history.
Definition variables.h:625
char output_fields_instantaneous[1024]
Definition variables.h:608
char eulerianExt[8]
Definition variables.h:630
char particle_pipeline[1024]
Definition variables.h:610
char process_pipeline[1024]
Definition variables.h:607
PetscInt particle_output_freq
Definition variables.h:613
char particle_fields[1024]
Definition variables.h:611
PetscBool outputParticles
Definition variables.h:604
PetscInt field_statistics_source_step
Committed step supplying the state; negative means the step being processed.
Definition variables.h:627
char particleExt[8]
Definition variables.h:631
char field_statistics_windows[1024]
Comma-separated window names to derive; empty disables the pipeline.
Definition variables.h:621
char field_statistics_outputs[1024]
Comma-separated outputs: mean, reynolds_stress, rms, tke, flux.
Definition variables.h:623
PetscInt startTime
Definition variables.h:601
char PostprocessingControlFile[PETSC_MAX_PATH_LEN]
Definition variables.h:889
Holds all configuration parameters for a post-processing run.
Definition variables.h:596
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParseScalingInformation()

PetscErrorCode ParseScalingInformation ( SimCtx simCtx)

Parses physical scaling parameters from command-line options.

This function reads the reference length, velocity, and density from the PETSc options database (provided via -scaling_L_ref, etc.). It populates the simCtx->scaling struct and calculates the derived reference pressure. It sets default values of 1.0 for a fully non-dimensional case if the options are not provided.

Parameters
[in,out]simCtxThe simulation context whose 'scaling' member will be populated.
Returns
PetscErrorCode

Parses physical scaling parameters from command-line options.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/io.h.

See also
ParseScalingInformation()

Definition at line 3242 of file io.c.

3243{
3244 PetscErrorCode ierr;
3245 PetscBool flg;
3246
3247 PetscFunctionBeginUser;
3249
3250 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx is NULL in ParseScalingInformation");
3251
3252 // --- 1. Set default values to 1.0 ---
3253 // This represents a purely non-dimensional run if no scaling is provided.
3254 simCtx->scaling.L_ref = 1.0;
3255 simCtx->scaling.U_ref = 1.0;
3256 simCtx->scaling.rho_ref = 1.0;
3257
3258 // --- 2. Read overrides from the command line / control file ---
3259 ierr = PetscOptionsGetReal(NULL, NULL, "-scaling_L_ref", &simCtx->scaling.L_ref, &flg); CHKERRQ(ierr);
3260 ierr = PetscOptionsGetReal(NULL, NULL, "-scaling_U_ref", &simCtx->scaling.U_ref, &flg); CHKERRQ(ierr);
3261 ierr = PetscOptionsGetReal(NULL, NULL, "-scaling_rho_ref", &simCtx->scaling.rho_ref, &flg); CHKERRQ(ierr);
3262
3263 // --- 3. Calculate derived scaling factors ---
3264 // Check for division by zero to be safe, though U_ref should be positive.
3265 if (simCtx->scaling.U_ref <= 0.0) {
3266 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Reference velocity U_ref must be positive. Got %g", (double)simCtx->scaling.U_ref);
3267 }
3268 simCtx->scaling.P_ref = simCtx->scaling.rho_ref * simCtx->scaling.U_ref * simCtx->scaling.U_ref;
3269
3270 // --- 4. Log the final, effective scales for verification ---
3271 LOG(GLOBAL, LOG_INFO, "---------------- Physical Scales Initialized -----------------\n");
3272 LOG(GLOBAL, LOG_INFO, " L_ref: %.4f, U_ref: %.4f, rho_ref: %.4f, P_ref: %.4f\n",
3273 simCtx->scaling.L_ref, simCtx->scaling.U_ref, simCtx->scaling.rho_ref, simCtx->scaling.P_ref);
3274 LOG(GLOBAL, LOG_INFO, "--------------------------------------------------------------\n");
3275
3277 PetscFunctionReturn(0);
3278}
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:84
PetscReal L_ref
Definition variables.h:677
ScalingCtx scaling
Definition variables.h:785
PetscReal P_ref
Definition variables.h:680
PetscReal rho_ref
Definition variables.h:679
PetscReal U_ref
Definition variables.h:678
Here is the caller graph for this function: