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 ReadSimulationFields (UserCtx *user, PetscInt ti)
 Reads binary field data for velocity, pressure, and other required vectors.
 
PetscErrorCode ReadFieldData (UserCtx *user, const char *field_name, Vec field_vec, PetscInt ti, const char *ext)
 Reads data for a specific field from a file into the provided vector.
 
PetscErrorCode ReadStatisticalFields (UserCtx *user, PetscInt ti)
 Reads statistical fields used for time-averaged simulations.
 
PetscErrorCode ReadLESFields (UserCtx *user, PetscInt ti)
 Reads LES-related fields used in turbulence modeling.
 
PetscErrorCode ReadRANSFields (UserCtx *user, PetscInt ti)
 Reads RANS-related fields for turbulence modeling.
 
PetscErrorCode WriteFieldData (UserCtx *user, const char *field_name, Vec field_vec, PetscInt ti, const char *ext)
 Writes data from a specific PETSc vector to a file.
 
PetscErrorCode WriteSimulationFields (UserCtx *user)
 Writes simulation fields to files.
 
PetscErrorCode WriteStatisticalFields (UserCtx *user)
 Writes statistical fields for averaging purposes.
 
PetscErrorCode WriteLESFields (UserCtx *user)
 Writes LES-related fields.
 
PetscErrorCode WriteRANSFields (UserCtx *user)
 Writes RANS-related fields.
 
PetscErrorCode WriteSwarmField (UserCtx *user, const char *field_name, PetscInt ti, const char *ext)
 Writes data from a specific field in a PETSc Swarm to a file.
 
PetscErrorCode WriteSwarmIntField (UserCtx *user, const char *field_name, PetscInt ti, const char *ext)
 Writes integer data from a specific PETSc Swarm field to a file.
 
PetscErrorCode WriteAllSwarmFields (UserCtx *user)
 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, 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, PetscInt ti, const char *ext)
 Reads data from a file into a specified field of a PETSc DMSwarm.
 
PetscErrorCode ReadSwarmIntField (UserCtx *user, const char *field_name, PetscInt ti, 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 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 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)
 Helper function to trim leading/trailing whitespace from a 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 85 of file io.c.

86{
87 PetscErrorCode ierr;
88 SimCtx *simCtx = user->simCtx;
89 PetscInt nblk = simCtx->block_number;
90 PetscInt block_index = user->_this;
91 PetscBool found;
92
93 // Temporary arrays to hold the parsed values for ALL blocks
94 PetscInt *IMs = NULL, *JMs = NULL, *KMs = NULL, *cgrids = NULL;
95 PetscReal *xMins = NULL, *xMaxs = NULL, *rxs = NULL;
96 PetscReal *yMins = NULL, *yMaxs = NULL, *rys = NULL;
97 PetscReal *zMins = NULL, *zMaxs = NULL, *rzs = NULL;
98
99 PetscFunctionBeginUser;
101
102 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Reading generated grid inputs for block %d.\n", simCtx->rank, block_index);
103
104 if (block_index >= nblk) {
105 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Block index %d is out of range for nblk=%d", block_index, nblk);
106 }
107
108 // --- Allocate temporary storage for all array options ---
109 ierr = PetscMalloc4(nblk, &IMs, nblk, &JMs, nblk, &KMs, nblk, &cgrids); CHKERRQ(ierr);
110 ierr = PetscMalloc6(nblk, &xMins, nblk, &xMaxs, nblk, &rxs, nblk, &yMins, nblk, &yMaxs, nblk, &rys); CHKERRQ(ierr);
111 ierr = PetscMalloc3(nblk, &zMins, nblk, &zMaxs, nblk, &rzs); CHKERRQ(ierr);
112
113 // --- Set default values for the temporary arrays ---
114 for (PetscInt i = 0; i < nblk; ++i) {
115 IMs[i] = 10; JMs[i] = 10; KMs[i] = 10; cgrids[i] = 0;
116 xMins[i] = 0.0; xMaxs[i] = 1.0; rxs[i] = 1.0;
117 yMins[i] = 0.0; yMaxs[i] = 1.0; rys[i] = 1.0;
118 zMins[i] = 0.0; zMaxs[i] = 1.0; rzs[i] = 1.0;
119 }
120
121 // --- Parse the array options from the command line / control file ---
122 PetscInt count;
123 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-im", IMs, &count, &found); CHKERRQ(ierr);
124 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-jm", JMs, &count, &found); CHKERRQ(ierr);
125 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-km", KMs, &count, &found); CHKERRQ(ierr);
126 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-xMins", xMins, &count, &found); CHKERRQ(ierr);
127 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-xMaxs", xMaxs, &count, &found); CHKERRQ(ierr);
128 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-rxs", rxs, &count, &found); CHKERRQ(ierr);
129 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-yMins", yMins, &count, &found); CHKERRQ(ierr);
130 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-yMaxs", yMaxs, &count, &found); CHKERRQ(ierr);
131 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-rys", rys, &count, &found); CHKERRQ(ierr);
132 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-zMins", zMins, &count, &found); CHKERRQ(ierr);
133 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-zMaxs", zMaxs, &count, &found); CHKERRQ(ierr);
134 count = nblk; ierr = PetscOptionsGetRealArray(NULL, NULL, "-rzs", rzs, &count, &found); CHKERRQ(ierr);
135 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-cgrids", cgrids, &count, &found); CHKERRQ(ierr);
136
137 // --- Assign the parsed values to the specific UserCtx struct passed in ---
138 user->IM = IMs[block_index];
139 user->JM = JMs[block_index];
140 user->KM = KMs[block_index];
141 user->Min_X = xMins[block_index];
142 user->Max_X = xMaxs[block_index];
143 user->rx = rxs[block_index];
144 user->Min_Y = yMins[block_index];
145 user->Max_Y = yMaxs[block_index];
146 user->ry = rys[block_index];
147 user->Min_Z = zMins[block_index];
148 user->Max_Z = zMaxs[block_index];
149 user->rz = rzs[block_index];
150 user->cgrid = cgrids[block_index];
151
152 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d grid generation inputs set: IM=%d, JM=%d, KM=%d\n",
153 simCtx->rank, block_index, user->IM, user->JM, user->KM);
154 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d bounds: X=[%.2f, %.2f], Y=[%.2f, %.2f], Z=[%.2f, %.2f]\n",
155 simCtx->rank, block_index, user->Min_X, user->Max_X, user->Min_Y, user->Max_Y, user->Min_Z, user->Max_Z);
156
157 // --- Clean up temporary storage ---
158 ierr = PetscFree4(IMs, JMs, KMs, cgrids); CHKERRQ(ierr);
159 ierr = PetscFree6(xMins, xMaxs, rxs, yMins, yMaxs, rys); CHKERRQ(ierr);
160 ierr = PetscFree3(zMins, zMaxs, rzs); CHKERRQ(ierr);
161
163 PetscFunctionReturn(0);
164}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#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:199
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:820
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:811
PetscMPIInt rank
Definition variables.h:654
PetscInt cgrid
Definition variables.h:845
PetscInt block_number
Definition variables.h:726
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:833
PetscReal Min_X
Definition variables.h:840
PetscInt KM
Definition variables.h:839
PetscInt _this
Definition variables.h:843
PetscReal ry
Definition variables.h:844
PetscReal Max_Y
Definition variables.h:840
PetscReal rz
Definition variables.h:844
PetscInt JM
Definition variables.h:839
PetscReal Min_Z
Definition variables.h:840
PetscReal Max_X
Definition variables.h:840
PetscReal Min_Y
Definition variables.h:840
PetscInt IM
Definition variables.h:839
PetscReal rx
Definition variables.h:844
PetscReal Max_Z
Definition variables.h:840
The master context for the entire simulation.
Definition variables.h:651
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 170 of file io.c.

171{
172 PetscErrorCode ierr;
173 PetscBool found;
174 PetscInt *IMs = NULL, *JMs = NULL, *KMs = NULL;
175 SimCtx *simCtx = NULL;
176
177 PetscFunctionBeginUser;
178
179 if (!finest_users) {
180 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "finest_users cannot be NULL.");
181 }
182 if (nblk <= 0) {
183 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nblk must be positive. Got %d.", nblk);
184 }
185 simCtx = finest_users[0].simCtx;
186
187 ierr = PetscMalloc3(nblk, &IMs, nblk, &JMs, nblk, &KMs); CHKERRQ(ierr);
188 for (PetscInt i = 0; i < nblk; ++i) {
189 IMs[i] = 10; JMs[i] = 10; KMs[i] = 10;
190 }
191
192 PetscInt count;
193 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-im", IMs, &count, &found); CHKERRQ(ierr);
194 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-jm", JMs, &count, &found); CHKERRQ(ierr);
195 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-km", KMs, &count, &found); CHKERRQ(ierr);
196
197 for (PetscInt bi = 0; bi < nblk; ++bi) {
198 finest_users[bi].IM = IMs[bi];
199 finest_users[bi].JM = JMs[bi];
200 finest_users[bi].KM = KMs[bi];
201 if (simCtx) {
203 "Rank %d: Preloaded analytical grid resolution for block %d: IM=%d, JM=%d, KM=%d\n",
204 simCtx->rank, bi, finest_users[bi].IM, finest_users[bi].JM, finest_users[bi].KM);
205 }
206 }
207
208 ierr = PetscFree3(IMs, JMs, KMs); CHKERRQ(ierr);
209 PetscFunctionReturn(0);
210}
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 219 of file io.c.

220{
221 PetscErrorCode ierr;
222 SimCtx *simCtx = user->simCtx;
223 PetscInt block_index = user->_this;
224
225 PetscFunctionBeginUser;
227
228 // --- One-Time Read and Broadcast Logic ---
230 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "First call to ReadGridFile. Reading and broadcasting grid file header from '%s'...\n", simCtx->grid_file);
231 PetscMPIInt rank = simCtx->rank;
232 PetscInt nblk = simCtx->block_number;
233
234 if (rank == 0) {
235 FILE *fd = fopen(simCtx->grid_file, "r");
236 if (!fd) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file: %s", simCtx->grid_file);
237
238 // Read and validate the canonical PICGRID header.
239 char firstTok[32] = {0};
240 if (fscanf(fd, "%31s", firstTok) != 1)
241 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Empty grid file: %s", simCtx->grid_file);
242 if (strcmp(firstTok, "PICGRID") != 0)
243 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
244 "Grid file %s must begin with the canonical PICGRID header.", simCtx->grid_file);
245 if (fscanf(fd, "%d", &g_nblk_from_file) != 1)
246 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Expected number of blocks after \"PICGRID\" in %s", simCtx->grid_file);
247 if (g_nblk_from_file != nblk) {
248 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Mismatch: -nblk is %d but grid file specifies %d blocks.", nblk, g_nblk_from_file);
249 }
250
251 ierr = PetscMalloc3(nblk, &g_IMs_from_file, nblk, &g_JMs_from_file, nblk, &g_KMs_from_file); CHKERRQ(ierr);
252 for (PetscInt i = 0; i < nblk; ++i) {
253 if (fscanf(fd, "%d %d %d\n", &g_IMs_from_file[i], &g_JMs_from_file[i], &g_KMs_from_file[i]) != 3) {
254 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Expected 3 integers for block %d in %s", i, simCtx->grid_file);
255 }
256 }
257 fclose(fd);
258 }
259
260 // Broadcast nblk to verify (optional, good practice)
261 ierr = MPI_Bcast(&g_nblk_from_file, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
262
263 // Allocate on other ranks before receiving the broadcast
264 if (rank != 0) {
265 ierr = PetscMalloc3(nblk, &g_IMs_from_file, nblk, &g_JMs_from_file, nblk, &g_KMs_from_file); CHKERRQ(ierr);
266 }
267
268 // Broadcast the data arrays
269 ierr = MPI_Bcast(g_IMs_from_file, nblk, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
270 ierr = MPI_Bcast(g_JMs_from_file, nblk, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
271 ierr = MPI_Bcast(g_KMs_from_file, nblk, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
272
273 g_file_has_been_read = PETSC_TRUE;
274 LOG_ALLOW(GLOBAL, LOG_INFO, "Grid file header read and broadcast complete.\n");
275 }
276
277 // --- Per-Block Assignment Logic (runs on every call) ---
278 user->IM = g_IMs_from_file[block_index];
279 user->JM = g_JMs_from_file[block_index];
280 user->KM = g_KMs_from_file[block_index];
281
282 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Set file inputs for Block %d: IM=%d, JM=%d, KM=%d\n",
283 simCtx->rank, block_index, user->IM, user->JM, user->KM);
284
286 PetscFunctionReturn(0);
287}
static PetscInt * g_IMs_from_file
Caches the IM dimensions for all blocks read from the grid file.
Definition io.c:19
static PetscInt g_nblk_from_file
Stores the number of blocks read from the grid file.
Definition io.c:17
static PetscBool g_file_has_been_read
A flag to ensure the grid file is read only once.
Definition io.c:25
static PetscInt * g_KMs_from_file
Caches the KM dimensions for all blocks read from the grid file.
Definition io.c:23
static PetscInt * g_JMs_from_file
Caches the JM dimensions for all blocks read from the grid file.
Definition io.c:21
#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:252
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
char grid_file[PETSC_MAX_PATH_LEN]
Definition variables.h:731
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 741 of file io.c.

742{
743 PetscErrorCode ierr;
744 PetscMPIInt rank;
745 MPI_Comm comm = PETSC_COMM_WORLD;
746
747 PetscFunctionBeginUser;
748 ierr = MPI_Comm_rank(comm, &rank); CHKERRQ(ierr);
749
750 if (rank == 0) {
751 if (is_dir) {
752 ierr = PetscTestDirectory(path, 'r', exists); CHKERRQ(ierr);
753 } else {
754 ierr = PetscTestFile(path, 'r', exists); CHKERRQ(ierr);
755 }
756
757 if (!(*exists)) {
758 if (is_optional) {
759 LOG_ALLOW(GLOBAL, LOG_WARNING, "Optional %s not found at: %s (using defaults/ignoring).\n", description, path);
760 } else {
761 LOG_ALLOW(GLOBAL, LOG_ERROR, "Mandatory %s not found at: %s\n", description, path);
762 }
763 } else {
764 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Found %s: %s\n", description, path);
765 }
766 }
767
768 // Broadcast the result from Rank 0
769 PetscMPIInt exists_int = (rank == 0) ? (PetscMPIInt)(*exists) : 0;
770 ierr = MPI_Bcast(&exists_int, 1, MPI_INT, 0, comm); CHKERRMPI(ierr);
771 *exists = (PetscBool)exists_int;
772
773 // Collective error for mandatory files
774 if (!(*exists) && !is_optional) {
775 SETERRQ(comm, PETSC_ERR_FILE_OPEN, "Mandatory %s not found. Rank 0 expected it at '%s'. Check path and permissions.", description, path);
776 }
777
778 PetscFunctionReturn(0);
779}
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:28
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
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 70 of file io.c.

71{
72 if (!simCtx) {
73 return PETSC_FALSE;
74 }
75 return (PetscBool)(simCtx->tiout > 0 && completed_step > 0 && completed_step % simCtx->tiout == 0);
76}
PetscInt tiout
Definition variables.h:663
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.

Reads contravariant velocity (Ucont) from vfield, Cartesian velocity (Ucat) from ufield, pressure (P), node state (Nvert_o), and optionally statistical quantities, LES, and RANS fields from binary files. Logs missing files but continues execution.

Parameters
[in,out]userPointer to the UserCtx structure containing the simulation context.
[in]tiTimestep index used to construct restart file names.
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 1129 of file io.c.

1130{
1131 PetscErrorCode ierr;
1132
1133 SimCtx *simCtx = user->simCtx;
1134 const char *source_path = NULL;
1135 const char *eulerian_ext = "dat";
1136
1137 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1138 source_path = simCtx->pps->source_dir;
1139 if (simCtx->pps->eulerianExt[0] != '\0') {
1140 eulerian_ext = simCtx->pps->eulerianExt;
1141 }
1142 } else if(simCtx->exec_mode == EXEC_MODE_SOLVER){
1143 source_path = simCtx->restart_dir;
1144 } else{
1145 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Invalid execution mode for reading simulation fields.");
1146 }
1147
1148 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to read simulation fields.\n");
1149
1150 // Set the current I/O directory context
1151 ierr = PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer), "%s/%s",source_path,simCtx->euler_subdir); CHKERRQ(ierr);
1152 simCtx->current_io_directory = simCtx->_io_context_buffer;
1153
1154 // Read Cartesian velocity field
1155 ierr = ReadFieldData(user, "ufield", user->Ucat, ti, eulerian_ext); CHKERRQ(ierr);
1156
1157 // Read contravariant velocity field
1158 ierr = ReadFieldData(user, "vfield", user->Ucont, ti, eulerian_ext); CHKERRQ(ierr);
1159
1160 // Read pressure field
1161 ierr = ReadFieldData(user, "pfield", user->P, ti, eulerian_ext); CHKERRQ(ierr);
1162
1163 // Read node state field (nvert)
1164 ierr = ReadFieldData(user, "nvfield", user->Nvert, ti, eulerian_ext); CHKERRQ(ierr);
1165
1166 LOG_ALLOW(GLOBAL,LOG_INFO,"Successfully read all mandatory fields. \n");
1167
1168 if(simCtx->np>0){
1169 // Read Particle Count field
1170 if(!user->ParticleCount){
1171 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "ParticleCount Vec is NULL but np>0");
1172 }
1173 ierr = ReadOptionalField(user, "ParticleCount", "Particle Count", user->ParticleCount, ti, eulerian_ext); CHKERRQ(ierr);
1174
1175 ierr = ReadOptionalField(user, "psifield", "Scalar Psi Field", user->Psi, ti, eulerian_ext); CHKERRQ(ierr);
1176 }
1177 else{
1178 LOG_ALLOW(GLOBAL, LOG_INFO, "No particles in simulation, skipping Particle fields reading.\n");
1179 }
1180 // Process LES fields if enabled
1181 if (simCtx->les) {
1182 ierr = ReadLESFields(user,ti); CHKERRQ(ierr);
1183 }
1184
1185 // Process RANS fields if enabled
1186 if (simCtx->rans) {
1187 ierr = ReadRANSFields(user,ti); CHKERRQ(ierr);
1188 }
1189
1190 // Process statistical fields if averaging is enabled
1191 if (simCtx->averaging) {
1192 ierr = ReadStatisticalFields(user,ti); CHKERRQ(ierr);
1193 }
1194
1195 simCtx->current_io_directory = NULL; // Clear the I/O context after reading
1196
1197 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished reading simulation fields.\n");
1198
1199 return 0;
1200}
PetscErrorCode ReadStatisticalFields(UserCtx *user, PetscInt ti)
Implementation of ReadStatisticalFields().
Definition io.c:1208
PetscErrorCode ReadRANSFields(UserCtx *user, PetscInt ti)
Internal helper implementation: ReadRANSFields().
Definition io.c:1260
PetscErrorCode ReadLESFields(UserCtx *user, PetscInt ti)
Internal helper implementation: ReadLESFields().
Definition io.c:1232
PetscErrorCode ReadFieldData(UserCtx *user, const char *field_name, Vec field_vec, PetscInt ti, const char *ext)
Internal helper implementation: ReadFieldData().
Definition io.c:901
static PetscErrorCode ReadOptionalField(UserCtx *user, const char *field_name, const char *field_label, Vec field_vec, PetscInt ti, const char *ext)
Internal helper implementation: ReadOptionalField().
Definition io.c:825
char euler_subdir[PETSC_MAX_PATH_LEN]
Definition variables.h:674
PetscInt rans
Definition variables.h:746
PetscInt np
Definition variables.h:753
PetscBool averaging
Definition variables.h:750
Vec Ucont
Definition variables.h:856
char * current_io_directory
Definition variables.h:678
char eulerianExt[8]
Definition variables.h:586
char source_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:563
Vec Ucat
Definition variables.h:856
Vec ParticleCount
Definition variables.h:903
PostProcessParams * pps
Definition variables.h:817
@ EXEC_MODE_SOLVER
Definition variables.h:624
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:625
char _io_context_buffer[PETSC_MAX_PATH_LEN]
Definition variables.h:677
PetscInt les
Definition variables.h:746
Vec Nvert
Definition variables.h:856
ExecutionMode exec_mode
Definition variables.h:670
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:672
Vec Psi
Definition variables.h:904
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,
PetscInt  ti,
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]tiTime index for constructing the file name.
[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 901 of file io.c.

906{
907 PetscErrorCode ierr;
908 char filename[PETSC_MAX_PATH_LEN];
909 MPI_Comm comm;
910 PetscMPIInt rank,size;
911 SimCtx *simCtx = user->simCtx;
912
913
914 PetscFunctionBeginUser;
916
917 if(!simCtx->current_io_directory){
918 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "I/O context directory was not set before calling ReadFieldData().");
919 }
920
921
922 ierr = PetscObjectGetComm((PetscObject)field_vec,&comm);CHKERRQ(ierr);
923 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
924 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
925
926 const char *source_path = NULL;
927 source_path = simCtx->current_io_directory;
928
929 if(!source_path){
930 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "source_path was not set for the current execution mode.");
931 }
932 /* ---------------------------------------------------------------------
933 * Compose <path-to-file>/<field_name><step with 5 digits>_0.<ext>
934 * (all restart files are written by rank-0 with that naming scheme).
935 * ------------------------------------------------------------------ */
936 ierr = PetscSNPrintf(filename,sizeof(filename),
937 "%s/%s%05" PetscInt_FMT "_0.%s",
938 source_path,field_name,ti,ext);CHKERRQ(ierr);
939
941 "Attempting to read <%s> on rank %d/%d\n",
942 filename,(int)rank,(int)size);
943
944 /* ======================================================================
945 * 1. SERIAL JOB – just hand the Vec to VecLoad()
946 * ==================================================================== */
947 if(size==1)
948 {
949 PetscViewer viewer;
950 PetscBool found;
951 Vec temp_vec;
952 PetscInt expectedSize,loadedSize;
953
954 ierr = PetscTestFile(filename,'r',&found);CHKERRQ(ierr);
955 if(!found) SETERRQ(comm,PETSC_ERR_FILE_OPEN,
956 "Restart/Source file not found: %s",filename);
957
958 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr);
959// ---- START MODIFICATION ----
960 // DO NOT load directly into field_vec, as this can resize it, which is
961 // illegal for DMSwarm "view" vectors. Instead, load into a temporary vector.
962 ierr = VecCreate(PETSC_COMM_SELF, &temp_vec); CHKERRQ(ierr);
963 ierr = VecLoad(temp_vec,viewer);CHKERRQ(ierr);
964 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
965
966 // Sanity check: ensure the file size matches the expected vector size.
967 ierr = VecGetSize(field_vec, &expectedSize);CHKERRQ(ierr);
968 ierr = VecGetSize(temp_vec, &loadedSize);CHKERRQ(ierr);
969 if (loadedSize != expectedSize) {
970 SETERRQ(comm,PETSC_ERR_FILE_UNEXPECTED,
971 "File %s holds %d entries – expected %d for field '%s'",
972 filename, loadedSize, expectedSize, field_name);
973 }
974
975 // Now, safely copy the data from the temporary vector to the final destination.
976 ierr = VecCopy(temp_vec, field_vec);CHKERRQ(ierr);
977
978 // Clean up the temporary vector.
979 ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
980
981 // ---- END MODIFICATION ----
982
983 /* create EMPTY sequential Vec – VecLoad() will size it correctly */
984 /*
985 ierr = VecCreate(PETSC_COMM_SELF,&seq_vec);CHKERRQ(ierr);
986 ierr = VecSetType(seq_vec,VECSEQ);CHKERRQ(ierr);
987
988 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,
989 FILE_MODE_READ,&viewer);CHKERRQ(ierr);
990
991 ierr = VecLoad(field_vec,viewer);CHKERRQ(ierr);
992 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
993 */
995 "Loaded <%s> (serial path)\n",filename);
996
998 PetscFunctionReturn(0);
999 }
1000
1001 /* ======================================================================
1002 * 2. PARALLEL JOB
1003 * ==================================================================== */
1004 PetscInt globalSize;
1005 ierr = VecGetSize(field_vec,&globalSize);CHKERRQ(ierr);
1006
1007 DM dm = NULL;
1008 const char *dmtype = NULL;
1009 Vec nat = NULL; /* Natural-ordered vector for DMDA */
1010
1011 /* -------------------- rank-0 : read the sequential file -------------- */
1012 Vec seq_vec = NULL; /* only valid on rank-0 */
1013 const PetscScalar *seqArray = NULL; /* borrowed pointer on rank-0 only */
1014
1015 if(rank==0)
1016 {
1017 PetscViewer viewer;
1018 PetscBool found;
1019
1020 ierr = PetscTestFile(filename,'r',&found);CHKERRQ(ierr);
1021 if(!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,
1022 "Restart file not found: %s",filename);
1023
1024 /* create EMPTY sequential Vec – VecLoad() will size it correctly */
1025 ierr = VecCreate(PETSC_COMM_SELF,&seq_vec);CHKERRQ(ierr);
1026 ierr = VecSetType(seq_vec,VECSEQ);CHKERRQ(ierr);
1027
1028 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,
1029 FILE_MODE_READ,&viewer);CHKERRQ(ierr);
1030 ierr = VecLoad(seq_vec,viewer);CHKERRQ(ierr);
1031 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1032
1033 /* size sanity-check */
1034 PetscInt loaded;
1035 ierr = VecGetSize(seq_vec,&loaded);CHKERRQ(ierr);
1036 if(loaded != globalSize)
1037 SETERRQ(comm,PETSC_ERR_FILE_UNEXPECTED,
1038 "File %s holds %d entries – expected %d",
1039 filename,loaded,globalSize);
1040
1041 /* borrow array for later Bcast */
1042 ierr = VecGetArrayRead(seq_vec,&seqArray);CHKERRQ(ierr);
1043
1045 "Rank 0 successfully loaded <%s>\n",filename);
1046 }
1047
1048 /* -------------------- Check if this is a DMDA vector ----------------- */
1049 ierr = VecGetDM(field_vec, &dm); CHKERRQ(ierr);
1050 if (dm) { ierr = DMGetType(dm, &dmtype); CHKERRQ(ierr); }
1051
1052 if (dmtype && !strcmp(dmtype, DMDA)) {
1053 /* ==================================================================
1054 * DMDA PATH: File is in natural ordering, need to convert to global
1055 * ================================================================== */
1056
1057 /* Create natural vector */
1058 ierr = DMDACreateNaturalVector(dm, &nat); CHKERRQ(ierr);
1059
1060 /* Scatter from rank 0's seq_vec to all ranks' natural vector */
1061 VecScatter scatter;
1062 Vec nat_seq = NULL; /* Sequential natural vector on rank 0 */
1063
1064 ierr = VecScatterCreateToZero(nat, &scatter, &nat_seq); CHKERRQ(ierr);
1065
1066 /* Reverse scatter: from rank 0 to all ranks */
1067 ierr = VecScatterBegin(scatter, (rank == 0 ? seq_vec : nat_seq), nat,
1068 INSERT_VALUES, SCATTER_REVERSE); CHKERRQ(ierr);
1069 ierr = VecScatterEnd(scatter, (rank == 0 ? seq_vec : nat_seq), nat,
1070 INSERT_VALUES, SCATTER_REVERSE); CHKERRQ(ierr);
1071
1072 /* Convert natural → global ordering */
1073 ierr = DMDANaturalToGlobalBegin(dm, nat, INSERT_VALUES, field_vec); CHKERRQ(ierr);
1074 ierr = DMDANaturalToGlobalEnd(dm, nat, INSERT_VALUES, field_vec); CHKERRQ(ierr);
1075
1076 /* Cleanup */
1077 ierr = VecScatterDestroy(&scatter); CHKERRQ(ierr);
1078 ierr = VecDestroy(&nat_seq); CHKERRQ(ierr);
1079 ierr = VecDestroy(&nat); CHKERRQ(ierr);
1080
1081 } else {
1082 /* ==================================================================
1083 * NON-DMDA PATH: Use broadcast and direct copy (assumes global ordering)
1084 * ================================================================== */
1085
1086 PetscScalar *buffer = NULL;
1087 if (rank == 0) {
1088 buffer = (PetscScalar *)seqArray;
1089 } else {
1090 ierr = PetscMalloc1(globalSize, &buffer); CHKERRQ(ierr);
1091 }
1092
1093 ierr = MPI_Bcast(buffer, (int)globalSize, MPIU_SCALAR, 0, comm); CHKERRQ(ierr);
1094
1095 /* Copy slice based on ownership range */
1096 PetscInt rstart, rend, loc;
1097 PetscScalar *locArray;
1098
1099 ierr = VecGetOwnershipRange(field_vec, &rstart, &rend); CHKERRQ(ierr);
1100 loc = rend - rstart;
1101
1102 ierr = VecGetArray(field_vec, &locArray); CHKERRQ(ierr);
1103 ierr = PetscMemcpy(locArray, buffer + rstart, loc * sizeof(PetscScalar)); CHKERRQ(ierr);
1104 ierr = VecRestoreArray(field_vec, &locArray); CHKERRQ(ierr);
1105
1106 if (rank != 0) {
1107 ierr = PetscFree(buffer); CHKERRQ(ierr);
1108 }
1109 }
1110
1111 /* -------------------- tidy up ---------------------------------------- */
1112 if (rank == 0) {
1113 ierr = VecRestoreArrayRead(seq_vec, &seqArray); CHKERRQ(ierr);
1114 ierr = VecDestroy(&seq_vec); CHKERRQ(ierr);
1115 }
1116
1118 "Loaded <%s> (parallel path)\n",filename);
1119
1121 PetscFunctionReturn(0);
1122}
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:32
Here is the caller graph for this function:

◆ ReadStatisticalFields()

PetscErrorCode ReadStatisticalFields ( UserCtx user,
PetscInt  ti 
)

Reads statistical fields used for time-averaged simulations.

Reads statistical quantities such as velocity sums and pressure sums. Logs missing files and initializes fields to zero if files are unavailable.

Parameters
[in,out]userPointer to the UserCtx structure containing the simulation context.
[in]tiTimestep index used to construct statistics file names.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads statistical fields used for time-averaged simulations.

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

See also
ReadStatisticalFields()

Definition at line 1208 of file io.c.

1209{
1210 PetscErrorCode ierr;
1211 const char *eulerian_ext = "dat";
1212 if (user->simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR && user->simCtx->pps->eulerianExt[0] != '\0') {
1213 eulerian_ext = user->simCtx->pps->eulerianExt;
1214 }
1215
1216 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to read statistical fields.\n");
1217
1218 ierr = ReadOptionalField(user, "su0", "Velocity Sum", user->Ucat_sum, ti, eulerian_ext); CHKERRQ(ierr);
1219 ierr = ReadOptionalField(user, "su1", "Velocity Cross Sum", user->Ucat_cross_sum, ti, eulerian_ext); CHKERRQ(ierr);
1220 ierr = ReadOptionalField(user, "su2", "Velocity Square Sum",user->Ucat_square_sum, ti, eulerian_ext); CHKERRQ(ierr);
1221 ierr = ReadOptionalField(user, "sp", "Pressure Sum", user->P_sum, ti, eulerian_ext); CHKERRQ(ierr);
1222
1223 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished reading statistical fields.\n");
1224
1225 return 0;
1226}
Vec Ucat_square_sum
Definition variables.h:889
Vec P_sum
Definition variables.h:889
Vec Ucat_sum
Definition variables.h:889
Vec Ucat_cross_sum
Definition variables.h:889
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadLESFields()

PetscErrorCode ReadLESFields ( UserCtx user,
PetscInt  ti 
)

Reads LES-related fields used in turbulence modeling.

Reads the Smagorinsky constant (Cs) and transfers data to local vectors. Logs missing files and initializes fields to zero if files are unavailable.

Parameters
[in,out]userPointer to the UserCtx structure containing the simulation context.
[in]tiTime index for constructing the file name.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads LES-related fields used in turbulence modeling.

Local to this translation unit.

Definition at line 1232 of file io.c.

1233{
1234 PetscErrorCode ierr;
1235 const char *eulerian_ext = "dat";
1236 if (user->simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR && user->simCtx->pps->eulerianExt[0] != '\0') {
1237 eulerian_ext = user->simCtx->pps->eulerianExt;
1238 }
1239
1240 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to read LES fields.\n");
1241
1242 ierr = ReadOptionalField(user, "Nu_t", "Turbulent Viscosity", user->Nu_t, ti, eulerian_ext); CHKERRQ(ierr);
1243 ierr = ReadOptionalField(user, "cs", "Smagorinsky Constant (Cs)", user->CS, ti, eulerian_ext); CHKERRQ(ierr);
1244
1245 DMGlobalToLocalBegin(user->da, user->CS, INSERT_VALUES, user->lCs);
1246 DMGlobalToLocalEnd(user->da, user->CS, INSERT_VALUES, user->lCs);
1247
1248 DMGlobalToLocalBegin(user->da, user->Nu_t, INSERT_VALUES, user->lNu_t);
1249 DMGlobalToLocalEnd(user->da, user->Nu_t, INSERT_VALUES, user->lNu_t);
1250
1251 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished reading LES fields.\n");
1252
1253 return 0;
1254}
Vec lCs
Definition variables.h:886
Vec lNu_t
Definition variables.h:886
Vec Nu_t
Definition variables.h:886
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadRANSFields()

PetscErrorCode ReadRANSFields ( UserCtx user,
PetscInt  ti 
)

Reads RANS-related fields for turbulence modeling.

Reads K_Omega fields (used in RANS modeling) and initializes them if files are unavailable.

Parameters
[in,out]userPointer to the UserCtx structure containing the simulation context.
[in]tiTime index for constructing the file name.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Reads RANS-related fields for turbulence modeling.

Local to this translation unit.

Definition at line 1260 of file io.c.

1261{
1262 PetscErrorCode ierr;
1263 const char *eulerian_ext = "dat";
1264 if (user->simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR && user->simCtx->pps->eulerianExt[0] != '\0') {
1265 eulerian_ext = user->simCtx->pps->eulerianExt;
1266 }
1267
1268 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to read RANS fields.\n");
1269
1270 ierr = ReadOptionalField(user, "kfield", "K-Omega RANS", user->K_Omega, ti, eulerian_ext); CHKERRQ(ierr);
1271 ierr = ReadOptionalField(user, "Nu_t", "Turbulent Viscosity", user->Nu_t, ti, eulerian_ext); CHKERRQ(ierr);
1272
1273 VecCopy(user->K_Omega, user->K_Omega_o);
1274
1275 DMGlobalToLocalBegin(user->fda2, user->K_Omega, INSERT_VALUES, user->lK_Omega);
1276 DMGlobalToLocalEnd(user->fda2, user->K_Omega, INSERT_VALUES, user->lK_Omega);
1277
1278 DMGlobalToLocalBegin(user->da, user->Nu_t, INSERT_VALUES, user->lNu_t);
1279 DMGlobalToLocalEnd(user->da, user->Nu_t, INSERT_VALUES, user->lNu_t);
1280
1281 DMGlobalToLocalBegin(user->fda2, user->K_Omega_o, INSERT_VALUES, user->lK_Omega_o);
1282 DMGlobalToLocalEnd(user->fda2, user->K_Omega_o, INSERT_VALUES, user->lK_Omega_o);
1283
1284 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished reading RANS fields.\n");
1285
1286 return 0;
1287}
Vec K_Omega_o
Definition variables.h:886
Vec K_Omega
Definition variables.h:886
Vec lK_Omega_o
Definition variables.h:886
Vec lK_Omega
Definition variables.h:886
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteFieldData()

PetscErrorCode WriteFieldData ( UserCtx user,
const char *  field_name,
Vec  field_vec,
PetscInt  ti,
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]tiTime index for constructing the file name.
[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 1451 of file io.c.

1456{
1457 PetscErrorCode ierr;
1458 MPI_Comm comm;
1459 PetscMPIInt rank, size;
1460
1461 const PetscInt placeholder_int = 0; /* keep legacy name */
1462 char filename[PETSC_MAX_PATH_LEN];
1463 SimCtx *simCtx=user->simCtx;
1464
1465 PetscFunctionBeginUser;
1467
1468 if(!simCtx->current_io_directory){
1469 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "I/O context directory was not set before calling WriteFieldData().");
1470 }
1471
1472 /* ------------------------------------------------------------ */
1473 /* Basic communicator information */
1474 /* ------------------------------------------------------------ */
1475 ierr = PetscObjectGetComm((PetscObject)field_vec,&comm);CHKERRQ(ierr);
1476 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1477 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1478
1479 ierr = PetscSNPrintf(filename,sizeof(filename),
1480 "%s/%s%05" PetscInt_FMT "_%d.%s",
1481 simCtx->current_io_directory,field_name,ti,placeholder_int,ext);CHKERRQ(ierr);
1482
1484 " Preparing to write <%s> on rank %d/%d\n",
1485 filename,rank,size);
1486
1487 /* ------------------------------------------------------------ */
1488 /* 1. Serial path */
1489 /* ------------------------------------------------------------ */
1490 if (size == 1) {
1491 PetscViewer viewer;
1492
1493 ierr = PetscViewerBinaryOpen(comm,filename,
1494 FILE_MODE_WRITE,&viewer);CHKERRQ(ierr);
1495 ierr = VecView(field_vec,viewer);CHKERRQ(ierr);
1496 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1497
1499 " Wrote <%s> (serial path)\n",filename);
1500 PetscFunctionReturn(0);
1501 }
1502
1503 /* ------------------------------------------------------------ */
1504 /* 2. Parallel path */
1505 /* ------------------------------------------------------------ */
1506 VecScatter scatter;
1507 Vec seq_vec=NULL; /* created by PETSc, lives only on rank 0 */
1508 DM dm = NULL;
1509 const char *dmtype = NULL;
1510 Vec nat = NULL; /* Natural-ordered vector for DMDA */
1511
1512 /* 2.1 Check if vector has DMDA and convert to natural ordering if needed */
1513 ierr = VecGetDM(field_vec, &dm); CHKERRQ(ierr);
1514 if (dm) { ierr = DMGetType(dm, &dmtype); CHKERRQ(ierr); }
1515
1516 if (dmtype && !strcmp(dmtype, DMDA)) {
1517 /* DMDA path: convert to natural ordering first */
1518 ierr = DMDACreateNaturalVector(dm, &nat); CHKERRQ(ierr);
1519 ierr = DMDAGlobalToNaturalBegin(dm, field_vec, INSERT_VALUES, nat); CHKERRQ(ierr);
1520 ierr = DMDAGlobalToNaturalEnd(dm, field_vec, INSERT_VALUES, nat); CHKERRQ(ierr);
1521
1522 /* Gather the natural-ordered vector */
1523 ierr = VecScatterCreateToZero(nat, &scatter, &seq_vec); CHKERRQ(ierr);
1524 } else {
1525 /* Non-DMDA path: direct gather in global ordering */
1526 ierr = VecScatterCreateToZero(field_vec, &scatter, &seq_vec); CHKERRQ(ierr);
1527 }
1528
1529 /* 2.2 Gather distributed → sequential (on rank 0) */
1530 ierr = VecScatterBegin(scatter, (nat ? nat : field_vec), seq_vec,
1531 INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
1532 ierr = VecScatterEnd(scatter, (nat ? nat : field_vec), seq_vec,
1533 INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
1534
1535 /* 2.3 Rank 0 writes the file */
1536 if (rank == 0) {
1537 PetscViewer viewer;
1538
1539 /* (optional) value diagnostics */
1540 PetscReal vmin,vmax;
1541 ierr = VecMin(seq_vec,NULL,&vmin);CHKERRQ(ierr);
1542 ierr = VecMax(seq_vec,NULL,&vmax);CHKERRQ(ierr);
1544 " <%s> range = [%.4e … %.4e]\n",
1545 field_name,(double)vmin,(double)vmax);
1546
1547 ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,filename,
1548 FILE_MODE_WRITE,&viewer);CHKERRQ(ierr);
1549 ierr = VecView(seq_vec,viewer);CHKERRQ(ierr);
1550 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1551
1553 " Wrote <%s> (parallel path)\n",filename);
1554 }
1555
1556 /* 2.4 Cleanup */
1557 ierr = VecScatterDestroy(&scatter);CHKERRQ(ierr);
1558 ierr = VecDestroy(&seq_vec);CHKERRQ(ierr);
1559 if (nat) { ierr = VecDestroy(&nat); CHKERRQ(ierr); }
1560
1562 PetscFunctionReturn(0);
1563}
Here is the caller graph for this function:

◆ WriteSimulationFields()

PetscErrorCode WriteSimulationFields ( UserCtx user)

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, RANS, and statistical fields if they are enabled.

Parameters
[in]userPointer to the UserCtx structure containing simulation context.
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 1571 of file io.c.

1572{
1573 PetscErrorCode ierr;
1574
1575 SimCtx *simCtx = user->simCtx;
1576
1577 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to write simulation fields.\n");
1578
1579 // Set the current IO directory
1580 ierr = PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
1581 "%s/%s", simCtx->output_dir, simCtx->euler_subdir);CHKERRQ(ierr);
1582 simCtx->current_io_directory = simCtx->_io_context_buffer;
1583
1584 // Write contravariant velocity field
1585 ierr = WriteFieldData(user, "vfield", user->Ucont, simCtx->step, "dat"); CHKERRQ(ierr);
1586
1587 // Write Cartesian velocity field
1588 ierr = WriteFieldData(user, "ufield", user->Ucat, simCtx->step, "dat"); CHKERRQ(ierr);
1589
1590 // Write pressure field
1591 ierr = WriteFieldData(user, "pfield", user->P, simCtx->step, "dat"); CHKERRQ(ierr);
1592
1593 // Write node state field (nvert)
1594 ierr = WriteFieldData(user, "nvfield", user->Nvert, simCtx->step, "dat"); CHKERRQ(ierr);
1595
1596 // Write ParticleCountPerCell if enabled.
1597 if(simCtx->np>0){
1598 ierr = WriteFieldData(user, "ParticleCount",user->ParticleCount,simCtx->step,"dat"); CHKERRQ(ierr);
1599 ierr = WriteFieldData(user, "psifield", user->Psi, simCtx->step, "dat"); CHKERRQ(ierr);
1600 }
1601
1602 // Write LES fields if enabled
1603 if (simCtx->les) {
1604 ierr = WriteLESFields(user); CHKERRQ(ierr);
1605 }
1606
1607 // Write RANS fields if enabled
1608 if (simCtx->rans) {
1609 ierr = WriteRANSFields(user); CHKERRQ(ierr);
1610 }
1611
1612 // Write statistical fields if averaging is enabled
1613 if (simCtx->averaging) {
1614 ierr = WriteStatisticalFields(user); CHKERRQ(ierr);
1615 }
1616
1617 simCtx->current_io_directory = NULL;
1618
1619 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished writing simulation fields.\n");
1620
1621 return 0;
1622}
PetscErrorCode WriteStatisticalFields(UserCtx *user)
Implementation of WriteStatisticalFields().
Definition io.c:1630
PetscErrorCode WriteFieldData(UserCtx *user, const char *field_name, Vec field_vec, PetscInt ti, const char *ext)
Internal helper implementation: WriteFieldData().
Definition io.c:1451
PetscErrorCode WriteRANSFields(UserCtx *user)
Implementation of WriteRANSFields().
Definition io.c:1682
PetscErrorCode WriteLESFields(UserCtx *user)
Internal helper implementation: WriteLESFields().
Definition io.c:1652
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:673
PetscInt step
Definition variables.h:659
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteStatisticalFields()

PetscErrorCode WriteStatisticalFields ( UserCtx user)

Writes statistical fields for averaging purposes.

This function writes data for fields such as Ucat_sum, Ucat_cross_sum, Ucat_square_sum, and P_sum to their respective binary files.

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

Writes statistical fields for averaging purposes.

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

See also
WriteStatisticalFields()

Definition at line 1630 of file io.c.

1631{
1632 PetscErrorCode ierr;
1633
1634 SimCtx *simCtx = user->simCtx;
1635
1636 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to write statistical fields.\n");
1637
1638 ierr = WriteFieldData(user, "su0", user->Ucat_sum, simCtx->step, "dat"); CHKERRQ(ierr);
1639 ierr = WriteFieldData(user, "su1", user->Ucat_cross_sum, simCtx->step, "dat"); CHKERRQ(ierr);
1640 ierr = WriteFieldData(user, "su2", user->Ucat_square_sum, simCtx->step, "dat"); CHKERRQ(ierr);
1641 ierr = WriteFieldData(user, "sp", user->P_sum, simCtx->step, "dat"); CHKERRQ(ierr);
1642
1643 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished writing statistical fields.\n");
1644
1645 return 0;
1646}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteLESFields()

PetscErrorCode WriteLESFields ( UserCtx user)

Writes LES-related fields.

This function writes LES-related fields such as Cs (Smagorinsky constant) to their respective binary files.

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

Writes LES-related fields.

Local to this translation unit.

Definition at line 1652 of file io.c.

1653{
1654 PetscErrorCode ierr;
1655
1656 SimCtx *simCtx = user->simCtx;
1657
1658 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to write LES fields.\n");
1659
1660
1661 DMLocalToGlobalBegin(user->da, user->lCs, INSERT_VALUES, user->CS);
1662 DMLocalToGlobalEnd(user->da, user->lCs, INSERT_VALUES, user->CS);
1663
1664 DMLocalToGlobalBegin(user->da, user->lNu_t, INSERT_VALUES, user->Nu_t);
1665 DMLocalToGlobalEnd(user->da, user->lNu_t, INSERT_VALUES, user->Nu_t);
1666
1667 ierr = WriteFieldData(user, "Nu_t", user->Nu_t, simCtx->step, "dat"); CHKERRQ(ierr);
1668 ierr = WriteFieldData(user, "cs", user->CS, simCtx->step, "dat"); CHKERRQ(ierr);
1669
1670
1671 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished writing LES fields.\n");
1672
1673 return 0;
1674}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteRANSFields()

PetscErrorCode WriteRANSFields ( UserCtx user)

Writes RANS-related fields.

This function writes RANS-related fields such as K_Omega to their respective binary files.

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

Writes RANS-related fields.

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

See also
WriteRANSFields()

Definition at line 1682 of file io.c.

1683{
1684 PetscErrorCode ierr;
1685
1686 SimCtx *simCtx = user->simCtx;
1687
1688 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to write RANS fields.\n");
1689
1690 ierr = WriteFieldData(user, "kfield", user->K_Omega, simCtx->step, "dat"); CHKERRQ(ierr);
1691
1692 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished writing RANS fields.\n");
1693
1694 return 0;
1695}
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,
PetscInt  ti,
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]tiTime index used to construct the output file name.
[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 1703 of file io.c.

1704{
1705 PetscErrorCode ierr;
1706 Vec fieldVec;
1707 DM swarm;
1708
1709 PetscFunctionBeginUser; /* PETSc macro indicating start of function */
1710
1711 /*
1712 * 1) Retrieve the PetscSwarm from the user context.
1713 * Ensure user->swarm is initialized and not NULL.
1714 */
1715 swarm = user->swarm;
1716
1717 /*
1718 * 2) Create a global vector from the specified swarm field.
1719 * This function is available in PETSc 3.14.4.
1720 * It provides a read/write "view" of the swarm field as a global Vec.
1721 */
1723 "Attempting to create global vector from field: %s\n",
1724 field_name);
1725 ierr = DMSwarmCreateGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
1726
1727 /*
1728 * 3) Use your existing WriteFieldData() to write the global vector to a file.
1729 * The field name, time index, and extension are passed along for naming.
1730 */
1732 "Calling WriteFieldData for field: %s\n",
1733 field_name);
1734 ierr = WriteFieldData(user, field_name, fieldVec, ti, ext);CHKERRQ(ierr);
1735
1736 /*
1737 * 4) Destroy the global vector once the data is successfully written.
1738 * This step is crucial for avoiding memory leaks.
1739 * DMSwarmDestroyGlobalVectorFromField() is also available in PETSc 3.14.4.
1740 */
1742 "Destroying the global vector for field: %s\n",
1743 field_name);
1744 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
1745
1746 /* Log and return success. */
1748 "Successfully wrote swarm data for field: %s\n",
1749 field_name);
1750
1751 PetscFunctionReturn(0); /* PETSc macro indicating end of function */
1752}
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,
PetscInt  ti,
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]tiTime index used to construct the output file name.
[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 1758 of file io.c.

1759{
1760 PetscErrorCode ierr;
1761 DM swarm = user->swarm;
1762 Vec temp_vec; // Temporary Vec to hold casted data
1763 PetscInt nlocal, nglobal,bs,i;
1764 void *field_array_void;
1765 PetscScalar *scalar_array; // Pointer to the temporary Vec's scalar data
1766
1767 PetscFunctionBeginUser;
1768
1769 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Casting '%s' to Vec for writing.\n", field_name);
1770
1771 // Get the swarm field properties
1772 ierr = DMSwarmGetLocalSize(swarm, &nlocal); CHKERRQ(ierr);
1773 ierr = DMSwarmGetSize(swarm, &nglobal); CHKERRQ(ierr);
1774 ierr = DMSwarmGetField(swarm, field_name, &bs, NULL, &field_array_void); CHKERRQ(ierr);
1775
1776 // Create Temporary parallel Vec wit the CORRECT layout
1777 ierr = VecCreate(PETSC_COMM_WORLD, &temp_vec); CHKERRQ(ierr);
1778 ierr = VecSetType(temp_vec, VECMPI); CHKERRQ(ierr);
1779 ierr = VecSetSizes(temp_vec, nlocal*bs, nglobal*bs); CHKERRQ(ierr);
1780 ierr = VecSetUp(temp_vec); CHKERRQ(ierr);
1781
1782 // Defining Vector field to mandatory field 'position'
1783 DMSwarmVectorDefineField(swarm,"position");
1784
1785 ierr = VecGetArray(temp_vec, &scalar_array); CHKERRQ(ierr);
1786
1787 if(strcasecmp(field_name,"DMSwarm_pid") == 0){
1788 PetscInt64 *int64_array = (PetscInt64 *)field_array_void;
1789 // Perform the cast from PetscInt64 to PetscScalar
1790 for (i = 0; i < nlocal*bs; i++) {
1791 scalar_array[i] = (PetscScalar)int64_array[i];
1792 }
1793 }else{
1794 PetscInt *int_array = (PetscInt *)field_array_void;
1795 //Perform the cast from PetscInt to PetscScalar
1796 for (i = 0; i < nlocal*bs; i++) {
1797 scalar_array[i] = (PetscScalar)int_array[i];
1798 }
1799 }
1800
1801 // Restore access to both arrays
1802 ierr = VecRestoreArray(temp_vec, &scalar_array); CHKERRQ(ierr);
1803 ierr = DMSwarmRestoreField(swarm, field_name, &bs, NULL, &field_array_void); CHKERRQ(ierr);
1804
1805 // Call your existing writer with the temporary, populated Vec
1806 ierr = WriteFieldData(user, field_name, temp_vec, ti, ext); CHKERRQ(ierr);
1807
1808 // Clean up
1809 ierr = VecDestroy(&temp_vec); CHKERRQ(ierr);
1810
1811 PetscFunctionReturn(0);
1812}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteAllSwarmFields()

PetscErrorCode WriteAllSwarmFields ( UserCtx user)

Writes a predefined set of PETSc Swarm fields to files.

This function iterates through a hardcoded list of common swarm fields (position, velocity, etc.) and calls the WriteSwarmField() helper function for each one. This provides a straightforward way to output essential particle data at a given simulation step.

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.
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 1818 of file io.c.

1819{
1820 PetscErrorCode ierr;
1821 SimCtx *simCtx = user->simCtx;
1822
1823 PetscFunctionBeginUser;
1824
1825 // If no swarm is configured or there are no particles, do nothing and return.
1826 if (!user->swarm || simCtx->np <= 0) {
1827 PetscFunctionReturn(0);
1828 }
1829
1830 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting to write swarm fields.\n");
1831
1832 // Ensure the current IO directory is set
1833 ierr = PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
1834 "%s/%s", simCtx->output_dir, simCtx->particle_subdir);CHKERRQ(ierr);
1835 simCtx->current_io_directory = simCtx->_io_context_buffer;
1836
1837 // Write particle position field
1838 ierr = WriteSwarmField(user, "position", simCtx->step, "dat"); CHKERRQ(ierr);
1839
1840 // Write particle velocity field
1841 ierr = WriteSwarmField(user, "velocity", simCtx->step, "dat"); CHKERRQ(ierr);
1842
1843 // Write particle weight field
1844 ierr = WriteSwarmField(user, "weight", simCtx->step, "dat"); CHKERRQ(ierr);
1845
1846 // Write custom particle field "Psi"
1847 ierr = WriteSwarmField(user, "Psi", simCtx->step, "dat"); CHKERRQ(ierr);
1848
1849 // Integer fields require special handling
1850
1851 // Write the background mesh cell ID for each particle
1852 ierr = WriteSwarmIntField(user, "DMSwarm_CellID", simCtx->step, "dat"); CHKERRQ(ierr);
1853
1854 // Write the particle location status (e.g., inside or outside the domain)
1855 ierr = WriteSwarmIntField(user, "DMSwarm_location_status", simCtx->step, "dat"); CHKERRQ(ierr);
1856
1857 // Write the unique particle ID
1858 ierr = WriteSwarmIntField(user, "DMSwarm_pid", simCtx->step, "dat"); CHKERRQ(ierr);
1859
1860 simCtx->current_io_directory = NULL;
1861
1862 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished writing swarm fields.\n");
1863
1864 PetscFunctionReturn(0);
1865}
PetscErrorCode WriteSwarmField(UserCtx *user, const char *field_name, PetscInt ti, const char *ext)
Implementation of WriteSwarmField().
Definition io.c:1703
PetscErrorCode WriteSwarmIntField(UserCtx *user, const char *field_name, PetscInt ti, const char *ext)
Internal helper implementation: WriteSwarmIntField().
Definition io.c:1758
char particle_subdir[PETSC_MAX_PATH_LEN]
Definition variables.h:675
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 2414 of file io.c.

2418{
2419 /* STEP 0: Prepare local variables & log function entry */
2420 PetscMPIInt rank, size;
2421 PetscErrorCode ierr;
2422 FILE *fp = NULL;
2423 PetscInt N = 0; /* number of lines/values read on rank 0 */
2424 double *array = NULL; /* pointer to local array on each rank */
2425 PetscInt fileExistsFlag = 0; /* 0 = doesn't exist, 1 = does exist */
2426
2428 "Start reading from file: %s\n",
2429 filename);
2430
2431 /* Basic error checking: data_out, Nout must be non-null. */
2432 if (!filename || !data_out || !Nout) {
2434 "Null pointer argument provided.\n");
2435 return 1;
2436 }
2437
2438 /* Determine rank/size for coordinating I/O. */
2439 MPI_Comm_rank(comm, &rank);
2440 MPI_Comm_size(comm, &size);
2441
2442 /* STEP 1: On rank 0, check if file can be opened. */
2443 if (!rank) {
2444 fp = fopen(filename, "r");
2445 if (fp) {
2446 fileExistsFlag = 1;
2447 fclose(fp);
2448 }
2449 }
2450
2451 /* STEP 2: Broadcast file existence to all ranks. */
2452 // In ReadDataFileToArray:
2453 ierr = MPI_Bcast(&fileExistsFlag, 1, MPI_INT, 0, comm); CHKERRQ(ierr);
2454
2455 if (!fileExistsFlag) {
2456 /* If file does not exist, log & return. */
2457 if (!rank) {
2459 "File '%s' not found.\n",
2460 filename);
2461 }
2462 return 2;
2463 }
2464
2465 /* STEP 3: Rank 0 re-opens and reads the file, counting lines, etc. */
2466 if (!rank) {
2467 fp = fopen(filename, "r");
2468 if (!fp) {
2470 "File '%s' could not be opened for reading.\n",
2471 filename);
2472 return 3;
2473 }
2474
2475 /* (3a) Count lines first. */
2476 {
2477 char line[256];
2478 while (fgets(line, sizeof(line), fp)) {
2479 N++;
2480 }
2481 }
2482
2484 "File '%s' has %d lines.\n",
2485 filename, N);
2486
2487 /* (3b) Allocate array on rank 0. */
2488 array = (double*)malloc(N * sizeof(double));
2489 if (!array) {
2490 fclose(fp);
2492 "malloc failed for array.\n");
2493 return 4;
2494 }
2495
2496 /* (3c) Rewind & read values into array. */
2497 rewind(fp);
2498 {
2499 PetscInt i = 0;
2500 char line[256];
2501 while (fgets(line, sizeof(line), fp)) {
2502 double val;
2503 if (sscanf(line, "%lf", &val) == 1) {
2504 array[i++] = val;
2505 }
2506 }
2507 }
2508 fclose(fp);
2509
2511 "Successfully read %d values from '%s'.\n",
2512 N, filename);
2513 }
2514
2515 /* STEP 4: Broadcast the integer N to all ranks. */
2516 ierr = MPI_Bcast(&N, 1, MPI_INT, 0, comm); CHKERRQ(ierr);
2517
2518 /* STEP 5: Each rank allocates an array to receive the broadcast if rank>0. */
2519 if (rank) {
2520 array = (double*)malloc(N * sizeof(double));
2521 if (!array) {
2523 "malloc failed on rank %d.\n",
2524 rank);
2525 return 5;
2526 }
2527 }
2528
2529 /* STEP 6: Broadcast the actual data from rank 0 to all. */
2530 ierr = MPI_Bcast(array, N, MPI_DOUBLE, 0, comm); CHKERRQ(ierr);
2531
2532 /* STEP 7: Assign outputs on all ranks. */
2533 *data_out = array;
2534 *Nout = N;
2535
2537 "Done. Provided array of length=%d to all ranks.\n",
2538 N);
2539 return 0; /* success */
2540}

◆ 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 153 of file vtk_io.c.

154{
155 PetscMPIInt rank;
156 MPI_Comm_rank(comm, &rank);
157 PetscErrorCode ierr = 0;
158
159 if (!rank) {
160 char tmp_filename[PETSC_MAX_PATH_LEN];
161 FILE *fp = NULL;
162
163 ierr = PetscSNPrintf(tmp_filename, sizeof(tmp_filename), "%s.tmp", filename);CHKERRQ(ierr);
164 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank 0 writing combined VTK file '%s'.\n", filename);
165 fp = fopen(tmp_filename, "wb");
166 if (!fp) {
167 LOG_ALLOW(GLOBAL, LOG_ERROR, "fopen failed for %s.\n", tmp_filename);
168 return PETSC_ERR_FILE_OPEN;
169 }
170
171 PetscInt boffset = 0;
172
173 ierr = WriteVTKFileHeader(fp, meta, &boffset);
174 if (ierr) {
175 fclose(fp);
176 remove(tmp_filename);
177 return ierr;
178 }
179
180 if (meta->coords) {
181 ierr = WriteVTKAppendedBlock(fp, meta->coords, 3 * meta->npoints, sizeof(PetscScalar));
182 if (ierr) {
183 fclose(fp);
184 remove(tmp_filename);
185 return ierr;
186 }
187 }
188
189 for (PetscInt i = 0; i < meta->num_point_data_fields; i++) {
190 const VTKFieldInfo *field = &meta->point_data_fields[i];
191 if (field->data) {
192 ierr = WriteVTKAppendedBlock(fp, field->data, field->num_components * meta->npoints, sizeof(PetscScalar));
193 if (ierr) {
194 fclose(fp);
195 remove(tmp_filename);
196 return ierr;
197 }
198 }
199 }
200 if (meta->fileType == VTK_POLYDATA) {
201 if (meta->connectivity) {
202 ierr = WriteVTKAppendedBlock(fp, meta->connectivity, meta->npoints, sizeof(PetscInt));
203 if (ierr) {
204 fclose(fp);
205 remove(tmp_filename);
206 return ierr;
207 }
208 }
209 if (meta->offsets) {
210 ierr = WriteVTKAppendedBlock(fp, meta->offsets, meta->npoints, sizeof(PetscInt));
211 if (ierr) {
212 fclose(fp);
213 remove(tmp_filename);
214 return ierr;
215 }
216 }
217 }
218 ierr = WriteVTKFileFooter(fp, meta);
219 if (ierr) {
220 fclose(fp);
221 remove(tmp_filename);
222 return ierr;
223 }
224 if (fclose(fp) != 0) {
225 remove(tmp_filename);
226 return PETSC_ERR_FILE_WRITE;
227 }
228 if (rename(tmp_filename, filename) != 0) {
229 remove(tmp_filename);
230 return PETSC_ERR_FILE_WRITE;
231 }
232 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank 0 finished writing VTK file '%s'.\n", filename);
233 }
234 return 0;
235}
PetscInt npoints
Definition variables.h:612
PetscInt num_components
Definition variables.h:599
PetscInt num_point_data_fields
Definition variables.h:615
PetscInt * connectivity
Definition variables.h:616
PetscInt * offsets
Definition variables.h:617
VTKFileType fileType
Definition variables.h:610
PetscScalar * data
Definition variables.h:600
PetscScalar * coords
Definition variables.h:613
VTKFieldInfo point_data_fields[20]
Definition variables.h:614
@ VTK_POLYDATA
Definition variables.h:606
Stores all necessary information for a single data array in a VTK file.
Definition variables.h:597
static PetscErrorCode WriteVTKFileFooter(FILE *fp, const VTKMetaData *meta)
Internal helper implementation: WriteVTKFileFooter().
Definition vtk_io.c:136
static PetscErrorCode WriteVTKAppendedBlock(FILE *fp, const void *data, PetscInt num_elements, size_t element_size)
Internal helper implementation: WriteVTKAppendedBlock().
Definition vtk_io.c:21
static PetscErrorCode WriteVTKFileHeader(FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
Internal helper implementation: WriteVTKFileHeader().
Definition vtk_io.c:122
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 1871 of file io.c.

1872{
1873 PetscErrorCode ierr;
1874 MPI_Comm comm;
1875 PetscMPIInt rank;
1876 PetscInt globalSize;
1877 DM dm = NULL;
1878 const char *dmtype = NULL;
1879
1880 /* For DMDA path */
1881 Vec nat = NULL, seqNat = NULL;
1882 VecScatter scatNat = NULL;
1883 const PetscScalar *nar = NULL;
1884 PetscScalar *buf = NULL;
1885
1886 /* For generic (no DM) path */
1887 Vec seq = NULL;
1888 VecScatter scat = NULL;
1889 const PetscScalar *sar = NULL;
1890
1891 PetscFunctionBeginUser;
1892
1893 ierr = PetscObjectGetComm((PetscObject)inVec, &comm); CHKERRQ(ierr);
1894 ierr = MPI_Comm_rank(comm, &rank); CHKERRQ(ierr);
1895 ierr = VecGetSize(inVec, &globalSize); CHKERRQ(ierr);
1896 *N = globalSize;
1897 *arrayOut = NULL;
1898
1899 ierr = VecGetDM(inVec, &dm); CHKERRQ(ierr);
1900 if (dm) { ierr = DMGetType(dm, &dmtype); CHKERRQ(ierr); }
1901
1902 if (dmtype && !strcmp(dmtype, DMDA)) {
1903 /* --- DMDA path: go to NATURAL ordering, then gather to rank 0 --- */
1904 ierr = DMDACreateNaturalVector(dm, &nat); CHKERRQ(ierr);
1905 ierr = DMDAGlobalToNaturalBegin(dm, inVec, INSERT_VALUES, nat); CHKERRQ(ierr);
1906 ierr = DMDAGlobalToNaturalEnd (dm, inVec, INSERT_VALUES, nat); CHKERRQ(ierr);
1907
1908 ierr = VecScatterCreateToZero(nat, &scatNat, &seqNat); CHKERRQ(ierr);
1909 ierr = VecScatterBegin(scatNat, nat, seqNat, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
1910 ierr = VecScatterEnd (scatNat, nat, seqNat, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
1911
1912 if (rank == 0) {
1913 PetscInt nseq;
1914 ierr = VecGetLocalSize(seqNat, &nseq); CHKERRQ(ierr);
1915 ierr = VecGetArrayRead(seqNat, &nar); CHKERRQ(ierr);
1916
1917 ierr = PetscMalloc1(nseq, &buf); CHKERRQ(ierr);
1918 ierr = PetscMemcpy(buf, nar, (size_t)nseq * sizeof(PetscScalar)); CHKERRQ(ierr);
1919
1920 ierr = VecRestoreArrayRead(seqNat, &nar); CHKERRQ(ierr);
1921 *arrayOut = (double*)buf; /* hand back as double* to match the helper signature */
1922 }
1923
1924 ierr = VecScatterDestroy(&scatNat); CHKERRQ(ierr);
1925 ierr = VecDestroy(&seqNat); CHKERRQ(ierr);
1926 ierr = VecDestroy(&nat); CHKERRQ(ierr);
1927 } else {
1928 /* --- No DM attached: plain gather in Vec’s global (parallel) layout order --- */
1929 ierr = VecScatterCreateToZero(inVec, &scat, &seq); CHKERRQ(ierr);
1930 ierr = VecScatterBegin(scat, inVec, seq, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
1931 ierr = VecScatterEnd (scat, inVec, seq, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
1932
1933 if (rank == 0) {
1934 PetscInt nseq;
1935 ierr = VecGetLocalSize(seq, &nseq); CHKERRQ(ierr);
1936 ierr = VecGetArrayRead(seq, &sar); CHKERRQ(ierr);
1937
1938 ierr = PetscMalloc1(nseq, &buf); CHKERRQ(ierr);
1939 ierr = PetscMemcpy(buf, sar, (size_t)nseq * sizeof(PetscScalar)); CHKERRQ(ierr);
1940
1941 ierr = VecRestoreArrayRead(seq, &sar); CHKERRQ(ierr);
1942 *arrayOut = (double*)buf;
1943 }
1944
1945 ierr = VecScatterDestroy(&scat); CHKERRQ(ierr);
1946 ierr = VecDestroy(&seq); CHKERRQ(ierr);
1947 }
1948
1949 PetscFunctionReturn(0);
1950}
Here is the caller graph for this function:

◆ SwarmFieldToArrayOnRank0()

PetscErrorCode SwarmFieldToArrayOnRank0 ( DM  swarm,
const char *  field_name,
PetscInt *  n_total_particles,
PetscInt *  n_components,
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_particles(Output on rank 0) Total number of particles in the global swarm.
[out]n_components(Output on rank 0) Number of components for the field.
[out]gathered_array(Output on rank 0) A newly allocated array containing the full, gathered data. 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 1956 of file io.c.

1957{
1958 PetscErrorCode ierr;
1959 PetscMPIInt rank, size;
1960 PetscInt nlocal, nglobal, bs;
1961 void *local_array_void;
1962 size_t element_size = 0;
1963
1964 PetscFunctionBeginUser;
1965
1966 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1967 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
1968
1969 // All ranks get swarm properties to determine send/receive counts
1970 ierr = DMSwarmGetLocalSize(swarm, &nlocal); CHKERRQ(ierr);
1971 ierr = DMSwarmGetSize(swarm, &nglobal); CHKERRQ(ierr);
1972 ierr = DMSwarmGetField(swarm, field_name, &bs, NULL, &local_array_void); CHKERRQ(ierr);
1973
1974 // Determine the size of one element of the field's data type
1975 if (strcasecmp(field_name, "DMSwarm_pid") == 0) {
1976 element_size = sizeof(PetscInt64);
1977 } else if (strcasecmp(field_name, "DMSwarm_CellID") == 0 || strcasecmp(field_name, "DMSwarm_location_status") == 0) {
1978 element_size = sizeof(PetscInt);
1979 } else {
1980 element_size = sizeof(PetscScalar);
1981 }
1982
1983 if (rank == 0) {
1984 *n_total_particles = nglobal;
1985 *n_components = bs;
1986 *gathered_array = NULL; // Initialize output
1987 }
1988
1989 if (size == 1) { // Serial case is a simple copy
1990 if (rank == 0) {
1991 ierr = PetscMalloc(nglobal * bs * element_size, gathered_array); CHKERRQ(ierr);
1992 ierr = PetscMemcpy(*gathered_array, local_array_void, nglobal * bs * element_size); CHKERRQ(ierr);
1993 }
1994 } else { // Parallel case: use MPI_Gatherv
1995 PetscInt *recvcounts = NULL, *displs = NULL;
1996 if (rank == 0) {
1997 ierr = PetscMalloc1(size, &recvcounts); CHKERRQ(ierr);
1998 ierr = PetscMalloc1(size, &displs); CHKERRQ(ierr);
1999 }
2000 PetscInt sendcount = nlocal * bs;
2001
2002 // Gather the number of elements (not bytes) from each rank
2003 ierr = MPI_Gather(&sendcount, 1, MPIU_INT, recvcounts, 1, MPIU_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
2004
2005 if (rank == 0) {
2006 displs[0] = 0;
2007 // Convert counts and calculate displacements in terms of BYTES
2008 for (PetscMPIInt i = 0; i < size; i++) recvcounts[i] *= element_size;
2009 for (PetscMPIInt i = 1; i < size; i++) displs[i] = displs[i-1] + recvcounts[i-1];
2010
2011 ierr = PetscMalloc(nglobal * bs * element_size, gathered_array); CHKERRQ(ierr);
2012 }
2013
2014 // Use Gatherv with MPI_BYTE to handle any data type generically
2015 ierr = MPI_Gatherv(local_array_void, nlocal * bs * element_size, MPI_BYTE,
2016 *gathered_array, recvcounts, displs, MPI_BYTE,
2017 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
2018
2019 if (rank == 0) {
2020 ierr = PetscFree(recvcounts); CHKERRQ(ierr);
2021 ierr = PetscFree(displs); CHKERRQ(ierr);
2022 }
2023 }
2024
2025 ierr = DMSwarmRestoreField(swarm, field_name, &bs, NULL, &local_array_void); CHKERRQ(ierr);
2026
2027 PetscFunctionReturn(0);
2028}
Here is the caller graph for this function:

◆ ReadSwarmField()

PetscErrorCode ReadSwarmField ( UserCtx user,
const char *  field_name,
PetscInt  ti,
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]tiTime index used to construct the input file name.
[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 1294 of file io.c.

1295{
1296 PetscErrorCode ierr;
1297 DM swarm;
1298 Vec fieldVec;
1299
1300 PetscFunctionBegin;
1301
1302 swarm = user->swarm;
1303
1304 LOG_ALLOW(GLOBAL,LOG_DEBUG," ReadSwarmField Begins \n");
1305
1306 /* 2) Create a global vector that references the specified Swarm field. */
1307 ierr = DMSwarmCreateGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
1308
1309 LOG_ALLOW(GLOBAL,LOG_DEBUG," Vector created from Field \n");
1310
1311 /* 3) Use the ReadFieldData() function to read data into fieldVec. */
1312 ierr = ReadFieldData(user, field_name, fieldVec, ti, ext);CHKERRQ(ierr);
1313
1314 /* 4) Destroy the global vector reference. */
1315 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, field_name, &fieldVec);CHKERRQ(ierr);
1316
1317 PetscFunctionReturn(0);
1318}
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,
PetscInt  ti,
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]tiTime index for the input file.
[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 1324 of file io.c.

1325{
1326 PetscErrorCode ierr;
1327 DM swarm = user->swarm;
1328 Vec temp_vec;
1329 PetscInt nlocal, nglobal, bs, i;
1330 const PetscScalar *scalar_array; // Read-only pointer from the temp Vec
1331 void *field_array_void;
1332
1333
1334 PetscFunctionBeginUser;
1335
1336 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Reading '%s' via temporary Vec.\n", field_name);
1337
1338 // Get the properties of the swarm field to determine the expected layout
1339 ierr = DMSwarmGetLocalSize(swarm, &nlocal); CHKERRQ(ierr);
1340 ierr = DMSwarmGetSize(swarm, &nglobal); CHKERRQ(ierr);
1341 // We get the block size but not the data pointer yet
1342 ierr = DMSwarmGetField(swarm, field_name, &bs, NULL, NULL); CHKERRQ(ierr);
1343 ierr = DMSwarmRestoreField(swarm, field_name, &bs, NULL, NULL); CHKERRQ(ierr);
1344
1345 // Create a temporary Vec with the CORRECT layout to receive the data
1346 ierr = VecCreate(PETSC_COMM_WORLD, &temp_vec); CHKERRQ(ierr);
1347 ierr = VecSetType(temp_vec, VECMPI); CHKERRQ(ierr);
1348 ierr = VecSetSizes(temp_vec, nlocal * bs, nglobal * bs); CHKERRQ(ierr);
1349 ierr = VecSetBlockSize(temp_vec, bs); CHKERRQ(ierr);
1350 ierr = VecSetUp(temp_vec); CHKERRQ(ierr);
1351
1352 // Call your existing reader to populate the temporary Vec
1353 ierr = ReadFieldData(user, field_name, temp_vec, ti, ext); CHKERRQ(ierr);
1354
1355 // Get local pointers
1356 ierr = VecGetArrayRead(temp_vec, &scalar_array); CHKERRQ(ierr);
1357 ierr = DMSwarmGetField(swarm, field_name, NULL, NULL, &field_array_void); CHKERRQ(ierr);
1358
1359 // Perform the cast back, using the correct loop size (nlocal * bs)
1360 if (strcmp(field_name, "DMSwarm_pid") == 0) {
1361 PetscInt64 *int64_array = (PetscInt64 *)field_array_void;
1362 for (i = 0; i < nlocal * bs; i++) {
1363 int64_array[i] = (PetscInt64)scalar_array[i];
1364 }
1365 } else {
1366 PetscInt *int_array = (PetscInt *)field_array_void;
1367 for (i = 0; i < nlocal * bs; i++) {
1368 int_array[i] = (PetscInt)scalar_array[i];
1369 }
1370 }
1371
1372 // Restore access
1373 ierr = DMSwarmRestoreField(swarm, field_name, NULL, NULL, &field_array_void); CHKERRQ(ierr);
1374 ierr = VecRestoreArrayRead(temp_vec, &scalar_array); CHKERRQ(ierr);
1375
1376 // 6. Clean up
1377 ierr = VecDestroy(&temp_vec); CHKERRQ(ierr);
1378
1379 PetscFunctionReturn(0);
1380}
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 1386 of file io.c.

1387{
1388 PetscErrorCode ierr;
1389 PetscInt nGlobal;
1390 SimCtx *simCtx = user->simCtx;
1391 const char *source_path = NULL;
1392 const char *particle_ext = "dat";
1393
1394 PetscFunctionBeginUser;
1395 ierr = DMSwarmGetSize(user->swarm, &nGlobal); CHKERRQ(ierr);
1396 LOG_ALLOW(GLOBAL, LOG_INFO, "Reading DMSwarm fields for timestep %d (swarm size is %d).\n", ti, nGlobal);
1397
1398 if (nGlobal == 0) {
1399 LOG_ALLOW(GLOBAL, LOG_INFO, "Swarm is empty for timestep %d. Nothing to read.\n", ti);
1400 PetscFunctionReturn(0);
1401 }
1402
1403 // First, determine the top-level source directory based on the execution mode.
1404 if (simCtx->exec_mode == EXEC_MODE_SOLVER) {
1405 source_path = simCtx->restart_dir;
1406 } else if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
1407 source_path = simCtx->pps->source_dir;
1408 if (simCtx->pps->particleExt[0] != '\0') {
1409 particle_ext = simCtx->pps->particleExt;
1410 }
1411 } else {
1412 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "Invalid execution mode for reading simulation fields.");
1413 }
1414
1415 // Set the current I/O directory context
1416 ierr = PetscSNPrintf(simCtx->_io_context_buffer, sizeof(simCtx->_io_context_buffer),
1417 "%s/%s", source_path, simCtx->particle_subdir); CHKERRQ(ierr);
1418
1419 simCtx->current_io_directory = simCtx->_io_context_buffer;
1420
1421 /* 1) Read positions (REQUIRED) */
1422 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Reading mandatory position field...\n");
1423 ierr = ReadSwarmField(user, "position", ti, particle_ext);
1424 if (ierr) {
1425 SETERRQ(PETSC_COMM_WORLD, ierr, "Failed to read MANDATORY 'position' field for step %d. Cannot continue.", ti);
1426 }
1427 LOG_ALLOW(GLOBAL, LOG_INFO, "Successfully read mandatory position field for step %d.\n", ti);
1428
1429 /* 2) Read all OPTIONAL fields using the helper function. */
1430 /* The helper will print a warning and continue if a file is not found. */
1431 ierr = ReadOptionalSwarmField(user, "velocity", "Velocity", ti, particle_ext); CHKERRQ(ierr);
1432 ierr = ReadOptionalSwarmField(user, "DMSwarm_pid", "Particle ID", ti, particle_ext); CHKERRQ(ierr);
1433 ierr = ReadOptionalSwarmField(user, "DMSwarm_CellID", "Cell ID", ti, particle_ext); CHKERRQ(ierr);
1434 ierr = ReadOptionalSwarmField(user, "weight", "Particle Weight", ti, particle_ext); CHKERRQ(ierr);
1435 ierr = ReadOptionalSwarmField(user, "Psi", "Scalar Psi", ti, particle_ext); CHKERRQ(ierr);
1436 ierr = ReadOptionalSwarmField(user, "DMSwarm_location_status", "Migration Status", ti, particle_ext); CHKERRQ(ierr);
1437
1438 simCtx->current_io_directory = NULL; // Clear the I/O context after reading
1439
1440 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished reading DMSwarm fields for timestep %d.\n", ti);
1441 PetscFunctionReturn(0);
1442}
PetscErrorCode ReadSwarmField(UserCtx *user, const char *field_name, PetscInt ti, const char *ext)
Internal helper implementation: ReadSwarmField().
Definition io.c:1294
static PetscErrorCode ReadOptionalSwarmField(UserCtx *user, const char *field_name, const char *field_label, PetscInt ti, const char *ext)
Internal helper implementation: ReadOptionalSwarmField().
Definition io.c:859
char particleExt[8]
Definition variables.h:587
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 2546 of file io.c.

2550{
2551 PetscFunctionBeginUser;
2552
2553 PetscErrorCode ierr;
2554 Vec coordsVec;
2555
2556 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating coords Vec.\n");
2557 ierr = VecCreate(PETSC_COMM_WORLD, &coordsVec);CHKERRQ(ierr);
2558 ierr = VecSetFromOptions(coordsVec);CHKERRQ(ierr);
2559
2560 // For example: "position" is the name of the coordinate data
2561 ierr = ReadFieldData(user, "position", coordsVec, timeIndex, "dat");
2562 if (ierr) {
2564 "Error reading position data (ti=%d).\n",
2565 timeIndex);
2566 PetscFunctionReturn(ierr);
2567 }
2568
2569 LOG_ALLOW(GLOBAL, LOG_DEBUG, "ReadPositions - Gathering coords Vec to rank 0.\n");
2570 ierr = VecToArrayOnRank0(coordsVec, Ncoords, coordsArray);CHKERRQ(ierr);
2571
2572 ierr = VecDestroy(&coordsVec);CHKERRQ(ierr);
2573
2575 "Successfully gathered coordinates. Ncoords=%d.\n", *Ncoords);
2576 PetscFunctionReturn(0);
2577}
PetscErrorCode VecToArrayOnRank0(Vec inVec, PetscInt *N, double **arrayOut)
Internal helper implementation: VecToArrayOnRank0().
Definition io.c:1871
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 2584 of file io.c.

2589{
2590 PetscFunctionBeginUser;
2591
2592 PetscErrorCode ierr;
2593 Vec fieldVec;
2594
2595 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating field Vec.\n");
2596 ierr = VecCreate(PETSC_COMM_WORLD, &fieldVec);CHKERRQ(ierr);
2597 ierr = VecSetFromOptions(fieldVec);CHKERRQ(ierr);
2598
2599 ierr = ReadFieldData(user, fieldName, fieldVec, timeIndex, "dat");
2600 if (ierr) {
2602 "Error reading field '%s' (ti=%d).\n",
2603 fieldName, timeIndex);
2604 PetscFunctionReturn(ierr);
2605 }
2606
2607 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Gathering field Vec to rank 0.\n");
2608 ierr = VecToArrayOnRank0(fieldVec, Nscalars, scalarArray);CHKERRQ(ierr);
2609
2610 ierr = VecDestroy(&fieldVec);CHKERRQ(ierr);
2611
2613 "Successfully gathered field '%s'. Nscalars=%d.\n",
2614 fieldName, *Nscalars);
2615 PetscFunctionReturn(0);
2616}
Here is the call graph for this function:

◆ DisplayBanner()

PetscErrorCode DisplayBanner ( SimCtx simCtx)

Displays a structured banner summarizing the simulation configuration.

This function prints key simulation parameters to standard output. It is intended to be called ONLY by MPI rank 0. It retrieves global domain bounds and block metadata from simCtx.

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

Displays a structured banner summarizing the simulation configuration.

Local to this translation unit.

Definition at line 2034 of file io.c.

2035{
2036 PetscErrorCode ierr;
2037 PetscMPIInt rank;
2038 Cmpnts global_min_coords, global_max_coords;
2039 PetscReal StartTime;
2040 PetscInt StartStep,StepsToRun,total_num_particles;
2041 PetscMPIInt num_mpi_procs;
2042
2043 // SimCtx *simCtx = user->simCtx;
2044 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
2045 num_mpi_procs = simCtx->size;
2046 StartTime = simCtx->StartTime;
2047 StartStep = simCtx->StartStep;
2048 StepsToRun = simCtx->StepsToRun;
2049 total_num_particles = simCtx->np;
2050 BoundingBox *bboxlist_on_rank0 = simCtx->bboxlist;
2051
2052
2053 PetscFunctionBeginUser;
2054
2055 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "DisplayBanner - UserCtx pointer is NULL.");
2056 global_min_coords = user->bbox.min_coords;
2057 global_max_coords = user->bbox.max_coords;
2058 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2059
2060 if (rank == 0) {
2061 // If global_domain_bbox is not pre-populated in UserCtx, compute it here from bboxlist_on_rank0
2062 // This assumes bboxlist_on_rank0 is valid and contains all local bounding boxes on rank 0.
2063 if (bboxlist_on_rank0 && num_mpi_procs > 0) {
2064 global_min_coords = bboxlist_on_rank0[0].min_coords;
2065 global_max_coords = bboxlist_on_rank0[0].max_coords;
2066 for (PetscMPIInt p = 1; p < num_mpi_procs; ++p) {
2067 global_min_coords.x = PetscMin(global_min_coords.x, bboxlist_on_rank0[p].min_coords.x);
2068 global_min_coords.y = PetscMin(global_min_coords.y, bboxlist_on_rank0[p].min_coords.y);
2069 global_min_coords.z = PetscMin(global_min_coords.z, bboxlist_on_rank0[p].min_coords.z);
2070 global_max_coords.x = PetscMax(global_max_coords.x, bboxlist_on_rank0[p].max_coords.x);
2071 global_max_coords.y = PetscMax(global_max_coords.y, bboxlist_on_rank0[p].max_coords.y);
2072 global_max_coords.z = PetscMax(global_max_coords.z, bboxlist_on_rank0[p].max_coords.z);
2073 }
2074 // Optionally store this in user->global_domain_bbox if it's useful elsewhere
2075 // user->global_domain_bbox.min_coords = global_min_coords;
2076 // user->global_domain_bbox.max_coords = global_max_coords;
2077 } else {
2078 // Fallback or warning if bboxlist is not available for global calculation
2079 LOG_ALLOW(LOCAL, LOG_WARNING, "(Rank 0) - bboxlist not provided or num_mpi_procs <=0; using user->bbox for domain bounds.\n");
2080 // global_min_coords = user->bbox.min_coords; // Use local bbox of rank 0 as fallback
2081 // global_max_coords = user->bbox.max_coords;
2082 }
2083
2084 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); CHKERRQ(ierr);
2085 ierr = PetscPrintf(PETSC_COMM_SELF, "=============================================================\n"); CHKERRQ(ierr);
2086 ierr = PetscPrintf(PETSC_COMM_SELF, " CASE SUMMARY \n"); CHKERRQ(ierr);
2087 ierr = PetscPrintf(PETSC_COMM_SELF, "=============================================================\n"); CHKERRQ(ierr);
2088 ierr = PetscPrintf(PETSC_COMM_SELF, " Grid Points : %d X %d X %d\n", user->IM, user->JM, user->KM); CHKERRQ(ierr);
2089 ierr = PetscPrintf(PETSC_COMM_SELF, " Cells : %d X %d X %d\n", user->IM - 1, user->JM - 1, user->KM - 1); CHKERRQ(ierr);
2090 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);
2091 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);
2092 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);
2093 if(strcmp(simCtx->eulerianSource,"load")==0 || strcmp(simCtx->eulerianSource,"solve")==0){
2094 ierr = PetscPrintf(PETSC_COMM_SELF, "-------------------- Boundary Conditions --------------------\n"); CHKERRQ(ierr);
2095 const int face_name_width = 17; // Adjusted for longer names (Zeta,Eta,Xi)
2096 for (PetscInt i_face = 0; i_face < 6; ++i_face) {
2097 BCFace current_face = (BCFace)i_face;
2098 // The BCFaceToString will now return the Xi, Eta, Zeta versions
2099 const char* face_str = BCFaceToString(current_face);
2100 const char* bc_type_str = BCTypeToString(user->boundary_faces[current_face].mathematical_type);
2101 const char* bc_handler_type_str = BCHandlerTypeToString(user->boundary_faces[current_face].handler_type);
2102 if(user->boundary_faces[current_face].mathematical_type == INLET){
2104 Cmpnts inlet_velocity = {0.0,0.0,0.0};
2105 PetscBool found;
2106 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"vx",&inlet_velocity.x,&found); CHKERRQ(ierr);
2107 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"vy",&inlet_velocity.y,&found); CHKERRQ(ierr);
2108 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"vz",&inlet_velocity.z,&found); CHKERRQ(ierr);
2109 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - [%.4f,%.4f,%.4f]\n",
2110 face_name_width, face_str, bc_type_str, bc_handler_type_str,inlet_velocity.x,inlet_velocity.y,inlet_velocity.z); CHKERRQ(ierr);
2111 } else if(user->boundary_faces[current_face].handler_type == BC_HANDLER_INLET_PARABOLIC){
2112 PetscReal v_max = 0.0;
2113 PetscBool found;
2114 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"v_max",&v_max,&found); CHKERRQ(ierr);
2115 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - v_max=%.4f\n",
2116 face_name_width, face_str, bc_type_str, bc_handler_type_str, v_max); CHKERRQ(ierr);
2117 } else if(user->boundary_faces[current_face].handler_type == BC_HANDLER_INLET_PROFILE_FROM_FILE){
2118 const char *source_file = "(missing)";
2119 for (BC_Param *param = user->boundary_faces[current_face].params; param; param = param->next) {
2120 if (strcasecmp(param->key, "source_file") == 0 && param->value) {
2121 source_file = param->value;
2122 break;
2123 }
2124 }
2125 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - source_file=%s\n",
2126 face_name_width, face_str, bc_type_str, bc_handler_type_str, source_file); CHKERRQ(ierr);
2127 }
2129 PetscReal flux;
2130 PetscBool trimflag,foundflux,foundtrimflag;
2131 ierr = GetBCParamReal(user->boundary_faces[current_face].params,"target_flux",&flux,&foundflux); CHKERRQ(ierr);
2132 ierr = GetBCParamBool(user->boundary_faces[current_face].params,"apply_trim",&trimflag,&foundtrimflag); CHKERRQ(ierr);
2133 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s - [%.4f] - %s\n",
2134 face_name_width, face_str, bc_type_str, bc_handler_type_str,flux,trimflag?"Trim Ucont":"No Trim"); CHKERRQ(ierr);
2135 } else{
2136 ierr = PetscPrintf(PETSC_COMM_SELF, " Face %-*s : %s - %s\n",
2137 face_name_width, face_str, bc_type_str,bc_handler_type_str); CHKERRQ(ierr);
2138 }
2139 }
2140 }
2141 ierr = PetscPrintf(PETSC_COMM_SELF, "-------------------------------------------------------------\n"); CHKERRQ(ierr);
2142 ierr = PetscPrintf(PETSC_COMM_SELF, " Run Mode : %s\n", simCtx->OnlySetup ? "SETUP ONLY" : "Full Simulation"); CHKERRQ(ierr);
2143 ierr = PetscPrintf(PETSC_COMM_SELF, " Start Time : %.4f\n", (double)StartTime); CHKERRQ(ierr);
2144 ierr = PetscPrintf(PETSC_COMM_SELF, " Timestep Size : %.4f\n", (double)simCtx->dt); CHKERRQ(ierr);
2145 ierr = PetscPrintf(PETSC_COMM_SELF, " Starting Step : %d\n", StartStep); CHKERRQ(ierr);
2146 ierr = PetscPrintf(PETSC_COMM_SELF, " Total Steps to Run : %d\n", StepsToRun); CHKERRQ(ierr);
2147 ierr = PetscPrintf(PETSC_COMM_SELF, " Ending Step : %d\n", StartStep + StepsToRun); CHKERRQ(ierr);
2148 if (simCtx->tiout > 0) {
2149 ierr = PetscPrintf(PETSC_COMM_SELF, " Field/Restart Cadence : every %d step(s)\n", simCtx->tiout); CHKERRQ(ierr);
2150 } else {
2151 ierr = PetscPrintf(PETSC_COMM_SELF, " Field/Restart Cadence : DISABLED\n"); CHKERRQ(ierr);
2152 }
2153 ierr = PetscPrintf(PETSC_COMM_SELF, " Immersed Boundary : %s\n", simCtx->immersed ? "ENABLED" : "DISABLED"); CHKERRQ(ierr);
2154 if (simCtx->walltimeGuardEnabled) {
2155 ierr = PetscPrintf(
2156 PETSC_COMM_SELF,
2157 " Runtime Walltime Guard : %s (warmup=%d, multiplier=%.2f, min=%.1f s, alpha=%.2f)\n",
2158 simCtx->walltimeGuardActive ? "ENABLED" : "CONFIGURED BUT INACTIVE",
2159 simCtx->walltimeGuardWarmupSteps,
2160 (double)simCtx->walltimeGuardMultiplier,
2161 (double)simCtx->walltimeGuardMinSeconds,
2162 (double)simCtx->walltimeGuardEstimatorAlpha
2163 ); CHKERRQ(ierr);
2164 } else {
2165 ierr = PetscPrintf(PETSC_COMM_SELF, " Runtime Walltime Guard : DISABLED\n"); CHKERRQ(ierr);
2166 }
2167 ierr = PetscPrintf(PETSC_COMM_SELF, " Number of MPI Processes : %d\n", num_mpi_procs); CHKERRQ(ierr);
2168 ierr = PetscPrintf(PETSC_COMM_WORLD," Number of Particles : %d\n", total_num_particles); CHKERRQ(ierr);
2169 if (simCtx->np > 0) {
2170 const char *particle_init_str = ParticleInitializationToString(simCtx->ParticleInitialization);
2171
2172 if (simCtx->particleConsoleOutputFreq > 0) {
2173 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Console Cadence : every %d step(s)\n", simCtx->particleConsoleOutputFreq); CHKERRQ(ierr);
2174 } else {
2175 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Console Cadence : DISABLED\n"); CHKERRQ(ierr);
2176 }
2177 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Log Row Sampling : every %d particle(s)\n", simCtx->LoggingFrequency); CHKERRQ(ierr);
2178 if (simCtx->StartStep > 0) {
2179 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Restart Mode : %s\n", simCtx->particleRestartMode); CHKERRQ(ierr);
2180 }
2181 ierr = PetscPrintf(PETSC_COMM_SELF, " Particle Initialization Mode: %s\n", particle_init_str); CHKERRQ(ierr);
2182 ierr = PetscPrintf(PETSC_COMM_SELF, " Interpolation Method : %s\n",
2183 simCtx->interpolationMethod == INTERP_TRILINEAR ? "Trilinear (direct cell-center)" : "CornerAveraged (legacy)"); CHKERRQ(ierr);
2186 if (user->inletFaceDefined) {
2187 ierr = PetscPrintf(PETSC_COMM_SELF, " Particles Initialized At : %s (Enum Val: %d)\n", BCFaceToString(user->identifiedInletBCFace), user->identifiedInletBCFace); CHKERRQ(ierr);
2188 } else {
2189 ierr = PetscPrintf(PETSC_COMM_SELF, " Particles Initialized At : --- (No INLET face identified)\n"); CHKERRQ(ierr);
2190 }
2191 }
2192 }
2193 if(strcmp(simCtx->eulerianSource,"solve")==0 || strcmp(simCtx->eulerianSource,"load")==0){
2194 const char* field_init_str = FieldInitializationToString(simCtx->FieldInitialization);
2195 ierr = PetscPrintf(PETSC_COMM_WORLD," Reynolds Number : %le\n", simCtx->ren); CHKERRQ(ierr);
2196 //ierr = PetscPrintf(PETSC_COMM_WORLD," Von-Neumann Number : %le\n", simCtx->vnn); CHKERRQ(ierr);
2197 if(strcmp(simCtx->eulerianSource,"solve")==0){
2198 //ierr = PetscPrintf(PETSC_COMM_WORLD," Stanton Number : %le\n", simCtx->st); CHKERRQ(ierr);
2199 ierr = PetscPrintf(PETSC_COMM_WORLD," Momentum Equation Solver : %s\n", MomentumSolverTypeToString(simCtx->mom_solver_type)); CHKERRQ(ierr);
2200 ierr = PetscPrintf(PETSC_COMM_WORLD," Initial Pseudo-CFL : %le\n", simCtx->pseudo_cfl); CHKERRQ(ierr);
2201 ierr = PetscPrintf(PETSC_COMM_WORLD," Large Eddy Simulation Model : %s\n", LESModelToString(simCtx->les)); CHKERRQ(ierr);
2202 }
2203 ierr = PetscPrintf(PETSC_COMM_SELF, " Field Initialization Mode : %s\n", field_init_str); CHKERRQ(ierr);
2204 if (simCtx->FieldInitialization == 1) {
2205 ierr = PetscPrintf(PETSC_COMM_SELF, " Constant Velocity : x - %.4f, y - %.4f, z - %.4f \n", (double)simCtx->InitialConstantContra.x,(double)simCtx->InitialConstantContra.y,(double)simCtx->InitialConstantContra.z ); CHKERRQ(ierr);
2206 }
2207 } else if(strcmp(simCtx->eulerianSource,"analytical")==0){
2208 ierr = PetscPrintf(PETSC_COMM_WORLD," Analytical Solution Type : %s\n", simCtx->AnalyticalSolutionType); CHKERRQ(ierr);
2209 }
2210 ierr = PetscPrintf(PETSC_COMM_SELF, "=============================================================\n"); CHKERRQ(ierr);
2211 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); CHKERRQ(ierr);
2212 }
2213 PetscFunctionReturn(0);
2214}
PetscErrorCode GetBCParamReal(BC_Param *params, const char *key, PetscReal *value_out, PetscBool *found)
Internal helper implementation: GetBCParamReal().
Definition io.c:390
PetscErrorCode GetBCParamBool(BC_Param *params, const char *key, PetscBool *value_out, PetscBool *found)
Internal helper implementation: GetBCParamBool().
Definition io.c:411
const char * BCHandlerTypeToString(BCHandlerType handler_type)
Converts a BCHandlerType enum to its string representation.
Definition logging.c:771
const char * FieldInitializationToString(PetscInt FieldInitialization)
Helper function to convert FieldInitialization to a string representation.
Definition logging.c:687
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
Definition logging.c:669
const char * BCTypeToString(BCType type)
Helper function to convert BCType enum to a string representation.
Definition logging.c:751
const char * LESModelToString(LESModelType LESFlag)
Helper function to convert LES Flag to a string representation.
Definition logging.c:720
const char * MomentumSolverTypeToString(MomentumSolverType SolverFlag)
Helper function to convert Momentum Solver flag to a string representation.
Definition logging.c:736
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Helper function to convert ParticleInitialization to a string representation.
Definition logging.c:703
@ INLET
Definition variables.h:258
UserCtx * user
Definition variables.h:536
PetscBool inletFaceDefined
Definition variables.h:849
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:848
BCFace identifiedInletBCFace
Definition variables.h:850
PetscBool walltimeGuardActive
Definition variables.h:796
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:517
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:520
PetscReal StartTime
Definition variables.h:665
UserMG usermg
Definition variables.h:778
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:277
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:276
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:286
@ BC_HANDLER_INLET_PROFILE_FROM_FILE
Definition variables.h:278
PetscInt FieldInitialization
Definition variables.h:704
PetscReal ren
Definition variables.h:699
BCHandlerType handler_type
Definition variables.h:337
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:156
PetscReal dt
Definition variables.h:666
PetscInt StepsToRun
Definition variables.h:662
PetscInt StartStep
Definition variables.h:661
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:155
PetscBool OnlySetup
Definition variables.h:667
PetscScalar x
Definition variables.h:101
InterpolationMethod interpolationMethod
Definition variables.h:758
char particleRestartMode[16]
Definition variables.h:759
BoundingBox * bboxlist
Definition variables.h:756
BC_Param * params
Definition variables.h:338
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:671
PetscBool walltimeGuardEnabled
Definition variables.h:795
ParticleInitializationType ParticleInitialization
Definition variables.h:757
PetscScalar z
Definition variables.h:101
@ INTERP_TRILINEAR
Definition variables.h:530
PetscInt mglevels
Definition variables.h:543
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:684
PetscInt particleConsoleOutputFreq
Definition variables.h:664
Cmpnts InitialConstantContra
Definition variables.h:705
PetscScalar y
Definition variables.h:101
PetscMPIInt size
Definition variables.h:655
MGCtx * mgctx
Definition variables.h:546
BCType mathematical_type
Definition variables.h:336
BoundingBox bbox
Definition variables.h:841
MomentumSolverType mom_solver_type
Definition variables.h:691
PetscInt immersed
Definition variables.h:681
PetscReal pseudo_cfl
Definition variables.h:699
PetscInt LoggingFrequency
Definition variables.h:783
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:244
A node in a linked list for storing key-value parameters from the bcs.dat file.
Definition variables.h:304
Defines a 3D axis-aligned bounding box.
Definition variables.h:154
A 3D point or vector with PetscScalar components.
Definition variables.h:100
User-defined context containing data specific to a single computational grid level.
Definition variables.h:830
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 317 of file io.c.

317 {
318 if (strcasecmp(str, "-Xi") == 0) *face_out = BC_FACE_NEG_X;
319 else if (strcasecmp(str, "+Xi") == 0) *face_out = BC_FACE_POS_X;
320 else if (strcasecmp(str, "-Eta") == 0) *face_out = BC_FACE_NEG_Y;
321 else if (strcasecmp(str, "+Eta") == 0) *face_out = BC_FACE_POS_Y;
322 else if (strcasecmp(str, "-Zeta") == 0) *face_out = BC_FACE_NEG_Z;
323 else if (strcasecmp(str, "+Zeta") == 0) *face_out = BC_FACE_POS_Z;
324 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown face specifier: %s", str);
325 return 0;
326}
@ BC_FACE_NEG_X
Definition variables.h:245
@ BC_FACE_POS_Z
Definition variables.h:247
@ BC_FACE_POS_Y
Definition variables.h:246
@ BC_FACE_NEG_Z
Definition variables.h:247
@ BC_FACE_POS_X
Definition variables.h:245
@ BC_FACE_NEG_Y
Definition variables.h:246
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 332 of file io.c.

332 {
333 if (strcasecmp(str, "WALL") == 0) *type_out = WALL;
334 else if (strcasecmp(str, "SYMMETRY") == 0) *type_out = SYMMETRY;
335 else if (strcasecmp(str, "INLET") == 0) *type_out = INLET;
336 else if (strcasecmp(str, "OUTLET") == 0) *type_out = OUTLET;
337 else if (strcasecmp(str, "PERIODIC") == 0) *type_out = PERIODIC;
338 // ... add other BCTypes here ...
339 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown BC Type string: %s", str);
340 return 0;
341}
@ SYMMETRY
Definition variables.h:256
@ OUTLET
Definition variables.h:257
@ PERIODIC
Definition variables.h:260
@ WALL
Definition variables.h:254
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 347 of file io.c.

347 {
348 if (strcasecmp(str, "noslip") == 0) *handler_out = BC_HANDLER_WALL_NOSLIP;
349 else if (strcasecmp(str, "constant_velocity") == 0) *handler_out = BC_HANDLER_INLET_CONSTANT_VELOCITY;
350 else if (strcasecmp(str, "conservation") == 0) *handler_out = BC_HANDLER_OUTLET_CONSERVATION;
351 else if (strcasecmp(str, "parabolic") == 0) *handler_out = BC_HANDLER_INLET_PARABOLIC;
352 else if (strcasecmp(str, "prescribed_flow") == 0) *handler_out = BC_HANDLER_INLET_PROFILE_FROM_FILE;
353 else if (strcasecmp(str,"geometric") == 0) *handler_out = BC_HANDLER_PERIODIC_GEOMETRIC;
354 else if (strcasecmp(str,"constant_flux") == 0) *handler_out = BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX;
355 else if (strcasecmp(str,"initial_flux") == 0) *handler_out = BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX;
356 // ... add other BCHandlerTypes here ...
357 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown BC Handler string: %s", str);
358 return 0;
359}
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:284
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:287
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:273
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:282
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 365 of file io.c.

365 {
366 switch (type) {
367 case OUTLET:
368 if(handler != BC_HANDLER_OUTLET_CONSERVATION) return PETSC_ERR_ARG_WRONG;
369 break;
370 case WALL:
371 if (handler != BC_HANDLER_WALL_NOSLIP && handler != BC_HANDLER_WALL_MOVING) return PETSC_ERR_ARG_WRONG;
372 break;
373 case INLET:
374 if (handler != BC_HANDLER_INLET_CONSTANT_VELOCITY &&
375 handler != BC_HANDLER_INLET_PARABOLIC &&
376 handler != BC_HANDLER_INLET_PROFILE_FROM_FILE) return PETSC_ERR_ARG_WRONG;
377 break;
378 case PERIODIC:
379 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;
380 // ... add other validation cases here ...
381 default: break;
382 }
383 return 0; // Combination is valid
384}
@ BC_HANDLER_WALL_MOVING
Definition variables.h:274
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 302 of file io.c.

302 {
303 BC_Param *current = head;
304 while (current != NULL) {
305 BC_Param *next = current->next;
306 PetscFree(current->key);
307 PetscFree(current->value);
308 PetscFree(current);
309 current = next;
310 }
311}
struct BC_Param_s * next
Definition variables.h:307
char * key
Definition variables.h:305
char * value
Definition variables.h:306
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 390 of file io.c.

390 {
391 *found = PETSC_FALSE;
392 *value_out = 0.0;
393 if (!key) return 0; // No key to search for
394
395 BC_Param *current = params;
396 while (current) {
397 if (strcasecmp(current->key, key) == 0) {
398 *value_out = atof(current->value);
399 *found = PETSC_TRUE;
400 return 0; // Found it, we're done
401 }
402 current = current->next;
403 }
404 return 0; // It's not an error to not find the key.
405}
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 411 of file io.c.

411 {
412 *found = PETSC_FALSE;
413 *value_out = PETSC_FALSE;
414 if (!key) return 0; // No key to search for
415
416 BC_Param *current = params;
417 while (current) {
418 if (strcasecmp(current->key, key) == 0) {
419 // Key was found.
420 *found = PETSC_TRUE;
421
422 // Check the value string. Default to FALSE if the value is NULL or doesn't match a "true" string.
423 if (current->value &&
424 (strcasecmp(current->value, "true") == 0 ||
425 strcmp(current->value, "1") == 0 ||
426 strcasecmp(current->value, "yes") == 0))
427 {
428 *value_out = PETSC_TRUE;
429 } else {
430 *value_out = PETSC_FALSE;
431 }
432 return 0; // Found it, we're done
433 }
434 current = current->next;
435 }
436 return 0; // It's not an error to not find the key.
437}
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 450 of file io.c.

451{
452 PetscErrorCode ierr;
453 PetscMPIInt rank;
454
455 // Temporary storage for rank 0 to build the configuration before broadcasting.
456 BoundaryFaceConfig configs_rank0[6];
457
458 PetscFunctionBeginUser;
460 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
461
462 if (rank == 0) {
463 FILE *file;
464 char line_buffer[1024];
465
466 // Initialize the temporary config array with safe defaults on rank 0.
467 for (int i = 0; i < 6; i++) {
468 configs_rank0[i].face_id = (BCFace)i;
469 configs_rank0[i].mathematical_type = WALL;
470 configs_rank0[i].handler_type = BC_HANDLER_WALL_NOSLIP;
471 configs_rank0[i].params = NULL;
472 configs_rank0[i].handler = NULL; // Handler object is not created here.
473 }
474
475 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing BC configuration from '%s' on rank 0... \n", bcs_input_filename);
476 file = fopen(bcs_input_filename, "r");
477 if (!file) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Could not open BCs file '%s'.", bcs_input_filename);
478
479 while (fgets(line_buffer, sizeof(line_buffer), file)) {
480 char *current_pos = line_buffer;
481 while (isspace((unsigned char)*current_pos)) current_pos++; // Skip leading whitespace
482 if (*current_pos == '#' || *current_pos == '\0' || *current_pos == '\n' || *current_pos == '\r') continue;
483
484 char *face_str = strtok(current_pos, " \t\n\r");
485 char *type_str = strtok(NULL, " \t\n\r");
486 char *handler_str = strtok(NULL, " \t\n\r");
487
488 if (!face_str || !type_str || !handler_str) {
489 LOG_ALLOW(GLOBAL, LOG_WARNING, "Malformed line in bcs.dat, skipping: %s \n", line_buffer);
490 continue;
491 }
492
493 BCFace face_enum;
494 BCType type_enum;
495 BCHandlerType handler_enum;
496 const char* handler_name_for_log;
497
498 // --- Convert strings to enums and validate ---
499 ierr = StringToBCFace(face_str, &face_enum); CHKERRQ(ierr);
500 ierr = StringToBCType(type_str, &type_enum); CHKERRQ(ierr);
501 ierr = StringToBCHandlerType(handler_str, &handler_enum); CHKERRQ(ierr);
502 ierr = ValidateBCHandlerForBCType(type_enum, handler_enum);
503 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);
504
505 // Store the core types for the corresponding face
506 configs_rank0[face_enum].mathematical_type = type_enum;
507 configs_rank0[face_enum].handler_type = handler_enum;
508 handler_name_for_log = BCHandlerTypeToString(handler_enum); // Assumes this utility exists
509 LOG_ALLOW(GLOBAL, LOG_DEBUG, " Parsed Face '%s': Type=%s, Handler=%s \n", face_str, type_str, handler_name_for_log);
510
511 // --- Parse optional key=value parameters for this face ---
512 FreeBC_ParamList(configs_rank0[face_enum].params); // Clear any previous (default) params
513 configs_rank0[face_enum].params = NULL;
514 BC_Param **param_next_ptr = &configs_rank0[face_enum].params; // Pointer to the 'next' pointer to build the list
515
516 char* token;
517 while ((token = strtok(NULL, " \t\n\r")) != NULL) {
518 char* equals_ptr = strchr(token, '=');
519 if (!equals_ptr) {
520 LOG_ALLOW(GLOBAL, LOG_WARNING, "Malformed parameter '%s' on face '%s', skipping. \n", token, face_str);
521 continue;
522 }
523
524 *equals_ptr = '\0'; // Temporarily split the string at '=' to separate key and value
525 char* key_str = token;
526 char* value_str = equals_ptr + 1;
527
528 BC_Param *new_param;
529 ierr = PetscMalloc1(1, &new_param); CHKERRQ(ierr);
530 ierr = PetscStrallocpy(key_str, &new_param->key); CHKERRQ(ierr);
531 ierr = PetscStrallocpy(value_str, &new_param->value); CHKERRQ(ierr);
532 new_param->next = NULL;
533
534 *param_next_ptr = new_param;
535 param_next_ptr = &new_param->next;
536 LOG_ALLOW(GLOBAL, LOG_TRACE, " - Found param: [%s] = [%s] \n", new_param->key, new_param->value);
537 }
538 }
539 fclose(file);
540 }
541
542 // =========================================================================
543 // BROADCASTING THE CONFIGURATION FROM RANK 0
544 // =========================================================================
545 // This is a critical step to ensure all processes have the same configuration.
546
547 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "Rank %d broadcasting/receiving BC configuration.\n", rank);
548
549 for (int i = 0; i < 6; i++) {
550 // --- Broadcast simple enums ---
551 if (rank == 0) {
552 user->boundary_faces[i] = configs_rank0[i]; // Rank 0 populates its final struct
553 }
554 ierr = MPI_Bcast(&user->boundary_faces[i].mathematical_type, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
555 ierr = MPI_Bcast(&user->boundary_faces[i].handler_type, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
556
557 // --- Serialize and Broadcast the parameter linked list ---
558 PetscInt n_params = 0;
559 if (rank == 0) { // On rank 0, count the number of parameters to send
560 for (BC_Param *p = user->boundary_faces[i].params; p; p = p->next) n_params++;
561 }
562 ierr = MPI_Bcast(&n_params, 1, MPI_INT, 0, PETSC_COMM_WORLD);CHKERRQ(ierr);
563
564 if (rank != 0) { // Non-root ranks need to receive and build the list
565 FreeBC_ParamList(user->boundary_faces[i].params); // Ensure list is empty before building
566 user->boundary_faces[i].params = NULL;
567 }
568
569 BC_Param **param_next_ptr = &user->boundary_faces[i].params;
570
571 for (int j = 0; j < n_params; j++) {
572 char key_buf[256] = {0}, val_buf[256] = {0};
573 if (rank == 0) {
574 // On rank 0, navigate to the j-th param and copy its data to buffers
575 BC_Param *p = user->boundary_faces[i].params;
576 for (int k = 0; k < j; k++) p = p->next;
577 strncpy(key_buf, p->key, 255);
578 strncpy(val_buf, p->value, 255);
579 }
580
581 ierr = MPI_Bcast(key_buf, 256, MPI_CHAR, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
582 ierr = MPI_Bcast(val_buf, 256, MPI_CHAR, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
583
584 if (rank != 0) {
585 // On non-root ranks, deserialize: create a new node and append it
586 BC_Param *new_param;
587 ierr = PetscMalloc1(1, &new_param); CHKERRQ(ierr);
588 ierr = PetscStrallocpy(key_buf, &new_param->key); CHKERRQ(ierr);
589 ierr = PetscStrallocpy(val_buf, &new_param->value); CHKERRQ(ierr);
590 new_param->next = NULL;
591 *param_next_ptr = new_param;
592 param_next_ptr = &new_param->next;
593 } else {
594 // On rank 0, just advance the pointer for the next iteration
595 param_next_ptr = &((*param_next_ptr)->next);
596 }
597 }
598 user->boundary_faces[i].face_id = (BCFace)i; // Ensure face_id is set on all ranks
599 }
600
601 // --- Set particle inlet lookup fields used by the particle system ---
602 user->inletFaceDefined = PETSC_FALSE;
603 for (int i=0; i<6; i++) {
604
605 if (user->boundary_faces[i].mathematical_type == INLET && !user->inletFaceDefined) {
606 user->inletFaceDefined = PETSC_TRUE;
607 user->identifiedInletBCFace = (BCFace)i;
608 LOG_ALLOW(GLOBAL, LOG_INFO, "Inlet face for particle initialization identified as Face %d.\n", i);
609 break; // Found the first one, stop looking
610 }
611 }
612
613
614 if (rank == 0) {
615 // Rank 0 can now free the linked lists it created for the temporary storage.
616 // As written, user->boundary_faces was populated directly on rank 0, so no extra free is needed.
617 // for(int i=0; i<6; i++) FreeBC_ParamList(configs_rank0[i].params); // This would be needed if we used configs_rank0 exclusively
618 }
619
621 PetscFunctionReturn(0);
622}
PetscErrorCode StringToBCHandlerType(const char *str, BCHandlerType *handler_out)
Internal helper implementation: StringToBCHandlerType().
Definition io.c:347
PetscErrorCode ValidateBCHandlerForBCType(BCType type, BCHandlerType handler)
Internal helper implementation: ValidateBCHandlerForBCType().
Definition io.c:365
PetscErrorCode StringToBCFace(const char *str, BCFace *face_out)
Internal helper implementation: StringToBCFace().
Definition io.c:317
void FreeBC_ParamList(BC_Param *head)
Implementation of FreeBC_ParamList().
Definition io.c:302
PetscErrorCode StringToBCType(const char *str, BCType *type_out)
Internal helper implementation: StringToBCType().
Definition io.c:332
BCType
Defines the general mathematical/physical Category of a boundary.
Definition variables.h:251
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:271
BoundaryCondition * handler
Definition variables.h:339
Holds the complete configuration for one of the six boundary faces.
Definition variables.h:334
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 637 of file io.c.

638{
639 PetscErrorCode ierr;
640 PetscMPIInt rank;
641 PetscInt periodic_flags[3] = {0, 0, 0}; // Index 0:I, 1:J, 2:K
642
643 PetscFunctionBeginUser;
644 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
645
646 // --- Part 1: Collectively verify all BCS files exist before proceeding ---
647 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
648 const char *bcs_filename = simCtx->bcs_files[bi];
649 if (!bcs_filename) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL, "BCS filename for block %d is not set in SimCtx.", bi);
650 char desc_buf[256];
651 PetscBool file_exists;
652 snprintf(desc_buf, sizeof(desc_buf), "BCS file for block %d", bi);
653 ierr = VerifyPathExistence(bcs_filename, PETSC_FALSE, PETSC_FALSE, desc_buf, &file_exists); CHKERRQ(ierr);
654 }
655
656 // --- Part 2: Rank 0 does the parsing, since we know all files exist ---
657 if (rank == 0) {
658 PetscBool global_is_periodic[3] = {PETSC_FALSE, PETSC_FALSE, PETSC_FALSE};
659 PetscBool is_set = PETSC_FALSE;
660
661 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
662 const char *bcs_filename = simCtx->bcs_files[bi];
663 FILE *file = fopen(bcs_filename, "r");
664
665 PetscBool face_is_periodic[6] = {PETSC_FALSE};
666 char line_buffer[1024];
667
668 while (fgets(line_buffer, sizeof(line_buffer), file)) {
669 char *current_pos = line_buffer;
670 while (isspace((unsigned char)*current_pos)) current_pos++;
671 if (*current_pos == '#' || *current_pos == '\0' || *current_pos == '\n') continue;
672
673 // --- Tokenize the line exactly like the main parser ---
674 char *face_str = strtok(current_pos, " \t\n\r");
675 char *type_str = strtok(NULL, " \t\n\r");
676
677 // If the line doesn't have at least two tokens, we can't determine the type.
678 if (!face_str || !type_str) continue;
679
680 // --- Perform a direct, non-erroring check on the mathematical type string ---
681 if (strcasecmp(type_str, "PERIODIC") == 0) {
682 BCFace face_enum;
683 // A malformed face string on a periodic line IS a fatal error.
684 ierr = StringToBCFace(face_str, &face_enum); CHKERRQ(ierr);
685 face_is_periodic[face_enum] = PETSC_TRUE;
686 }
687 // Any other type_str (e.g., "WALL", "INLET") is correctly and silently ignored.
688 }
689 fclose(file);
690
691 // --- Validate consistency within this file ---
692 if (face_is_periodic[BC_FACE_NEG_X] != face_is_periodic[BC_FACE_POS_X])
693 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);
694 if (face_is_periodic[BC_FACE_NEG_Y] != face_is_periodic[BC_FACE_POS_Y])
695 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);
696 if (face_is_periodic[BC_FACE_NEG_Z] != face_is_periodic[BC_FACE_POS_Z])
697 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);
698
699 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]};
700
701 // --- Validate consistency across block files ---
702 if (!is_set) {
703 global_is_periodic[0] = local_is_periodic[0];
704 global_is_periodic[1] = local_is_periodic[1];
705 global_is_periodic[2] = local_is_periodic[2];
706 is_set = PETSC_TRUE;
707 } else {
708 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]) {
709 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
710 "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).",
711 (int)global_is_periodic[0], (int)global_is_periodic[1], (int)global_is_periodic[2],
712 bi, bcs_filename,
713 (int)local_is_periodic[0], (int)local_is_periodic[1], (int)local_is_periodic[2]);
714 }
715 }
716 } // end loop over blocks
717
718 periodic_flags[0] = (global_is_periodic[0]) ? 1 : 0;
719 periodic_flags[1] = (global_is_periodic[1]) ? 1 : 0;
720 periodic_flags[2] = (global_is_periodic[2]) ? 1 : 0;
721
722 LOG_ALLOW(GLOBAL, LOG_INFO, "Global periodicity determined: I-periodic=%d, J-periodic=%d, K-periodic=%d\n",
723 periodic_flags[0], periodic_flags[1], periodic_flags[2]);
724 }
725
726 // --- Part 3: Broadcast the final flags from rank 0 to all other ranks ---
727 ierr = MPI_Bcast(periodic_flags, 3, MPIU_INT, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
728
729 // --- All ranks now update their SimCtx ---
730 simCtx->i_periodic = periodic_flags[0];
731 simCtx->j_periodic = periodic_flags[1];
732 simCtx->k_periodic = periodic_flags[2];
733
734 PetscFunctionReturn(0);
735}
PetscErrorCode VerifyPathExistence(const char *path, PetscBool is_dir, PetscBool is_optional, const char *description, PetscBool *exists)
Internal helper implementation: VerifyPathExistence().
Definition io.c:741
char ** bcs_files
Definition variables.h:734
PetscInt k_periodic
Definition variables.h:727
PetscInt i_periodic
Definition variables.h:727
PetscInt j_periodic
Definition variables.h:727
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TrimWhitespace()

void TrimWhitespace ( char *  str)

Helper function to trim leading/trailing whitespace from a string.

Parameters
strThe string to trim in-place.

Helper function to trim leading/trailing whitespace from a string.

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

See also
TrimWhitespace()

Definition at line 38 of file io.c.

38 {
39 if (!str) return;
40
41 char *start = str;
42 // Find the first non-whitespace character
43 while (isspace((unsigned char)*start)) {
44 start++;
45 }
46
47 // Find the end of the string
48 char *end = str + strlen(str) - 1;
49 // Move backwards from the end to find the last non-whitespace character
50 while (end > start && isspace((unsigned char)*end)) {
51 end--;
52 }
53
54 // Null-terminate after the last non-whitespace character
55 *(end + 1) = '\0';
56
57 // If there was leading whitespace, shift the string to the left
58 if (str != start) {
59 memmove(str, start, (end - start) + 2); // +2 to include the new null terminator
60 }
61}
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 2222 of file io.c.

2223{
2224 FILE *file;
2225 char line[1024];
2226 PetscBool startTimeSet, endTimeSet, timeStepSet;
2227
2228 PetscFunctionBeginUser;
2230
2231 if (!simCtx || !simCtx->pps) {
2232 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL, "SimCtx or its pps member is NULL in ParsePostProcessingSettings.");
2233 }
2234
2235 char *configFile = simCtx->PostprocessingControlFile;
2236 PostProcessParams *pps = simCtx->pps;
2237
2238
2239 // --- 1. Set Sane Defaults First ---
2240 pps->startTime = 0;
2241 pps->endTime = 0;
2242 pps->timeStep = 1;
2243 pps->outputParticles = PETSC_FALSE;
2244 pps->particle_output_freq = simCtx->LoggingFrequency; // Default to logging frequency;
2245 strcpy(pps->process_pipeline, "");
2246 strcpy(pps->output_fields_instantaneous, "Ucat,P");
2247 strcpy(pps->output_fields_averaged, "");
2248 strcpy(pps->output_prefix, "Field");
2249 strcpy(pps->particle_output_prefix,"Particle");
2250 strcpy(pps->particle_fields,"velocity,CellID,weight,pid");
2251 strcpy(pps->particle_pipeline,"");
2252 strncpy(pps->statistics_pipeline, "", MAX_PIPELINE_LENGTH - 1);
2253 strncpy(pps->statistics_output_prefix, "Stats", MAX_FILENAME_LENGTH - 1);
2254 strcpy(pps->particleExt,"dat"); // The input file format for particles.
2255 strcpy(pps->eulerianExt,"dat"); // The input file format for Eulerian fields.
2256 pps->reference[0] = pps->reference[1] = pps->reference[2] = 1;
2257 strncpy(pps->source_dir, simCtx->output_dir, sizeof(pps->source_dir) - 1);
2258 pps->source_dir[sizeof(pps->source_dir) - 1] = '\0'; // Ensure null-termination
2259
2260 // --- 2. Parse the Configuration File (overrides defaults) ---
2261 file = fopen(configFile, "r");
2262 if (file) {
2263 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing post-processing config file: %s\n", configFile);
2264 while (fgets(line, sizeof(line), file)) {
2265 char *key, *value, *comment;
2266 comment = strchr(line, '#'); if (comment) *comment = '\0';
2267 TrimWhitespace(line); if (strlen(line) == 0) continue;
2268 key = strtok(line, "="); value = strtok(NULL, "=");
2269 if (key && value) {
2270 TrimWhitespace(key); TrimWhitespace(value);
2271 if (strcmp(key, "startTime") == 0) pps->startTime = atoi(value);
2272 else if (strcmp(key, "endTime") == 0) pps->endTime = atoi(value);
2273 else if (strcmp(key, "timeStep") == 0) pps->timeStep = atoi(value);
2274 else if (strcmp(key, "output_particles") == 0) {
2275 if (strcasecmp(value, "true") == 0) pps->outputParticles = PETSC_TRUE;
2276 }
2277 else if (strcasecmp(key, "process_pipeline") == 0) {
2278 strncpy(pps->process_pipeline, value, MAX_PIPELINE_LENGTH - 1);
2279 pps->process_pipeline[MAX_PIPELINE_LENGTH - 1] = '\0'; // Ensure null-termination
2280 } else if (strcasecmp(key, "output_fields_instantaneous") == 0) {
2281 strncpy(pps->output_fields_instantaneous, value, MAX_FIELD_LIST_LENGTH - 1);
2283 } else if (strcasecmp(key, "output_fields_averaged") == 0) {
2284 strncpy(pps->output_fields_averaged, value, MAX_FIELD_LIST_LENGTH - 1);
2286 } else if (strcasecmp(key, "output_prefix") == 0) {
2287 strncpy(pps->output_prefix, value, MAX_FILENAME_LENGTH - 1);
2288 pps->output_prefix[MAX_FILENAME_LENGTH - 1] = '\0';
2289 } else if (strcasecmp(key, "particle_output_prefix") == 0) {
2290 strncpy(pps->particle_output_prefix, value, MAX_FILENAME_LENGTH - 1);
2292 } else if (strcasecmp(key, "particle_fields_instantaneous") == 0) {
2293 strncpy(pps->particle_fields, value, MAX_FIELD_LIST_LENGTH - 1);
2294 pps->particle_fields[MAX_FIELD_LIST_LENGTH - 1] = '\0';
2295 } else if (strcasecmp(key, "particle_pipeline") == 0) {
2296 strncpy(pps->particle_pipeline, value, MAX_PIPELINE_LENGTH - 1);
2297 pps->particle_pipeline[MAX_PIPELINE_LENGTH - 1] = '\0';
2298 } else if (strcasecmp(key, "particle_output_freq") == 0) {
2299 pps->particle_output_freq = atoi(value);
2300 } else if (strcasecmp(key, "statistics_pipeline") == 0) {
2301 strncpy(pps->statistics_pipeline, value, MAX_PIPELINE_LENGTH - 1);
2303 } else if (strcasecmp(key, "statistics_output_prefix") == 0) {
2304 strncpy(pps->statistics_output_prefix, value, MAX_FILENAME_LENGTH - 1);
2306 } else if (strcasecmp(key, "particleExt") == 0) {
2307 strncpy(pps->particleExt, value, sizeof(pps->particleExt) - 1);
2308 pps->particleExt[sizeof(pps->particleExt) - 1] = '\0';
2309 } else if (strcasecmp(key, "eulerianExt") == 0) {
2310 strncpy(pps->eulerianExt, value, sizeof(pps->eulerianExt) - 1);
2311 pps->eulerianExt[sizeof(pps->eulerianExt) - 1] = '\0';
2312 } else if (strcmp(key, "reference_ip") == 0) {pps->reference[0] = atoi(value);
2313 } else if (strcmp(key, "reference_jp") == 0) {pps->reference[1] = atoi(value);
2314 } else if (strcmp(key, "reference_kp") == 0) {pps->reference[2] = atoi(value);
2315 } else if (strcasecmp(key, "source_directory") == 0) {
2316 strncpy(pps->source_dir, value, sizeof(pps->source_dir) - 1);
2317 pps->source_dir[sizeof(pps->source_dir) - 1] = '\0';
2318 } else {
2319 LOG_ALLOW(GLOBAL, LOG_WARNING, "Unknown key '%s' in post-processing config file. Ignoring.\n", key);
2320 }
2321 // Add parsing for pipeline, fields, etc. in later phases
2322 }
2323 }
2324 fclose(file);
2325 } else {
2326 LOG_ALLOW(GLOBAL, LOG_WARNING, "Could not open post-processing config file '%s'. Using defaults and command-line overrides.\n", configFile);
2327 }
2328
2329 // --- 3. Parse Command-Line Options (overrides file settings and defaults) ---
2330 PetscOptionsGetInt(NULL, NULL, "-startTime", &pps->startTime, &startTimeSet);
2331 PetscOptionsGetInt(NULL, NULL, "-endTime", &pps->endTime, &endTimeSet);
2332 PetscOptionsGetInt(NULL, NULL, "-timeStep", &pps->timeStep, &timeStepSet);
2333 PetscOptionsGetBool(NULL, NULL, "-output_particles", &pps->outputParticles, NULL);
2334
2335 if(pps->endTime==-1){
2336 pps->endTime = simCtx->StartStep + simCtx->StepsToRun; // Total steps if endTime is set to -1.
2337 }
2338
2339 // If only startTime is given on command line, run for a single step
2340 if (startTimeSet && !endTimeSet) {
2341 pps->endTime = pps->startTime;
2342 }
2343
2344 LOG_ALLOW(GLOBAL, LOG_INFO, "Post-processing configured to run from t=%d to t=%d with step %d. Particle output: %s.\n",
2345 pps->startTime, pps->endTime, pps->timeStep, pps->outputParticles ? "TRUE" : "FALSE");
2346
2347 LOG_ALLOW(GLOBAL, LOG_INFO, "Process Pipeline: %s\n", pps->process_pipeline);
2348 LOG_ALLOW(GLOBAL, LOG_INFO, "Instantaneous Output Fields: %s\n", pps->output_fields_instantaneous);
2349 LOG_ALLOW(GLOBAL, LOG_INFO, "Output Prefix: %s\n", pps->output_prefix);
2350 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Output Prefix: %s\n", pps->particle_output_prefix);
2351 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Fields: %s\n", pps->particle_fields);
2352 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Pipeline: %s\n", pps->particle_pipeline);
2353 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Output Frequency: %d\n", pps->particle_output_freq);
2354 LOG_ALLOW(GLOBAL, LOG_INFO, "Averaged Output Fields (reserved): %s\n", pps->output_fields_averaged);
2355 LOG_ALLOW(GLOBAL, LOG_INFO, "Post input extensions: Eulerian='.%s', Particle='.%s'\n", pps->eulerianExt, pps->particleExt);
2356
2358 PetscFunctionReturn(0);
2359}
void TrimWhitespace(char *str)
Implementation of TrimWhitespace().
Definition io.c:38
char statistics_output_prefix[256]
basename for CSV output, e.g.
Definition variables.h:583
char particle_output_prefix[256]
Definition variables.h:578
char output_prefix[256]
Definition variables.h:575
#define MAX_FIELD_LIST_LENGTH
Definition variables.h:552
char output_fields_averaged[1024]
Definition variables.h:574
#define MAX_PIPELINE_LENGTH
Definition variables.h:551
PetscInt reference[3]
Definition variables.h:590
PetscInt timeStep
Definition variables.h:568
#define MAX_FILENAME_LENGTH
Definition variables.h:553
char statistics_pipeline[1024]
e.g.
Definition variables.h:582
char output_fields_instantaneous[1024]
Definition variables.h:573
char particle_pipeline[1024]
Definition variables.h:576
char process_pipeline[1024]
Definition variables.h:572
PetscInt particle_output_freq
Definition variables.h:579
char particle_fields[1024]
Definition variables.h:577
PetscBool outputParticles
Definition variables.h:569
PetscInt startTime
Definition variables.h:566
char PostprocessingControlFile[PETSC_MAX_PATH_LEN]
Definition variables.h:816
Holds all configuration parameters for a post-processing run.
Definition variables.h:561
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 2370 of file io.c.

2371{
2372 PetscErrorCode ierr;
2373 PetscBool flg;
2374
2375 PetscFunctionBeginUser;
2377
2378 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx is NULL in ParseScalingInformation");
2379
2380 // --- 1. Set default values to 1.0 ---
2381 // This represents a purely non-dimensional run if no scaling is provided.
2382 simCtx->scaling.L_ref = 1.0;
2383 simCtx->scaling.U_ref = 1.0;
2384 simCtx->scaling.rho_ref = 1.0;
2385
2386 // --- 2. Read overrides from the command line / control file ---
2387 ierr = PetscOptionsGetReal(NULL, NULL, "-scaling_L_ref", &simCtx->scaling.L_ref, &flg); CHKERRQ(ierr);
2388 ierr = PetscOptionsGetReal(NULL, NULL, "-scaling_U_ref", &simCtx->scaling.U_ref, &flg); CHKERRQ(ierr);
2389 ierr = PetscOptionsGetReal(NULL, NULL, "-scaling_rho_ref", &simCtx->scaling.rho_ref, &flg); CHKERRQ(ierr);
2390
2391 // --- 3. Calculate derived scaling factors ---
2392 // Check for division by zero to be safe, though U_ref should be positive.
2393 if (simCtx->scaling.U_ref <= 0.0) {
2394 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Reference velocity U_ref must be positive. Got %g", (double)simCtx->scaling.U_ref);
2395 }
2396 simCtx->scaling.P_ref = simCtx->scaling.rho_ref * simCtx->scaling.U_ref * simCtx->scaling.U_ref;
2397
2398 // --- 4. Log the final, effective scales for verification ---
2399 LOG(GLOBAL, LOG_INFO, "---------------- Physical Scales Initialized -----------------\n");
2400 LOG(GLOBAL, LOG_INFO, " L_ref: %.4f, U_ref: %.4f, rho_ref: %.4f, P_ref: %.4f\n",
2401 simCtx->scaling.L_ref, simCtx->scaling.U_ref, simCtx->scaling.rho_ref, simCtx->scaling.P_ref);
2402 LOG(GLOBAL, LOG_INFO, "--------------------------------------------------------------\n");
2403
2405 PetscFunctionReturn(0);
2406}
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:83
PetscReal L_ref
Definition variables.h:633
ScalingCtx scaling
Definition variables.h:721
PetscReal P_ref
Definition variables.h:636
PetscReal rho_ref
Definition variables.h:635
PetscReal U_ref
Definition variables.h:634
Here is the caller graph for this function: