PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Macros | Functions
setup.h File Reference
#include <petscpf.h>
#include <petscdmswarm.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <petsctime.h>
#include <petscsys.h>
#include <petscdmcomposite.h>
#include <petscsystypes.h>
#include "variables.h"
#include "ParticleSwarm.h"
#include "walkingsearch.h"
#include "grid.h"
#include "logging.h"
#include "io.h"
#include "interpolation.h"
#include "ParticleMotion.h"
#include "Boundaries.h"
Include dependency graph for setup.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define Allocate3DArray(array, nz, ny, nx)
 
#define Deallocate3DArray(array, nz, ny)
 

Functions

PetscErrorCode CreateSimulationContext (int argc, char **argv, SimCtx **p_simCtx)
 Allocates and populates the master SimulationContext object.
 
PetscBool RuntimeWalltimeGuardParsePositiveSeconds (const char *text, PetscReal *seconds_out)
 Parse a positive floating-point seconds value from runtime metadata.
 
PetscErrorCode SetupSimulationEnvironment (SimCtx *simCtx)
 Verifies and prepares the complete I/O environment for a simulation run.
 
PetscErrorCode SetupGridAndSolvers (SimCtx *simCtx)
 The main orchestrator for setting up all grid-related components.
 
PetscErrorCode CreateAndInitializeAllVectors (SimCtx *simCtx)
 Creates and initializes all PETSc Vec objects for all fields.
 
PetscErrorCode UpdateLocalGhosts (UserCtx *user, const char *fieldName)
 Updates the local vector (including ghost points) from its corresponding global vector.
 
PetscErrorCode SetupBoundaryConditions (SimCtx *simCtx)
 (Orchestrator) Sets up all boundary conditions for the simulation.
 
PetscErrorCode InitializeSolutionConvergenceState (SimCtx *simCtx)
 Allocates any runtime storage required by solution-convergence logging.
 
PetscErrorCode DestroySolutionConvergenceState (SimCtx *simCtx)
 Frees any runtime storage allocated for solution-convergence logging.
 
PetscErrorCode Allocate3DArrayScalar (PetscReal ****array, PetscInt nz, PetscInt ny, PetscInt nx)
 Allocates a 3D array of PetscReal values using PetscCalloc.
 
PetscErrorCode Deallocate3DArrayScalar (PetscReal ***array, PetscInt nz, PetscInt ny)
 Deallocates a 3D array of PetscReal values allocated by Allocate3DArrayScalar.
 
PetscErrorCode Allocate3DArrayVector (Cmpnts ****array, PetscInt nz, PetscInt ny, PetscInt nx)
 Allocates a contiguous 3D array of Cmpnts values.
 
PetscErrorCode Deallocate3DArrayVector (Cmpnts ***array, PetscInt nz, PetscInt ny)
 Deallocates a 3D array of Cmpnts structures allocated by Allocate3DArrayVector.
 
PetscErrorCode GetOwnedCellRange (const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global_out, PetscInt *xm_cell_local_out)
 Determines the global starting index and number of CELLS owned by the current processor in a specified dimension.
 
PetscErrorCode ComputeAndStoreNeighborRanks (UserCtx *user)
 Computes and stores the Cartesian neighbor ranks for the DMDA decomposition.
 
PetscErrorCode SetDMDAProcLayout (DM dm, UserCtx *user)
 Sets the processor layout for a given DMDA based on PETSc options.
 
PetscErrorCode SetupDomainRankInfo (SimCtx *simCtx)
 Sets up the full rank communication infrastructure, including neighbor ranks and bounding box exchange.
 
PetscErrorCode Contra2Cart (UserCtx *user)
 Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on cell faces.
 
PetscErrorCode Cart2Contra (UserCtx *user)
 Convert the ghosted Cartesian velocity field to contravariant face fluxes.
 
PetscErrorCode UniformCart2Contra (UserCtx *user, PetscReal u, PetscReal v, PetscReal w)
 Populate contravariant fluxes from one uniform Cartesian velocity.
 
PetscErrorCode SetupDomainCellDecompositionMap (UserCtx *user)
 Creates and distributes a map of the domain's cell decomposition to all ranks.
 
PetscErrorCode BinarySearchInt64 (PetscInt n, const PetscInt64 arr[], PetscInt64 key, PetscBool *found)
 Performs a binary search for a key in a sorted array of PetscInt64.
 
PetscErrorCode ComputeDivergence (UserCtx *user)
 Computes the discrete divergence of the contravariant velocity field.
 
PetscErrorCode InitializeRandomGenerators (UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
 Initializes random number generators for assigning particle properties.
 
PetscErrorCode InitializeLogicalSpaceRNGs (PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
 Initializes random number generators for logical space operations [0.0, 1.0).
 
PetscErrorCode InitializeBrownianRNG (SimCtx *simCtx)
 Initializes a single master RNG for time-stepping physics (Brownian motion).
 
void TransformScalarDerivativesToPhysical (PetscReal jacobian, Cmpnts csi_metrics, Cmpnts eta_metrics, Cmpnts zet_metrics, PetscReal dPhi_dcsi, PetscReal dPhi_deta, PetscReal dPhi_dzet, Cmpnts *gradPhi)
 Transforms scalar derivatives from computational space to physical space.
 
PetscErrorCode ComputeScalarFieldDerivatives (UserCtx *user, PetscInt i, PetscInt j, PetscInt k, PetscReal ***field_data, Cmpnts *grad)
 Computes the gradient of a cell-centered SCALAR field at a specific grid point.
 
PetscErrorCode ComputeVectorFieldDerivatives (UserCtx *user, PetscInt i, PetscInt j, PetscInt k, Cmpnts ***field_data, Cmpnts *dudx, Cmpnts *dvdx, Cmpnts *dwdx)
 Computes the derivatives of a cell-centered vector field at a specific grid point.
 
PetscErrorCode DestroyUserVectors (UserCtx *user)
 Destroys all PETSc Vec objects within a single UserCtx structure.
 
PetscErrorCode DestroyUserContext (UserCtx *user)
 Destroys all resources allocated within a single UserCtx structure.
 
PetscErrorCode FinalizeSimulation (SimCtx *simCtx)
 Main cleanup function for the entire simulation context.
 

Macro Definition Documentation

◆ Allocate3DArray

#define Allocate3DArray (   array,
  nz,
  ny,
  nx 
)
Value:
_Generic((array), \
PetscReal ****: Allocate3DArrayScalar, \
)(array, nz, ny, nx)
PetscErrorCode Allocate3DArrayScalar(PetscReal ****array, PetscInt nz, PetscInt ny, PetscInt nx)
Allocates a 3D array of PetscReal values using PetscCalloc.
Definition setup.c:2188
PetscErrorCode Allocate3DArrayVector(Cmpnts ****array, PetscInt nz, PetscInt ny, PetscInt nx)
Allocates a contiguous 3D array of Cmpnts values.
Definition setup.c:2266
A 3D point or vector with PetscScalar components.
Definition variables.h:100

Definition at line 27 of file setup.h.

31 )(array, nz, ny, nx)

◆ Deallocate3DArray

#define Deallocate3DArray (   array,
  nz,
  ny 
)
Value:
_Generic((array), \
PetscReal ***: Deallocate3DArrayScalar, \
)(array, nz, ny)
PetscErrorCode Deallocate3DArrayVector(Cmpnts ***array, PetscInt nz, PetscInt ny)
Deallocates a 3D array of Cmpnts structures allocated by Allocate3DArrayVector.
Definition setup.c:2316
PetscErrorCode Deallocate3DArrayScalar(PetscReal ***array, PetscInt nz, PetscInt ny)
Deallocates a 3D array of PetscReal values allocated by Allocate3DArrayScalar.
Definition setup.c:2223

Definition at line 34 of file setup.h.

38 )(array, nz, ny)

Function Documentation

◆ CreateSimulationContext()

PetscErrorCode CreateSimulationContext ( int  argc,
char **  argv,
SimCtx **  p_simCtx 
)

Allocates and populates the master SimulationContext object.

This function serves as the single, authoritative entry point for all simulation configuration. It merges the setup logic from both the legacy FSI/IBM solver and the modern particle solver into a unified, robust process.

The function follows a strict sequence:

  1. Allocate Context & Set Defaults: It first allocates the SimulationContext and populates every field with a sane, hardcoded default value. This ensures the simulation starts from a known, predictable state.
  2. Configure Logging System: It configures the custom logging framework. It parses the -func_config_file option to load a list of function names allowed to produce log output. This configuration (the file path and the list of function names) is stored within the SimulationContext for later reference and cleanup.
  3. Parse All Options: It performs a comprehensive pass of PetscOptionsGet... calls for every possible command-line flag, overriding the default values set in step 1.
  4. Log Summary: After all options are parsed, it uses the now-active logging system to print a summary of the key simulation parameters.
Parameters
[in]argcArgument count passed from main.
[in]argvArgument vector passed from main.
[out]p_simCtxOn success, this will point to the newly created and fully configured SimulationContext pointer. The caller is responsible for eventually destroying this object by calling FinalizeSimulation().
Returns
PetscErrorCode Returns 0 on success, or a non-zero PETSc error code on failure.

Allocates and populates the master SimulationContext object.

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

See also
CreateSimulationContext()

Definition at line 151 of file setup.c.

152{
153 PetscErrorCode ierr;
154 (void)argc;
155 (void)argv;
156 SimCtx *simCtx;
157 char control_filename[PETSC_MAX_PATH_LEN] = ""; // Temporary placeholder for control file name.
158 PetscBool control_flg; // Temporary placeholder for control file tag existence check flag.
159 PetscBool particle_console_output_freq_flg = PETSC_FALSE;
160
161 PetscFunctionBeginUser;
162
164
165 // === 1. Allocate the Context Struct and Set ALL Defaults ==================
166 ierr = PetscNew(p_simCtx); CHKERRQ(ierr);
167 simCtx = *p_simCtx;
168
169 // --- Group 1: Parallelism & MPI ---
170 simCtx->rank = 0; simCtx->size = 1;
171
172 // --- Group 2: Simulation Control, Time, and I/O ---
173 simCtx->step = 0; simCtx->ti = 0.0; simCtx->StartStep = 0; simCtx->StepsToRun = 10;
174 simCtx->tiout = 10; simCtx->particleConsoleOutputFreq = simCtx->tiout;
175 simCtx->StartTime = 0.0; simCtx->dt = 0.001;
176 simCtx->OnlySetup = PETSC_FALSE;
177 simCtx->continueMode = PETSC_FALSE;
178 simCtx->logviewer = NULL;
179 strcpy(simCtx->eulerianSource,"solve");
180 strcpy(simCtx->restart_dir,"restart");
181 strcpy(simCtx->output_dir,"output");
182 strcpy(simCtx->log_dir,"logs");
183 strcpy(simCtx->euler_subdir,"eulerian");
184 strcpy(simCtx->particle_subdir,"particles");
185 simCtx->_io_context_buffer[0] = '\0';
186 simCtx->current_io_directory = NULL;
187
188 // --- Group 3: High-Level Physics & Model Selection Flags ---
189 simCtx->immersed = 0; simCtx->movefsi = 0; simCtx->rotatefsi = 0;
190 simCtx->sediment = 0; simCtx->rheology = 0; simCtx->invicid = 0;
191 simCtx->TwoD = 0; simCtx->thin = 0; simCtx->moveframe = 0;
192 simCtx->rotateframe = 0; simCtx->blank = 0;
193 simCtx->dgf_x = 0; simCtx->dgf_y = 1; simCtx->dgf_z = 0;
194 simCtx->dgf_ax = 1; simCtx->dgf_ay = 0; simCtx->dgf_az = 0;
195 strcpy(simCtx->AnalyticalSolutionType,"TGV3D");
196
197 // --- Group 4: Specific Simulation Case Flags --- (DEPRICATED)
198 simCtx->cop=0; simCtx->fish=0; simCtx->fish_c=0; simCtx->fishcyl=0;
199 simCtx->eel=0; simCtx->pizza=0; simCtx->turbine=0; simCtx->Pipe=0;
200 simCtx->wing=0; simCtx->hydro=0; simCtx->MHV=0; simCtx->LV=0;
201 simCtx->channelz = 0;
202
203 // --- Group 5: Solver & Numerics Parameters ---
205 simCtx->mom_dt_jameson_residual_norm_noise_allowance_factor = 1.1; // raised from 1.05; less aggressive rejection
206 simCtx->mom_atol = 1e-7; simCtx->mom_rtol = 1e-4;
207 simCtx->mom_resid_atol = 0.0; simCtx->mom_resid_rtol = 0.0;
208 simCtx->imp_stol = 1.e-8;
209 simCtx->mglevels = 3; simCtx->mg_MAX_IT = 30; simCtx->mg_idx = 1;
210 simCtx->mg_preItr = 1; simCtx->mg_poItr = 1;
211 simCtx->poisson = 0; simCtx->poisson_tol = 5.e-9;
212 simCtx->STRONG_COUPLING = 0;simCtx->central=0;
213 /* pseudo_cfl and its bounds are now dimensionless Courant numbers: CFL = dtau * lambda_max,
214 where lambda_max is the global spectral radius computed at each physical timestep.
215 Stable range for 4-stage Jameson RK: ~0–2.83. Initial 0.5 gives a comfortable margin. */
216 simCtx->ren = 100.0; simCtx->pseudo_cfl = 0.5;
217 simCtx->max_pseudo_cfl = 2.0; simCtx->min_pseudo_cfl = 0.001;
218 simCtx->pseudo_cfl_reduction_factor = 0.75;
219 simCtx->pseudo_cfl_growth_factor = 1.1; // raised from 1.0; controller can now increase CFL
220 simCtx->no_pseudo_cfl_backtrack = PETSC_FALSE;
221 simCtx->mom_ratio_ema_alpha = 0.3; /* moderate smoothing; set to 1.0 to recover original raw-ratio behavior */
222 simCtx->mom_last_converged = PETSC_TRUE;
223 simCtx->mom_last_lambda_max = 0.0; /* populated after first momentum solve */
224 simCtx->mom_nk_monitor_history = PETSC_FALSE;
225 simCtx->ps_ksp_pic_monitor_true_residual = PETSC_FALSE;
226 simCtx->cdisx = 0.0; simCtx->cdisy = 0.0; simCtx->cdisz = 0.0;
229 strcpy(simCtx->initialConditionDirectory, "config/initial_condition");
230 simCtx->InitialConstantContra.x = 0.0;
231 simCtx->InitialConstantContra.y = 0.0;
232 simCtx->InitialConstantContra.z = 0.0;
234 simCtx->icVelocityPhysical = 0.0;
235 simCtx->AnalyticalUniformVelocity.x = 0.0;
236 simCtx->AnalyticalUniformVelocity.y = 0.0;
237 simCtx->AnalyticalUniformVelocity.z = 0.0;
244 simCtx->verificationDiffusivity.enabled = PETSC_FALSE;
245 strcpy(simCtx->verificationDiffusivity.mode, "");
246 strcpy(simCtx->verificationDiffusivity.profile, "");
247 simCtx->verificationDiffusivity.gamma0 = 0.0;
248 simCtx->verificationDiffusivity.slope_x = 0.0;
249
250 // --- Group 6: Physical & Geometric Parameters ---
251 simCtx->NumberOfBodies = 1; simCtx->Flux_in = 1.0; simCtx->angle = 0.0;
252 simCtx->max_angle = -54. * 3.1415926 / 180.;
253 simCtx->CMx_c=0.0; simCtx->CMy_c=0.0; simCtx->CMz_c=0.0;
254 simCtx->wall_roughness_height = 1e-16;
255 simCtx->schmidt_number = 1.0; simCtx->Turbulent_schmidt_number = 0.7;
256
257 // --- Group 7: Grid, Domain, and Boundary Condition Settings ---
258 simCtx->block_number = 1; simCtx->inletprofile = 1;
259 simCtx->grid1d = 0; simCtx->Ogrid = 0;
260 simCtx->i_periodic = 0; simCtx->j_periodic = 0; simCtx->k_periodic = 0;
261 simCtx->blkpbc = 10; simCtx->pseudo_periodic = 0;
262 strcpy(simCtx->grid_file, "config/grid.run");
263 simCtx->generate_grid = PETSC_FALSE;
264 simCtx->da_procs_x = PETSC_DECIDE;
265 simCtx->da_procs_y = PETSC_DECIDE;
266 simCtx->da_procs_z = PETSC_DECIDE;
267 simCtx->grid_rotation_angle = 0.0;
268 simCtx->Croty = 0.0; simCtx->Crotz = 0.0;
269 simCtx->num_bcs_files = 1;
270 ierr = PetscMalloc1(1, &simCtx->bcs_files); CHKERRQ(ierr);
271 ierr = PetscStrallocpy("config/bcs.run", &simCtx->bcs_files[0]); CHKERRQ(ierr);
272 simCtx->FluxInSum = 0.0; simCtx->FluxOutSum = 0.0; simCtx->Fluxsum = 0.0;
273 simCtx->drivingForceMagnitude = 0.0, simCtx->forceScalingFactor = 1.8;
274 simCtx->targetVolumetricFlux = 0.0;
275 simCtx->bulkVelocityCorrection = 0.0;
276 simCtx->boundaryVelocityCorrection = 0.0;
277 simCtx->AreaInSum = 0.0; simCtx->AreaOutSum = 0.0;
278 simCtx->U_bc = 0.0; simCtx->ccc = 0;
279 simCtx->ratio = 0.0;
280
281
282 // --- Group 8: Turbulence Modeling (LES/RANS) ---
283 simCtx->averaging = PETSC_FALSE; simCtx->les = NO_LES_MODEL; simCtx->rans = 0;
284 simCtx->wallfunction = 0; simCtx->mixed = 0; simCtx->clark = 0;
285 simCtx->dynamic_freq = 1; simCtx->max_cs = 0.5;
286 simCtx->Const_CS = 0.03;
287 simCtx->testfilter_ik = 0; simCtx->testfilter_1d = 0;
288 simCtx->i_homo_filter = 0; simCtx->j_homo_filter = 0; simCtx->k_homo_filter = 0;
289
290 // --- Group 9: Particle / DMSwarm Data & Settings ---
291 simCtx->np = 0; simCtx->readFields = PETSC_FALSE;
292 simCtx->dm_swarm = NULL; simCtx->bboxlist = NULL;
295 strcpy(simCtx->particleRestartMode,"load");
296 simCtx->particlesLostLastStep = 0;
297 simCtx->particlesLostCumulative = 0;
298 simCtx->particlesMigratedLastStep = 0;
299 simCtx->occupiedCellCount = 0;
300 simCtx->particleLoadImbalance = 0.0;
301 simCtx->migrationPassesLastStep = 0;
302 simCtx->searchMetrics.searchAttempts = 0;
305 simCtx->searchMetrics.searchLostCount = 0;
307 simCtx->searchMetrics.reSearchCount = 0;
310 simCtx->searchMetrics.tieBreakCount = 0;
316 simCtx->BrownianMotionRNG = NULL;
317 simCtx->C_IEM = 2.0;
318
319 // --- Group 10: Immersed Boundary & FSI Data Object Pointers ---
320 simCtx->ibm = NULL; simCtx->ibmv = NULL; simCtx->fsi = NULL;
321 simCtx->rstart_fsi = PETSC_FALSE; simCtx->duplicate = 0;
322
323 // --- Group 11: Logging and Custom Configuration ---
324 strcpy(simCtx->allowedFile, "config/whitelist.run");
325 simCtx->useCfg = PETSC_FALSE;
326 simCtx->allowedFuncs = NULL;
327 simCtx->nAllowed = 0;
328 simCtx->LoggingFrequency = 10;
329 simCtx->summationRHS = 0.0;
330 simCtx->MaxDiv = 0.0;
331 simCtx->MaxDivFlatArg = 0; simCtx->MaxDivx = 0; simCtx->MaxDivy = 0; simCtx->MaxDivz = 0;
332 strcpy(simCtx->profilingSelectedFuncsFile, "config/profile.run");
333 simCtx->useProfilingSelectedFuncsCfg = PETSC_FALSE;
334 simCtx->profilingSelectedFuncs = NULL;
335 simCtx->nProfilingSelectedFuncs = 0;
336 strcpy(simCtx->profilingTimestepMode, "selected");
337 strcpy(simCtx->profilingTimestepFile, "Profiling_Timestep_Summary.csv");
338 simCtx->profilingFinalSummary = PETSC_TRUE;
339 simCtx->walltimeGuardEnabled = PETSC_FALSE;
340 simCtx->walltimeGuardActive = PETSC_FALSE;
341 simCtx->walltimeGuardWarmupSteps = 10;
342 simCtx->walltimeGuardMultiplier = 2.0;
343 simCtx->walltimeGuardMinSeconds = 60.0;
344 simCtx->walltimeGuardEstimatorAlpha = 0.35;
346 simCtx->walltimeGuardLimitSeconds = 0.0;
347 simCtx->walltimeGuardCompletedSteps = 0;
350 simCtx->walltimeGuardHasEWMA = PETSC_FALSE;
351 simCtx->walltimeGuardEWMASeconds = 0.0;
352 simCtx->walltimeGuardLatestStepSeconds = 0.0;
353 simCtx->runtimeMemoryLogEnabled = PETSC_TRUE;
354 strcpy(simCtx->runtimeMemoryLogFile, "Runtime_Memory.log");
355 simCtx->runtimeMemoryLogStarted = PETSC_FALSE;
356 simCtx->runtimeMemoryLogHasPrevious = PETSC_FALSE;
358 // --- Group 11: Post-Processing Information ---
359 strcpy(simCtx->PostprocessingControlFile, "config/post.run");
360 ierr = PetscNew(&simCtx->pps); CHKERRQ(ierr);
361
362 // === 2. Get MPI Info and Handle Config File =============================
363 // -- Group 1: Parallelism & MPI Information
364 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &simCtx->rank); CHKERRQ(ierr);
365 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &simCtx->size); CHKERRQ(ierr);
366
367 // First, check if the -control_file argument was provided by the user/script.
368 ierr = PetscOptionsGetString(NULL, NULL, "-control_file", control_filename, sizeof(control_filename), &control_flg); CHKERRQ(ierr);
369
370 // If the flag is NOT present or the filename is empty, abort with a helpful error.
371 if (!control_flg || strlen(control_filename) == 0) {
372 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
373 "\n\n*** MANDATORY ARGUMENT MISSING ***\n"
374 "The -control_file argument was not provided.\n"
375 "This program must be launched with a configuration file.\n"
376 "Example: mpiexec -n 4 ./simulator -control_file /path/to/your/config.control\n"
377 "This is typically handled automatically by the 'picurv' script.\n");
378 }
379
380 // At this point, we have a valid filename. Attempt to load it.
381 LOG(GLOBAL, LOG_INFO, "Loading mandatory configuration from: %s\n", control_filename);
382 ierr = PetscOptionsInsertFile(PETSC_COMM_WORLD, NULL, control_filename, PETSC_FALSE);
383 if (ierr == PETSC_ERR_FILE_OPEN) {
384 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_FILE_OPEN, "The specified control file was not found or could not be opened: %s", control_filename);
385 }
386 CHKERRQ(ierr);
387
388 // === 3. A Configure Logging System ========================================
389 // This logic determines the logging configuration and STORES it in simCtx for
390 // later reference and cleanup.
391 ierr = PetscOptionsGetString(NULL, NULL, "-whitelist_config_file", simCtx->allowedFile, PETSC_MAX_PATH_LEN, &simCtx->useCfg); CHKERRQ(ierr);
392
393 if (simCtx->useCfg) {
394 ierr = LoadAllowedFunctionsFromFile(simCtx->allowedFile, &simCtx->allowedFuncs, &simCtx->nAllowed);
395 if (ierr) {
396 // Use direct PetscPrintf as logging system isn't fully active yet.
397 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Failed to load allowed functions from '%s'. Falling back to default list.\n", __func__, simCtx->allowedFile);
398 simCtx->useCfg = PETSC_FALSE; // Mark as failed.
399 ierr = 0; // Clear the error to allow fallback.
400 } else if (simCtx->nAllowed == 0) {
401 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
402 "Whitelist config file '%s' is empty. Omit -whitelist_config_file to use the default allow-list, or list at least one function.",
403 simCtx->allowedFile);
404 }
405 }
406 if (!simCtx->useCfg) {
407 // Fallback to default logging functions if no file was used or if loading failed.
408 simCtx->nAllowed = 2;
409 ierr = PetscMalloc1(simCtx->nAllowed, &simCtx->allowedFuncs); CHKERRQ(ierr);
410 ierr = PetscStrallocpy("main", &simCtx->allowedFuncs[0]); CHKERRQ(ierr);
411 ierr = PetscStrallocpy("CreateSimulationContext", &simCtx->allowedFuncs[1]); CHKERRQ(ierr);
412 }
413
414 // Activate the configuration by passing it to the logging module's setup function.
415 set_allowed_functions((const char**)simCtx->allowedFuncs, (size_t)simCtx->nAllowed);
416
417 // Now that the logger is configured, we can use it.
418 LOG_ALLOW_SYNC(LOCAL, LOG_INFO, "Context created. Initializing on rank %d of %d.\n", simCtx->rank, simCtx->size);
419 print_log_level(); // This will now correctly reflect the LOG_LEVEL environment variable.
420
421 // === 3.B Configure Profiling System ========================================
422 ierr = PetscOptionsGetString(NULL, NULL, "-profiling_timestep_mode", simCtx->profilingTimestepMode, sizeof(simCtx->profilingTimestepMode), NULL); CHKERRQ(ierr);
423 ierr = PetscOptionsGetString(NULL, NULL, "-profiling_timestep_file", simCtx->profilingTimestepFile, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
424 ierr = PetscOptionsGetBool(NULL, NULL, "-profiling_final_summary", &simCtx->profilingFinalSummary, NULL); CHKERRQ(ierr);
425 if (strcmp(simCtx->profilingTimestepMode, "off") != 0 &&
426 strcmp(simCtx->profilingTimestepMode, "selected") != 0 &&
427 strcmp(simCtx->profilingTimestepMode, "all") != 0) {
428 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Unknown profiling timestep mode '%s'. Falling back to 'selected'.\n", __func__, simCtx->profilingTimestepMode);
429 strcpy(simCtx->profilingTimestepMode, "selected");
430 }
431
432 if (strcmp(simCtx->profilingTimestepMode, "selected") == 0) {
433 ierr = PetscOptionsGetString(NULL, NULL, "-profile_config_file", simCtx->profilingSelectedFuncsFile, PETSC_MAX_PATH_LEN, &simCtx->useProfilingSelectedFuncsCfg); CHKERRQ(ierr);
434 if (simCtx->useProfilingSelectedFuncsCfg) {
436 if (ierr) {
437 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Failed to load selected profiling functions from '%s'. Falling back to default list.\n", __func__, simCtx->profilingSelectedFuncsFile);
438 simCtx->useProfilingSelectedFuncsCfg = PETSC_FALSE;
439 ierr = 0;
440 }
441 }
442 if (!simCtx->useProfilingSelectedFuncsCfg) {
443 // Fallback to a hardcoded default list if no file was provided or loading failed.
444 simCtx->nProfilingSelectedFuncs = 4;
445 ierr = PetscMalloc1(simCtx->nProfilingSelectedFuncs, &simCtx->profilingSelectedFuncs); CHKERRQ(ierr);
446 ierr = PetscStrallocpy("FlowSolver", &simCtx->profilingSelectedFuncs[0]); CHKERRQ(ierr);
447 ierr = PetscStrallocpy("AdvanceSimulation", &simCtx->profilingSelectedFuncs[1]); CHKERRQ(ierr);
448 ierr = PetscStrallocpy("LocateAllParticlesInGrid", &simCtx->profilingSelectedFuncs[2]); CHKERRQ(ierr);
449 ierr = PetscStrallocpy("InterpolateAllFieldsToSwarm", &simCtx->profilingSelectedFuncs[3]); CHKERRQ(ierr);
450 }
451 }
452
453 // Initialize the profiling system with the current updated simulation context.
454 ierr = ProfilingInitialize(simCtx); CHKERRQ(ierr);
455
456 // === 4. Parse All Command Line Options ==================================
457 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing command-line options...\n");
458
459 // --- Group 2
460 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 2: Simulation Control,Time and I/O.\n");
461 // Read the physical time to start from.
462 // The default is already 0.0, so this will only be non-zero if the user provides it.
463 ierr = PetscOptionsGetInt(NULL, NULL, "-start_step", &simCtx->StartStep, NULL); CHKERRQ(ierr);
464 ierr = PetscOptionsGetInt(NULL,NULL, "-totalsteps", &simCtx->StepsToRun, NULL); CHKERRQ(ierr);
465 ierr = PetscOptionsGetBool(NULL, NULL, "-only_setup", &simCtx->OnlySetup, NULL); CHKERRQ(ierr);
466 ierr = PetscOptionsGetBool(NULL, NULL, "-continue_mode", &simCtx->continueMode, NULL); CHKERRQ(ierr);
467 ierr = PetscOptionsGetReal(NULL, NULL, "-dt", &simCtx->dt, NULL); CHKERRQ(ierr);
468 ierr = PetscOptionsGetInt(NULL, NULL, "-tio", &simCtx->tiout, NULL); CHKERRQ(ierr);
469 ierr = PetscOptionsGetInt(NULL, NULL, "-particle_console_output_freq", &simCtx->particleConsoleOutputFreq, &particle_console_output_freq_flg); CHKERRQ(ierr);
470 if (!particle_console_output_freq_flg) {
471 simCtx->particleConsoleOutputFreq = simCtx->tiout;
472 }
473 ierr = PetscOptionsGetString(NULL,NULL,"-euler_field_source",simCtx->eulerianSource,sizeof(simCtx->eulerianSource),NULL);CHKERRQ(ierr);
474 ierr = PetscOptionsGetString(NULL,NULL,"-output_dir",simCtx->output_dir,sizeof(simCtx->output_dir),NULL);CHKERRQ(ierr);
475 ierr = PetscOptionsGetString(NULL,NULL,"-restart_dir",simCtx->restart_dir,sizeof(simCtx->restart_dir),NULL);CHKERRQ(ierr);
476 ierr = PetscOptionsGetString(NULL,NULL,"-log_dir",simCtx->log_dir,sizeof(simCtx->log_dir),NULL);CHKERRQ(ierr);
477 ierr = PetscOptionsGetString(NULL,NULL,"-euler_subdir",simCtx->euler_subdir,sizeof(simCtx->euler_subdir),NULL);CHKERRQ(ierr);
478 ierr = PetscOptionsGetString(NULL,NULL,"-particle_subdir",simCtx->particle_subdir,sizeof(simCtx->particle_subdir),NULL);CHKERRQ(ierr);
479 ierr = PetscOptionsGetBool(NULL, NULL, "-walltime_guard_enabled", &simCtx->walltimeGuardEnabled, NULL); CHKERRQ(ierr);
480 ierr = PetscOptionsGetInt(NULL, NULL, "-walltime_guard_warmup_steps", &simCtx->walltimeGuardWarmupSteps, NULL); CHKERRQ(ierr);
481 ierr = PetscOptionsGetReal(NULL, NULL, "-walltime_guard_multiplier", &simCtx->walltimeGuardMultiplier, NULL); CHKERRQ(ierr);
482 ierr = PetscOptionsGetBool(NULL, NULL, "-runtime_memory_log_enabled", &simCtx->runtimeMemoryLogEnabled, NULL); CHKERRQ(ierr);
483 ierr = PetscOptionsGetString(NULL, NULL, "-runtime_memory_log_file", simCtx->runtimeMemoryLogFile, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
484 ierr = PetscOptionsGetReal(NULL, NULL, "-walltime_guard_min_seconds", &simCtx->walltimeGuardMinSeconds, NULL); CHKERRQ(ierr);
485 ierr = PetscOptionsGetReal(NULL, NULL, "-walltime_guard_estimator_alpha", &simCtx->walltimeGuardEstimatorAlpha, NULL); CHKERRQ(ierr);
486
487 if (simCtx->walltimeGuardWarmupSteps <= 0) {
488 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_warmup_steps: %d. Must be > 0.", simCtx->walltimeGuardWarmupSteps);
489 }
490 if (simCtx->walltimeGuardMultiplier <= 0.0 || simCtx->walltimeGuardMultiplier > 5.0) {
491 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_multiplier: %.6f. Must be in (0, 5].", (double)simCtx->walltimeGuardMultiplier);
492 }
493 if (simCtx->walltimeGuardMinSeconds <= 0.0) {
494 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_min_seconds: %.6f. Must be > 0.", (double)simCtx->walltimeGuardMinSeconds);
495 }
496 if (simCtx->walltimeGuardEstimatorAlpha <= 0.0 || simCtx->walltimeGuardEstimatorAlpha > 1.0) {
497 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_estimator_alpha: %.6f. Must be in (0, 1].", (double)simCtx->walltimeGuardEstimatorAlpha);
498 }
499
500 if(strcmp(simCtx->eulerianSource,"solve")!= 0 && strcmp(simCtx->eulerianSource,"load") != 0 && strcmp(simCtx->eulerianSource,"analytical")!=0){
501 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Invalid value for -euler_field_source. Must be 'load','analytical' or 'solve'. You provided '%s'.",simCtx->eulerianSource);
502 }
503 if (simCtx->walltimeGuardEnabled) {
504 const char *job_start_env = getenv("PICURV_JOB_START_EPOCH");
505 const char *limit_env = getenv("PICURV_WALLTIME_LIMIT_SECONDS");
506 PetscBool job_start_ok = RuntimeWalltimeGuardParsePositiveSeconds(job_start_env, &simCtx->walltimeGuardJobStartEpochSeconds);
507 PetscBool limit_ok = RuntimeWalltimeGuardParsePositiveSeconds(limit_env, &simCtx->walltimeGuardLimitSeconds);
508
509 if (!job_start_ok || !limit_ok) {
510 simCtx->walltimeGuardActive = PETSC_FALSE;
512 simCtx->walltimeGuardLimitSeconds = 0.0;
513 LOG_ALLOW(
514 GLOBAL,
516 "Runtime walltime guard enabled but %s/%s are missing or invalid. Falling back to external shutdown signals only.\n",
517 "PICURV_JOB_START_EPOCH",
518 "PICURV_WALLTIME_LIMIT_SECONDS"
519 );
520 } else {
521 simCtx->walltimeGuardActive = PETSC_TRUE;
522 }
523 }
524
525 // --- Group 3
526 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 3: High-Level Physics & Model Selection Flags\n");
527 ierr = PetscOptionsGetInt(NULL, NULL, "-imm", &simCtx->immersed, NULL); CHKERRQ(ierr);
528 ierr = PetscOptionsGetInt(NULL, NULL, "-fsi", &simCtx->movefsi, NULL); CHKERRQ(ierr);
529 ierr = PetscOptionsGetInt(NULL, NULL, "-rfsi", &simCtx->rotatefsi, NULL); CHKERRQ(ierr);
530 ierr = PetscOptionsGetInt(NULL, NULL, "-sediment", &simCtx->sediment, NULL); CHKERRQ(ierr);
531 ierr = PetscOptionsGetInt(NULL, NULL, "-rheology", &simCtx->rheology, NULL); CHKERRQ(ierr);
532 ierr = PetscOptionsGetInt(NULL, NULL, "-inv", &simCtx->invicid, NULL); CHKERRQ(ierr);
533 ierr = PetscOptionsGetInt(NULL, NULL, "-TwoD", &simCtx->TwoD, NULL); CHKERRQ(ierr);
534 ierr = PetscOptionsGetInt(NULL, NULL, "-thin", &simCtx->thin, NULL); CHKERRQ(ierr);
535 ierr = PetscOptionsGetInt(NULL, NULL, "-mframe", &simCtx->moveframe, NULL); CHKERRQ(ierr);
536 ierr = PetscOptionsGetInt(NULL, NULL, "-rframe", &simCtx->rotateframe, NULL); CHKERRQ(ierr);
537 ierr = PetscOptionsGetInt(NULL, NULL, "-blk", &simCtx->blank, NULL); CHKERRQ(ierr);
538 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_z", &simCtx->dgf_z, NULL); CHKERRQ(ierr);
539 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_y", &simCtx->dgf_y, NULL); CHKERRQ(ierr);
540 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_x", &simCtx->dgf_x, NULL); CHKERRQ(ierr);
541 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_az", &simCtx->dgf_az, NULL); CHKERRQ(ierr);
542 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_ay", &simCtx->dgf_ay, NULL); CHKERRQ(ierr);
543 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_ax", &simCtx->dgf_ax, NULL); CHKERRQ(ierr);
544 ierr = PetscOptionsGetString(NULL,NULL,"-analytical_type",simCtx->AnalyticalSolutionType,sizeof(simCtx->AnalyticalSolutionType),NULL);CHKERRQ(ierr);
545
546 // --- Group 4
547 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 4: Specific Simulation Case Flags \n");
548 ierr = PetscOptionsGetInt(NULL, NULL, "-cop", &simCtx->cop, NULL); CHKERRQ(ierr);
549 ierr = PetscOptionsGetInt(NULL, NULL, "-fish", &simCtx->fish, NULL); CHKERRQ(ierr);
550 ierr = PetscOptionsGetInt(NULL, NULL, "-pizza", &simCtx->pizza, NULL); CHKERRQ(ierr);
551 ierr = PetscOptionsGetInt(NULL, NULL, "-turbine", &simCtx->turbine, NULL); CHKERRQ(ierr);
552 ierr = PetscOptionsGetInt(NULL, NULL, "-fishcyl", &simCtx->fishcyl, NULL); CHKERRQ(ierr);
553 ierr = PetscOptionsGetInt(NULL, NULL, "-eel", &simCtx->eel, NULL); CHKERRQ(ierr);
554 ierr = PetscOptionsGetInt(NULL, NULL, "-cstart", &simCtx->fish_c, NULL); CHKERRQ(ierr);
555 ierr = PetscOptionsGetInt(NULL, NULL, "-wing", &simCtx->wing, NULL); CHKERRQ(ierr);
556 ierr = PetscOptionsGetInt(NULL, NULL, "-mhv", &simCtx->MHV, NULL); CHKERRQ(ierr);
557 ierr = PetscOptionsGetInt(NULL, NULL, "-hydro", &simCtx->hydro, NULL); CHKERRQ(ierr);
558 ierr = PetscOptionsGetInt(NULL, NULL, "-lv", &simCtx->LV, NULL); CHKERRQ(ierr);
559 ierr = PetscOptionsGetInt(NULL, NULL, "-Pipe", &simCtx->Pipe, NULL); CHKERRQ(ierr);
560 ierr = PetscOptionsGetInt(NULL, NULL, "-Turbulent_Channel_z", &simCtx->channelz, NULL); CHKERRQ(ierr);
561 ierr = PetscOptionsGetReal(NULL,NULL,"-driven_flow_initial_force",&simCtx->drivingForceMagnitude,NULL);CHKERRQ(ierr);
562 ierr = PetscOptionsGetReal(NULL,NULL,"-driven_flow_scaling_factor",&simCtx->forceScalingFactor,NULL);CHKERRQ(ierr);
563 // --- Group 5
564 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 5: Solver & Numerics Parameters \n");
565 char mom_solver_type_char[PETSC_MAX_PATH_LEN];
566 char solution_convergence_mode_char[PETSC_MAX_PATH_LEN];
567 PetscBool mom_solver_type_flg = PETSC_FALSE;
568 PetscBool solution_convergence_mode_flg = PETSC_FALSE;
569 ierr = PetscOptionsGetString(NULL, NULL, "-mom_solver_type", mom_solver_type_char, sizeof(mom_solver_type_char), &mom_solver_type_flg); CHKERRQ(ierr);
570 ierr = PetscOptionsGetInt(NULL, NULL, "-mom_max_pseudo_steps", &simCtx->mom_max_pseudo_steps, NULL); CHKERRQ(ierr);
571 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_atol", &simCtx->mom_atol, NULL); CHKERRQ(ierr);
572 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_rtol", &simCtx->mom_rtol, NULL); CHKERRQ(ierr);
573 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_resid_atol", &simCtx->mom_resid_atol, NULL); CHKERRQ(ierr);
574 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_resid_rtol", &simCtx->mom_resid_rtol, NULL); CHKERRQ(ierr);
575 ierr = PetscOptionsGetReal(NULL, NULL, "-imp_stol", &simCtx->imp_stol, NULL); CHKERRQ(ierr);
576 ierr = PetscOptionsGetInt(NULL, NULL, "-central", &simCtx->central, NULL); CHKERRQ(ierr);
577 ierr = PetscOptionsGetString(NULL, NULL, "-solution_convergence_mode",
578 solution_convergence_mode_char, sizeof(solution_convergence_mode_char),
579 &solution_convergence_mode_flg); CHKERRQ(ierr);
580 ierr = PetscOptionsGetInt(NULL, NULL, "-solution_convergence_period_steps", &simCtx->solutionConvergencePeriodSteps, NULL); CHKERRQ(ierr);
581 ierr = PetscOptionsGetInt(NULL, NULL, "-solution_convergence_window_steps", &simCtx->solutionConvergenceWindowSteps, NULL); CHKERRQ(ierr);
582
583 // Keep parser acceptance aligned with the enum and FlowSolver dispatch.
584 if (mom_solver_type_flg) {
585 if(strcmp(mom_solver_type_char, "DUALTIME_PICARD_JAMESON_RK") == 0 ||
586 strcmp(mom_solver_type_char, "DUALTIME_PICARD_RK4") == 0) {
588 } else if (strcmp(mom_solver_type_char, "EXPLICIT_RK") == 0) {
590 } else if (strcmp(mom_solver_type_char, "newton_krylov") == 0) {
592 } else {
593 LOG(GLOBAL, LOG_ERROR, "Invalid value for -mom_solver_type: '%s'. Valid options are: 'DUALTIME_PICARD_JAMESON_RK', 'EXPLICIT_RK', 'newton_krylov'.\n", mom_solver_type_char);
594 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -mom_solver_type: '%s'.", mom_solver_type_char);
595 }
596 }
597
598 if (solution_convergence_mode_flg) {
599 if (strcmp(solution_convergence_mode_char, "STEADY_DETERMINISTIC") == 0) {
601 } else if (strcmp(solution_convergence_mode_char, "PERIODIC_DETERMINISTIC") == 0) {
603 } else if (strcmp(solution_convergence_mode_char, "STATISTICAL_STEADY") == 0) {
605 } else if (strcmp(solution_convergence_mode_char, "TRANSIENT") == 0) {
607 } else {
608 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
609 "Invalid value for -solution_convergence_mode: '%s'.", solution_convergence_mode_char);
610 }
611 }
612
614 simCtx->solutionConvergencePeriodSteps <= 0) {
615 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
616 "solution convergence mode PERIODIC_DETERMINISTIC requires -solution_convergence_period_steps > 0.");
617 }
619 simCtx->solutionConvergenceWindowSteps <= 0) {
620 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
621 "solution convergence mode STATISTICAL_STEADY requires -solution_convergence_window_steps > 0.");
622 }
623
624 // --- Multigrid Options ---
625 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_level", &simCtx->mglevels, NULL); CHKERRQ(ierr);
626 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_max_it", &simCtx->mg_MAX_IT, NULL); CHKERRQ(ierr);
627 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_idx", &simCtx->mg_idx, NULL); CHKERRQ(ierr);
628 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_pre_it", &simCtx->mg_preItr, NULL); CHKERRQ(ierr);
629 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_post_it", &simCtx->mg_poItr, NULL); CHKERRQ(ierr);
630
631 // --- Other Solver Options ---
632 ierr = PetscOptionsGetInt(NULL, NULL, "-poisson", &simCtx->poisson, NULL); CHKERRQ(ierr);
633 ierr = PetscOptionsGetReal(NULL, NULL, "-poisson_tol", &simCtx->poisson_tol, NULL); CHKERRQ(ierr);
634 ierr = PetscOptionsGetInt(NULL, NULL, "-str", &simCtx->STRONG_COUPLING, NULL); CHKERRQ(ierr);
635 ierr = PetscOptionsGetReal(NULL, NULL, "-ren", &simCtx->ren, NULL); CHKERRQ(ierr);
636 ierr = PetscOptionsGetReal(NULL, NULL, "-pseudo_cfl", &simCtx->pseudo_cfl, NULL); CHKERRQ(ierr);
637 ierr = PetscOptionsGetReal(NULL, NULL, "-max_pseudo_cfl", &simCtx->max_pseudo_cfl, NULL); CHKERRQ(ierr);
638 ierr = PetscOptionsGetReal(NULL, NULL, "-min_pseudo_cfl", &simCtx->min_pseudo_cfl, NULL); CHKERRQ(ierr);
639 ierr = PetscOptionsGetReal(NULL, NULL, "-pseudo_cfl_reduction_factor", &simCtx->pseudo_cfl_reduction_factor, NULL); CHKERRQ(ierr);
640 ierr = PetscOptionsGetReal(NULL, NULL, "-pseudo_cfl_growth_factor", &simCtx->pseudo_cfl_growth_factor, NULL); CHKERRQ(ierr);
641 // Read the deprecated RK4 spelling first so the canonical Jameson option wins if both are present.
642 ierr = PetscOptionsGetReal(NULL,NULL, "-mom_dt_rk4_residual_norm_noise_allowance_factor",&simCtx->mom_dt_jameson_residual_norm_noise_allowance_factor,NULL);CHKERRQ(ierr);
643 ierr = PetscOptionsGetReal(NULL,NULL, "-mom_dt_jameson_residual_norm_noise_allowance_factor",&simCtx->mom_dt_jameson_residual_norm_noise_allowance_factor,NULL);CHKERRQ(ierr);
644 ierr = PetscOptionsGetBool(NULL, NULL, "-no_pseudo_cfl_backtrack", &simCtx->no_pseudo_cfl_backtrack, NULL); CHKERRQ(ierr);
645 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_ratio_ema_alpha", &simCtx->mom_ratio_ema_alpha, NULL); CHKERRQ(ierr);
646 if (simCtx->min_pseudo_cfl <= 0.0 ||
647 simCtx->pseudo_cfl < simCtx->min_pseudo_cfl ||
648 simCtx->pseudo_cfl > simCtx->max_pseudo_cfl) {
649 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
650 "Pseudo-CFL controls require 0 < minimum <= initial <= maximum.");
651 }
652 if (simCtx->pseudo_cfl_growth_factor < 1.0 ||
653 simCtx->pseudo_cfl_reduction_factor <= 0.0 ||
654 simCtx->pseudo_cfl_reduction_factor >= 1.0 ||
656 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
657 "Pseudo-CFL controls require growth_factor >= 1, 0 < reduction_factor < 1, and noise allowance >= 1.");
658 }
659 if (simCtx->mom_ratio_ema_alpha < 0.0 || simCtx->mom_ratio_ema_alpha > 1.0) {
660 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
661 "-mom_ratio_ema_alpha must be in [0, 1].");
662 }
663 ierr = PetscOptionsHasName(NULL, NULL, "-ps_ksp_pic_monitor_true_residual", &simCtx->ps_ksp_pic_monitor_true_residual); CHKERRQ(ierr);
664 ierr = PetscOptionsGetBool(NULL, NULL, "-mom_nk_pic_monitor", &simCtx->mom_nk_monitor_history, NULL); CHKERRQ(ierr);
665 {
666 PetscInt ic_mode = (PetscInt)simCtx->initialConditionMode;
667 PetscInt ic_field = (PetscInt)simCtx->initialConditionField;
668 ierr = PetscOptionsGetInt(NULL, NULL, "-finit", &ic_mode, NULL); CHKERRQ(ierr);
669 ierr = PetscOptionsGetInt(NULL, NULL, "-ic_field", &ic_field, NULL); CHKERRQ(ierr);
672 }
673 ierr = PetscOptionsGetString(NULL, NULL, "-ic_dir", simCtx->initialConditionDirectory,
674 sizeof(simCtx->initialConditionDirectory), NULL); CHKERRQ(ierr);
676 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
677 "Invalid value for -finit. Expected an initial-condition mode in [0,4], got %d.",
678 simCtx->initialConditionMode);
679 }
681 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
682 "Invalid value for -ic_field. Expected 0 (Ucat) or 1 (Ucont), got %d.",
683 simCtx->initialConditionField);
684 }
685 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_x", &simCtx->InitialConstantContra.x, NULL); CHKERRQ(ierr);
686 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_y", &simCtx->InitialConstantContra.y, NULL); CHKERRQ(ierr);
687 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_z", &simCtx->InitialConstantContra.z, NULL); CHKERRQ(ierr);
688 {
689 PetscInt fd_int = (PetscInt)FLOW_DIR_UNSET;
690 PetscBool fd_set = PETSC_FALSE;
691 ierr = PetscOptionsGetInt(NULL, NULL, "-flow_direction", &fd_int, &fd_set); CHKERRQ(ierr);
692 if (fd_set) simCtx->flowDirection = (FlowDirection)fd_int;
693 }
694 ierr = PetscOptionsGetReal(NULL, NULL, "-ic_velocity_physical", &simCtx->icVelocityPhysical, NULL); CHKERRQ(ierr);
695 ierr = PetscOptionsGetReal(NULL, NULL, "-analytical_uniform_u", &simCtx->AnalyticalUniformVelocity.x, NULL); CHKERRQ(ierr);
696 ierr = PetscOptionsGetReal(NULL, NULL, "-analytical_uniform_v", &simCtx->AnalyticalUniformVelocity.y, NULL); CHKERRQ(ierr);
697 ierr = PetscOptionsGetReal(NULL, NULL, "-analytical_uniform_w", &simCtx->AnalyticalUniformVelocity.z, NULL); CHKERRQ(ierr);
698 PetscBool verification_scalar_value_set = PETSC_FALSE;
699 PetscBool verification_scalar_phi0_set = PETSC_FALSE;
700 PetscBool verification_scalar_slope_x_set = PETSC_FALSE;
701 PetscBool verification_scalar_amplitude_set = PETSC_FALSE;
702 PetscBool verification_scalar_kx_set = PETSC_FALSE;
703 PetscBool verification_scalar_ky_set = PETSC_FALSE;
704 PetscBool verification_scalar_kz_set = PETSC_FALSE;
705 ierr = PetscOptionsGetString(NULL, NULL, "-verification_diffusivity_mode",
707 sizeof(simCtx->verificationDiffusivity.mode), NULL); CHKERRQ(ierr);
708 ierr = PetscOptionsGetString(NULL, NULL, "-verification_diffusivity_profile",
710 sizeof(simCtx->verificationDiffusivity.profile), NULL); CHKERRQ(ierr);
711 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_diffusivity_gamma0",
712 &simCtx->verificationDiffusivity.gamma0, NULL); CHKERRQ(ierr);
713 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_diffusivity_slope_x",
714 &simCtx->verificationDiffusivity.slope_x, NULL); CHKERRQ(ierr);
715 ierr = PetscOptionsGetString(NULL, NULL, "-verification_scalar_mode",
716 simCtx->verificationScalar.mode,
717 sizeof(simCtx->verificationScalar.mode), NULL); CHKERRQ(ierr);
718 ierr = PetscOptionsGetString(NULL, NULL, "-verification_scalar_profile",
720 sizeof(simCtx->verificationScalar.profile), NULL); CHKERRQ(ierr);
721 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_value",
722 &simCtx->verificationScalar.value, &verification_scalar_value_set); CHKERRQ(ierr);
723 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_phi0",
724 &simCtx->verificationScalar.phi0, &verification_scalar_phi0_set); CHKERRQ(ierr);
725 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_slope_x",
726 &simCtx->verificationScalar.slope_x, &verification_scalar_slope_x_set); CHKERRQ(ierr);
727 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_amplitude",
728 &simCtx->verificationScalar.amplitude, &verification_scalar_amplitude_set); CHKERRQ(ierr);
729 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_kx",
730 &simCtx->verificationScalar.kx, &verification_scalar_kx_set); CHKERRQ(ierr);
731 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_ky",
732 &simCtx->verificationScalar.ky, &verification_scalar_ky_set); CHKERRQ(ierr);
733 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_kz",
734 &simCtx->verificationScalar.kz, &verification_scalar_kz_set); CHKERRQ(ierr);
736 (PetscBool)(simCtx->verificationDiffusivity.mode[0] != '\0' ||
737 simCtx->verificationDiffusivity.profile[0] != '\0');
739 (PetscBool)(simCtx->verificationScalar.mode[0] != '\0' ||
740 simCtx->verificationScalar.profile[0] != '\0');
741 if (simCtx->verificationDiffusivity.enabled) {
742 if (strcmp(simCtx->eulerianSource, "analytical") != 0) {
743 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
744 "verification diffusivity overrides require -euler_field_source \"analytical\".");
745 }
746 if (strcmp(simCtx->verificationDiffusivity.mode, "analytical") != 0) {
747 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
748 "Unsupported -verification_diffusivity_mode '%s'. Only 'analytical' is supported.",
750 }
751 if (strcmp(simCtx->verificationDiffusivity.profile, "LINEAR_X") != 0) {
752 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
753 "Unsupported -verification_diffusivity_profile '%s'. Only 'LINEAR_X' is supported.",
755 }
756 }
757 if (simCtx->verificationScalar.enabled) {
758 if (strcmp(simCtx->eulerianSource, "analytical") != 0) {
759 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
760 "verification scalar overrides require -euler_field_source \"analytical\".");
761 }
762 if (strcmp(simCtx->verificationScalar.mode, "analytical") != 0) {
763 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
764 "Unsupported -verification_scalar_mode '%s'. Only 'analytical' is supported.",
765 simCtx->verificationScalar.mode);
766 }
767 if (strcmp(simCtx->verificationScalar.profile, "CONSTANT") == 0) {
768 if (!verification_scalar_value_set) {
769 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
770 "verification scalar profile CONSTANT requires -verification_scalar_value.");
771 }
772 } else if (strcmp(simCtx->verificationScalar.profile, "LINEAR_X") == 0) {
773 if (!verification_scalar_phi0_set || !verification_scalar_slope_x_set) {
774 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
775 "verification scalar profile LINEAR_X requires -verification_scalar_phi0 and -verification_scalar_slope_x.");
776 }
777 } else if (strcmp(simCtx->verificationScalar.profile, "SIN_PRODUCT") == 0) {
778 if (!verification_scalar_amplitude_set || !verification_scalar_kx_set ||
779 !verification_scalar_ky_set || !verification_scalar_kz_set) {
780 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
781 "verification scalar profile SIN_PRODUCT requires -verification_scalar_amplitude, -verification_scalar_kx, -verification_scalar_ky, and -verification_scalar_kz.");
782 }
783 } else {
784 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
785 "Unsupported -verification_scalar_profile '%s'. Supported profiles: CONSTANT, LINEAR_X, SIN_PRODUCT.",
787 }
788 }
789 // NOTE: cdisx,cdisy,cdisz haven't been parsed, add if necessary.
790
791 // --- Group 6
792 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 6: Physical & Geometric Parameters \n");
793 ierr = PetscOptionsGetReal(NULL,NULL,"-schmidt_number",&simCtx->schmidt_number,NULL);CHKERRQ(ierr);
794 ierr = PetscOptionsGetReal(NULL,NULL,"-turb_schmidt_number",&simCtx->Turbulent_schmidt_number,NULL);CHKERRQ(ierr);
795 ierr = PetscOptionsGetInt(NULL, NULL, "-no_of_bodies", &simCtx->NumberOfBodies, NULL); CHKERRQ(ierr);
796 ierr = PetscOptionsGetReal(NULL,NULL,"-wall_roughness",&simCtx->wall_roughness_height,NULL);CHKERRQ(ierr);
797 // NOTE: angle is not parsed in the original code, it set programmatically. We will follow that.
798 // NOTE: max_angle is calculated based on other flags (like MHV) in the legacy code.
799 // We will defer that logic to a later setup stage and not parse them directly.
800 // The Scaling Information is calculated here
801 ierr = ParseScalingInformation(simCtx); CHKERRQ(ierr);
802
803 // --- Group 7
804 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 7: Grid, Domain, and Boundary Condition Settings \n");
805 ierr = PetscOptionsGetInt(NULL, NULL, "-nblk", &simCtx->block_number, NULL); CHKERRQ(ierr); // This is also a modern option
806 ierr = PetscOptionsGetInt(NULL, NULL, "-inlet", &simCtx->inletprofile, NULL); CHKERRQ(ierr);
807 ierr = PetscOptionsGetInt(NULL, NULL, "-Ogrid", &simCtx->Ogrid, NULL); CHKERRQ(ierr);
808 // NOTE: channelz was not parsed, likely set programmatically. We will omit its parsing call.
809 ierr = PetscOptionsGetInt(NULL, NULL, "-grid1d", &simCtx->grid1d, NULL); CHKERRQ(ierr);
810 ierr = PetscOptionsGetBool(NULL, NULL, "-grid", &simCtx->generate_grid, NULL); CHKERRQ(ierr);
811 ierr = PetscOptionsGetString(NULL, NULL, "-grid_file", simCtx->grid_file, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
812 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_x", &simCtx->da_procs_x, NULL); CHKERRQ(ierr);
813 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_y", &simCtx->da_procs_y, NULL); CHKERRQ(ierr);
814 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_z", &simCtx->da_procs_z, NULL); CHKERRQ(ierr);
815 ierr = PetscOptionsGetInt(NULL, NULL, "-pbc_domain", &simCtx->blkpbc, NULL); CHKERRQ(ierr);
816 // NOTE: pseudo_periodic was not parsed. We will omit its parsing call.
817 ierr = PetscOptionsGetReal(NULL, NULL, "-grid_rotation_angle", &simCtx->grid_rotation_angle, NULL); CHKERRQ(ierr);
818 ierr = PetscOptionsGetReal(NULL, NULL, "-Croty", &simCtx->Croty, NULL); CHKERRQ(ierr);
819 ierr = PetscOptionsGetReal(NULL, NULL, "-Crotz", &simCtx->Crotz, NULL); CHKERRQ(ierr);
820 PetscBool bcs_flg;
821 char file_list_str[PETSC_MAX_PATH_LEN * 10]; // Buffer for comma-separated list
822
823 ierr = PetscOptionsGetString(NULL, NULL, "-bcs_files", file_list_str, sizeof(file_list_str), &bcs_flg); CHKERRQ(ierr);
824 ierr = PetscOptionsGetReal(NULL, NULL, "-U_bc", &simCtx->U_bc, NULL); CHKERRQ(ierr);
825
826 if (bcs_flg) {
827 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Found -bcs_files option, overriding default.\n");
828
829 // A. Clean up the default memory we allocated in Phase 1.
830 ierr = PetscFree(simCtx->bcs_files[0]); CHKERRQ(ierr);
831 ierr = PetscFree(simCtx->bcs_files); CHKERRQ(ierr);
832 simCtx->num_bcs_files = 0;
833 simCtx->bcs_files = NULL;
834
835 // B. Parse the user-provided comma-separated list.
836 char *token;
837 char *str_copy;
838 ierr = PetscStrallocpy(file_list_str, &str_copy); CHKERRQ(ierr);
839
840 // First pass: count the number of files.
841 token = strtok(str_copy, ",");
842 while (token) {
843 simCtx->num_bcs_files++;
844 token = strtok(NULL, ",");
845 }
846 ierr = PetscFree(str_copy); CHKERRQ(ierr);
847
848 // Second pass: allocate memory and store the filenames.
849 ierr = PetscMalloc1(simCtx->num_bcs_files, &simCtx->bcs_files); CHKERRQ(ierr);
850 ierr = PetscStrallocpy(file_list_str, &str_copy); CHKERRQ(ierr);
851 token = strtok(str_copy, ",");
852 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
853 ierr = PetscStrallocpy(token, &simCtx->bcs_files[i]); CHKERRQ(ierr);
854 token = strtok(NULL, ",");
855 }
856 ierr = PetscFree(str_copy); CHKERRQ(ierr);
857 }
858
859
860 // --- Group 8
861 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 8: Turbulence Modeling (LES/RANS) \n");
862 PetscInt temp_les_model;
863 ierr = PetscOptionsGetInt(NULL, NULL, "-les", &temp_les_model, NULL); CHKERRQ(ierr);
864 simCtx->les = (LESModelType)temp_les_model;
865 ierr = PetscOptionsGetInt(NULL, NULL, "-rans", &simCtx->rans, NULL); CHKERRQ(ierr);
866 ierr = PetscOptionsGetInt(NULL, NULL, "-wallfunction", &simCtx->wallfunction, NULL); CHKERRQ(ierr);
867 ierr = PetscOptionsGetInt(NULL, NULL, "-mixed", &simCtx->mixed, NULL); CHKERRQ(ierr);
868 ierr = PetscOptionsGetInt(NULL, NULL, "-clark", &simCtx->clark, NULL); CHKERRQ(ierr);
869 ierr = PetscOptionsGetInt(NULL, NULL, "-dynamic_freq", &simCtx->dynamic_freq, NULL); CHKERRQ(ierr);
870 ierr = PetscOptionsGetReal(NULL, NULL, "-max_cs", &simCtx->max_cs, NULL); CHKERRQ(ierr);
871 ierr = PetscOptionsGetReal(NULL, NULL, "-const_cs", &simCtx->Const_CS, NULL); CHKERRQ(ierr);
872 ierr = PetscOptionsGetInt(NULL, NULL, "-testfilter_ik", &simCtx->testfilter_ik, NULL); CHKERRQ(ierr);
873 ierr = PetscOptionsGetInt(NULL, NULL, "-testfilter_1d", &simCtx->testfilter_1d, NULL); CHKERRQ(ierr);
874 ierr = PetscOptionsGetInt(NULL, NULL, "-i_homo_filter", &simCtx->i_homo_filter, NULL); CHKERRQ(ierr);
875 ierr = PetscOptionsGetInt(NULL, NULL, "-j_homo_filter", &simCtx->j_homo_filter, NULL); CHKERRQ(ierr);
876 ierr = PetscOptionsGetInt(NULL, NULL, "-k_homo_filter", &simCtx->k_homo_filter, NULL); CHKERRQ(ierr);
877 ierr = PetscOptionsGetBool(NULL, NULL, "-averaging", &simCtx->averaging, NULL); CHKERRQ(ierr);
878
879 // --- Group 9
880 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 9: Particle / DMSwarm Data & Settings \n");
881 ierr = PetscOptionsGetInt(NULL, NULL, "-numParticles", &simCtx->np, NULL); CHKERRQ(ierr);
882 ierr = PetscOptionsGetBool(NULL, NULL, "-read_fields", &simCtx->readFields, NULL); CHKERRQ(ierr);
883 PetscInt temp_pinit = (PetscInt)PARTICLE_INIT_SURFACE_RANDOM;
884 ierr = PetscOptionsGetInt(NULL, NULL, "-pinit", &temp_pinit, NULL); CHKERRQ(ierr);
886 PetscInt temp_interp = (PetscInt)INTERP_TRILINEAR;
887 ierr = PetscOptionsGetInt(NULL, NULL, "-interpolation_method", &temp_interp, NULL); CHKERRQ(ierr);
888 simCtx->interpolationMethod = (InterpolationMethod)temp_interp;
889 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Interpolation method: %s\n",
890 simCtx->interpolationMethod == INTERP_TRILINEAR ? "Trilinear (direct cell-center)" : "CornerAveraged (legacy)");
891 ierr = PetscOptionsGetReal(NULL, NULL, "-psrc_x", &simCtx->psrc_x, NULL); CHKERRQ(ierr);
892 ierr = PetscOptionsGetReal(NULL, NULL, "-psrc_y", &simCtx->psrc_y, NULL); CHKERRQ(ierr);
893 ierr = PetscOptionsGetReal(NULL, NULL, "-psrc_z", &simCtx->psrc_z, NULL); CHKERRQ(ierr);
894 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Particle initialization mode: %s. Point source: (%.6f, %.6f, %.6f)\n",
896 simCtx->psrc_x, simCtx->psrc_y, simCtx->psrc_z);
897 ierr = PetscOptionsGetString(NULL,NULL,"-particle_restart_mode",simCtx->particleRestartMode,sizeof(simCtx->particleRestartMode),NULL); CHKERRQ(ierr);
898 // Validation for Particle Restart Mode
899 if (strcmp(simCtx->particleRestartMode, "load") != 0 && strcmp(simCtx->particleRestartMode, "init") != 0) {
900 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -particle_restart_mode. Must be 'load' or 'init'. You provided '%s'.", simCtx->particleRestartMode);
901 }
902 ierr = InitializeBrownianRNG(simCtx); CHKERRQ(ierr);
903 // --- Group 10
904 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 10: Immersed Boundary & FSI Data Object Pointers \n");
905 ierr = PetscOptionsGetBool(NULL, NULL, "-rs_fsi", &simCtx->rstart_fsi, NULL); CHKERRQ(ierr);
906 ierr = PetscOptionsGetInt(NULL, NULL, "-duplicate", &simCtx->duplicate, NULL); CHKERRQ(ierr);
907
908 // --- Group 11
909 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 11: Top-Level Managers & Custom Configuration \n");
910 ierr = PetscOptionsGetInt(NULL, NULL, "-logfreq", &simCtx->LoggingFrequency, NULL); CHKERRQ(ierr);
911
912 if (simCtx->num_bcs_files != simCtx->block_number) {
913 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP, "Number of BC files (%d) does not match number of blocks (%d). Use -bcs_files \"file1.dat,file2.dat,...\".", simCtx->num_bcs_files, simCtx->block_number);
914 }
915
916 // --- Group 12
917 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 12: Post-Processing Information.\n");
918 // This logic determines the Post Processing configuration and STORES it in simCtx for later reference and cleanup.
919 ierr = PetscOptionsGetString(NULL,NULL,"-postprocessing_config_file",simCtx->PostprocessingControlFile,PETSC_MAX_PATH_LEN,NULL); CHKERRQ(ierr);
920 /* Parse post settings for both solver and post-processor binaries using the single pre-allocated pps object. */
921 ierr = ParsePostProcessingSettings(simCtx);
922
923 // === 5. Dependent Parameter Calculations ================================
924 // Some parameters depend on others, so we calculate them here.
925 simCtx->StartTime = (PetscReal)simCtx->StartStep*simCtx->dt;
926 simCtx->ti = simCtx->StartTime;
927 simCtx->step = simCtx->StartStep;
928
929 // === 5. Log Summary and Finalize Setup ==================================
930 LOG_ALLOW(GLOBAL, LOG_DEBUG, "-- Console Output Functions [Total : %d] : --\n", simCtx->nAllowed);
931 for (PetscInt i = 0; i < simCtx->nAllowed; ++i) {
932 LOG_ALLOW(GLOBAL, LOG_DEBUG, " [%2d] «%s»\n", i, simCtx->allowedFuncs[i]);
933 }
934
935 LOG_ALLOW(GLOBAL, LOG_INFO, "Configuration complete. Key parameters:\n");
936 LOG_ALLOW(GLOBAL, LOG_INFO, " - Run mode: %s\n", simCtx->OnlySetup ? "SETUP ONLY" : "Full Simulation");
937 LOG_ALLOW(GLOBAL, LOG_INFO, " - Time steps: %d (from %d to %d)\n", simCtx->StepsToRun, simCtx->StartStep, simCtx->StartStep + simCtx->StepsToRun);
938 LOG_ALLOW(GLOBAL, LOG_INFO, " - Time step size (dt): %g\n", simCtx->dt);
939 if (simCtx->tiout > 0) {
940 LOG_ALLOW(GLOBAL, LOG_INFO, " - Field/restart output cadence: every %d step(s)\n", simCtx->tiout);
941 } else {
942 LOG_ALLOW(GLOBAL, LOG_INFO, " - Field/restart output cadence: DISABLED\n");
943 }
944 LOG_ALLOW(GLOBAL, LOG_INFO, " - Immersed Boundary: %s\n", simCtx->immersed ? "ENABLED" : "DISABLED");
945 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particles: %d\n", simCtx->np);
946 if (simCtx->np > 0) {
947 if (simCtx->particleConsoleOutputFreq > 0) {
948 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle console cadence: every %d step(s)\n", simCtx->particleConsoleOutputFreq);
949 } else {
950 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle console cadence: DISABLED\n");
951 }
952 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle console row subsampling: every %d particle(s)\n", simCtx->LoggingFrequency);
953 }
954 if (simCtx->StartStep > 0 && simCtx->np > 0) {
955 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle Restart Mode: %s\n", simCtx->particleRestartMode);
956 }
957
958 // --- Initialize PETSc's internal performance logging stage ---
959 ierr = PetscLogDefaultBegin(); CHKERRQ(ierr); // REDUNDANT but safe.
960 ierr = PetscMemorySetGetMaximumUsage(); CHKERRQ(ierr);
961
962 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Finished CreateSimulationContext successfully on rank %d.\n", simCtx->rank);
963
965 PetscFunctionReturn(0);
966}
PetscErrorCode ParsePostProcessingSettings(SimCtx *simCtx)
Initializes post-processing settings from a config file and command-line overrides.
Definition io.c:2264
PetscErrorCode ParseScalingInformation(SimCtx *simCtx)
Parses physical scaling parameters from command-line options.
Definition io.c:2412
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
Definition logging.c:152
#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 LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:199
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
Definition logging.c:116
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:827
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:83
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
Definition logging.c:596
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:1927
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:28
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
@ 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:818
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Helper function to convert ParticleInitialization to a string representation.
Definition logging.c:723
PetscErrorCode InitializeBrownianRNG(SimCtx *simCtx)
Internal helper implementation: InitializeBrownianRNG().
Definition setup.c:3386
PetscBool RuntimeWalltimeGuardParsePositiveSeconds(const char *text, PetscReal *seconds_out)
Implementation of RuntimeWalltimeGuardParsePositiveSeconds().
Definition setup.c:18
LESModelType
Identifies the six logical faces of a structured computational block.
Definition variables.h:518
@ NO_LES_MODEL
Definition variables.h:519
PetscReal icVelocityPhysical
Definition variables.h:747
PetscInt MHV
Definition variables.h:720
PetscInt turbine
Definition variables.h:720
PetscBool mom_nk_monitor_history
Definition variables.h:740
PetscInt fishcyl
Definition variables.h:720
PetscInt clark
Definition variables.h:790
PetscInt movefsi
Definition variables.h:714
PetscBool continueMode
Definition variables.h:701
PetscInt moveframe
Definition variables.h:715
PetscInt TwoD
Definition variables.h:715
PetscInt pseudo_periodic
Definition variables.h:769
PetscInt fish_c
Definition variables.h:720
PetscInt dgf_z
Definition variables.h:716
PetscReal poisson_tol
Definition variables.h:729
PetscBool profilingFinalSummary
Definition variables.h:837
PetscReal schmidt_number
Definition variables.h:765
PetscMPIInt rank
Definition variables.h:687
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:836
PetscInt fish
Definition variables.h:720
PetscInt LV
Definition variables.h:720
PetscReal angle
Definition variables.h:760
PetscReal Turbulent_schmidt_number
Definition variables.h:765
PetscInt64 searchLocatedCount
Definition variables.h:239
PetscInt thin
Definition variables.h:715
PetscInt grid1d
Definition variables.h:768
PetscInt block_number
Definition variables.h:768
PetscReal mom_rtol
Definition variables.h:726
PetscInt64 searchLostCount
Definition variables.h:240
PetscInt da_procs_z
Definition variables.h:774
PetscInt blkpbc
Definition variables.h:769
PetscInt sediment
Definition variables.h:714
PetscReal targetVolumetricFlux
Definition variables.h:780
PetscBool walltimeGuardActive
Definition variables.h:839
PetscReal mom_last_lambda_max
Definition variables.h:739
PetscInt channelz
Definition variables.h:721
char euler_subdir[PETSC_MAX_PATH_LEN]
Definition variables.h:707
PetscReal walltimeGuardWarmupTotalSeconds
Definition variables.h:847
PetscReal forceScalingFactor
Definition variables.h:779
PetscReal pseudo_cfl_reduction_factor
Definition variables.h:733
InitialConditionMode initialConditionMode
Definition variables.h:742
PetscInt rans
Definition variables.h:789
ParticleInitializationType
Enumerator to identify the particle initialization strategy.
Definition variables.h:549
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:550
PetscReal StartTime
Definition variables.h:698
PetscInt dgf_az
Definition variables.h:716
PetscReal * solutionConvergenceMeanSpeedHistory
Definition variables.h:753
PetscReal FluxOutSum
Definition variables.h:777
PetscBool walltimeGuardHasEWMA
Definition variables.h:849
PetscReal CMy_c
Definition variables.h:761
FlowDirection flowDirection
Definition variables.h:746
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:852
char ** bcs_files
Definition variables.h:776
PetscReal boundaryVelocityCorrection
Definition variables.h:782
PetscReal max_angle
Definition variables.h:760
PetscReal min_pseudo_cfl
Definition variables.h:734
PetscInt64 boundaryClampCount
Definition variables.h:246
PetscInt particlesLostLastStep
Definition variables.h:803
PetscInt duplicate
Definition variables.h:818
PetscInt tiout
Definition variables.h:696
PetscReal walltimeGuardMinSeconds
Definition variables.h:842
char allowedFile[PETSC_MAX_PATH_LEN]
Definition variables.h:822
PetscInt da_procs_y
Definition variables.h:774
PetscInt64 traversalStepsSum
Definition variables.h:241
PetscBool mom_last_converged
Definition variables.h:738
PetscInt testfilter_1d
Definition variables.h:792
PetscReal psrc_x
Definition variables.h:762
PetscReal ren
Definition variables.h:732
PetscReal Crotz
Definition variables.h:772
PetscInt mixed
Definition variables.h:790
PetscInt solutionConvergenceSamplesRecorded
Definition variables.h:752
IBMVNodes * ibmv
Definition variables.h:815
PetscInt64 searchPopulation
Definition variables.h:238
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:706
PetscReal * solutionConvergenceMeanKEHistory
Definition variables.h:754
PetscReal walltimeGuardLatestStepSeconds
Definition variables.h:851
PetscReal dt
Definition variables.h:699
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:853
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
Definition variables.h:854
PetscInt occupiedCellCount
Definition variables.h:807
PetscInt StepsToRun
Definition variables.h:695
char profilingTimestepMode[32]
Definition variables.h:835
PetscInt k_periodic
Definition variables.h:769
PetscInt inletprofile
Definition variables.h:768
PetscReal bulkVelocityCorrection
Definition variables.h:781
PetscReal cdisy
Definition variables.h:732
PetscReal mom_atol
Definition variables.h:726
PetscBool rstart_fsi
Definition variables.h:817
PetscInt currentSettlementPass
Definition variables.h:250
PetscInt np
Definition variables.h:796
PetscBool averaging
Definition variables.h:793
PetscBool no_pseudo_cfl_backtrack
Definition variables.h:736
PetscReal C_IEM
Definition variables.h:811
PetscInt ccc
Definition variables.h:785
PetscReal ratio
Definition variables.h:786
PetscInt mg_idx
Definition variables.h:727
PetscInt StartStep
Definition variables.h:694
PetscInt mg_MAX_IT
Definition variables.h:727
PetscBool OnlySetup
Definition variables.h:700
PetscInt rotatefsi
Definition variables.h:714
@ MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK
Definition variables.h:534
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:533
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:535
PetscInt solutionConvergencePeriodSteps
Definition variables.h:750
PetscReal cdisz
Definition variables.h:732
PetscScalar x
Definition variables.h:101
PetscInt64 reSearchCount
Definition variables.h:242
PetscInt dgf_x
Definition variables.h:716
char * current_io_directory
Definition variables.h:711
PetscInt pizza
Definition variables.h:720
PetscReal MaxDiv
Definition variables.h:828
char grid_file[PETSC_MAX_PATH_LEN]
Definition variables.h:773
PetscReal max_cs
Definition variables.h:791
PetscInt invicid
Definition variables.h:715
char ** allowedFuncs
Definition variables.h:824
PetscInt64 bboxGuessFallbackCount
Definition variables.h:248
InterpolationMethod interpolationMethod
Definition variables.h:801
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
Definition variables.h:762
PetscInt mg_poItr
Definition variables.h:727
PetscInt STRONG_COUPLING
Definition variables.h:730
VerificationScalarConfig verificationScalar
Definition variables.h:756
PetscReal max_pseudo_cfl
Definition variables.h:734
PetscInt MaxDivx
Definition variables.h:829
PetscInt poisson
Definition variables.h:728
PetscInt k_homo_filter
Definition variables.h:792
char profilingSelectedFuncsFile[PETSC_MAX_PATH_LEN]
Definition variables.h:831
PetscInt MaxDivy
Definition variables.h:829
PetscInt NumberOfBodies
Definition variables.h:759
char particleRestartMode[16]
Definition variables.h:802
PetscInt Ogrid
Definition variables.h:768
PetscInt64 bboxGuessSuccessCount
Definition variables.h:247
char particle_subdir[PETSC_MAX_PATH_LEN]
Definition variables.h:708
PetscInt MaxDivz
Definition variables.h:829
BoundingBox * bboxlist
Definition variables.h:799
PetscInt j_homo_filter
Definition variables.h:792
PetscInt eel
Definition variables.h:720
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:709
PetscInt MaxDivFlatArg
Definition variables.h:829
PetscReal FluxInSum
Definition variables.h:777
PetscInt walltimeGuardCompletedSteps
Definition variables.h:846
PetscInt64 maxParticlePassDepth
Definition variables.h:249
PetscReal CMz_c
Definition variables.h:761
PetscInt64 maxTraversalSteps
Definition variables.h:243
PetscBool generate_grid
Definition variables.h:770
Cmpnts AnalyticalUniformVelocity
Definition variables.h:748
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:704
PetscReal imp_stol
Definition variables.h:726
PetscInt nAllowed
Definition variables.h:825
PetscBool walltimeGuardEnabled
Definition variables.h:838
PetscReal wall_roughness_height
Definition variables.h:764
PetscBool useProfilingSelectedFuncsCfg
Definition variables.h:832
PetscInt walltimeGuardWarmupSteps
Definition variables.h:840
ParticleInitializationType ParticleInitialization
Definition variables.h:800
PetscReal mom_dt_jameson_residual_norm_noise_allowance_factor
Definition variables.h:735
PetscScalar z
Definition variables.h:101
InterpolationMethod
Selects the grid-to-particle interpolation method.
Definition variables.h:562
@ INTERP_TRILINEAR
Definition variables.h:563
PetscReal Const_CS
Definition variables.h:791
PetscInt i_homo_filter
Definition variables.h:792
PetscInt wallfunction
Definition variables.h:790
PetscInt rheology
Definition variables.h:714
PetscReal Flux_in
Definition variables.h:760
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
Definition variables.h:855
char ** profilingSelectedFuncs
Definition variables.h:833
PetscReal cdisx
Definition variables.h:732
PetscInt dgf_ax
Definition variables.h:716
PetscInt mglevels
Definition variables.h:727
PetscInt num_bcs_files
Definition variables.h:775
DM dm_swarm
Definition variables.h:798
PetscBool useCfg
Definition variables.h:823
PetscReal psrc_y
Definition variables.h:762
PetscBool readFields
Definition variables.h:797
PetscInt solutionConvergenceWindowSteps
Definition variables.h:751
PetscInt central
Definition variables.h:730
PetscReal Fluxsum
Definition variables.h:777
FlowDirection
Primary flow direction for streamwise IC and Poiseuille modes.
Definition variables.h:270
@ FLOW_DIR_UNSET
Definition variables.h:277
PetscReal pseudo_cfl_growth_factor
Definition variables.h:733
PetscReal Croty
Definition variables.h:772
PetscInt particlesLostCumulative
Definition variables.h:804
PetscInt nProfilingSelectedFuncs
Definition variables.h:834
PetscInt particlesMigratedLastStep
Definition variables.h:806
char initialConditionDirectory[PETSC_MAX_PATH_LEN]
Definition variables.h:744
PetscReal grid_rotation_angle
Definition variables.h:771
PetscInt dynamic_freq
Definition variables.h:790
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:717
PetscInt da_procs_x
Definition variables.h:774
PetscReal U_bc
Definition variables.h:784
PetscReal walltimeGuardWarmupAverageSeconds
Definition variables.h:848
InitialConditionMode
Selects the algorithm used to populate a fresh Eulerian velocity field.
Definition variables.h:149
@ IC_MODE_FILE
Definition variables.h:154
@ IC_MODE_ZERO
Definition variables.h:150
PetscInt particleConsoleOutputFreq
Definition variables.h:697
Cmpnts InitialConstantContra
Definition variables.h:745
SearchMetricsState searchMetrics
Definition variables.h:809
PetscInt i_periodic
Definition variables.h:769
PetscReal mom_resid_rtol
Definition variables.h:726
PetscReal runtimeMemoryLogPreviousProcessMB
Previous local process memory sample in MB.
Definition variables.h:856
PetscInt step
Definition variables.h:692
PetscReal walltimeGuardEWMASeconds
Definition variables.h:850
PetscReal AreaOutSum
Definition variables.h:783
PetscInt dgf_ay
Definition variables.h:716
PetscInt mom_max_pseudo_steps
Definition variables.h:725
PetscRandom BrownianMotionRNG
Definition variables.h:810
PetscInt testfilter_ik
Definition variables.h:792
PetscInt hydro
Definition variables.h:720
PostProcessParams * pps
Definition variables.h:860
PetscInt migrationPassesLastStep
Definition variables.h:805
PetscScalar y
Definition variables.h:101
InitialConditionField
Selects the authoritative velocity representation in a staged file IC.
Definition variables.h:158
@ IC_FIELD_UCONT
Definition variables.h:160
@ IC_FIELD_UCAT
Definition variables.h:159
PetscMPIInt size
Definition variables.h:688
char _io_context_buffer[PETSC_MAX_PATH_LEN]
Definition variables.h:710
PetscReal walltimeGuardLimitSeconds
Definition variables.h:845
PetscBool ps_ksp_pic_monitor_true_residual
Definition variables.h:741
PetscReal walltimeGuardEstimatorAlpha
Definition variables.h:843
PetscInt les
Definition variables.h:789
@ SOLUTION_CONVERGENCE_TRANSIENT
Definition variables.h:545
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:543
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:544
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:542
PetscInt mg_preItr
Definition variables.h:727
PetscReal mom_ratio_ema_alpha
Definition variables.h:737
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:749
PetscViewer logviewer
Definition variables.h:702
PetscInt64 searchAttempts
Definition variables.h:237
InitialConditionField initialConditionField
Definition variables.h:743
PetscInt64 tieBreakCount
Definition variables.h:245
PetscReal mom_resid_atol
Definition variables.h:726
PetscInt cop
Definition variables.h:720
PetscReal ti
Definition variables.h:693
PetscReal walltimeGuardMultiplier
Definition variables.h:841
PetscInt Pipe
Definition variables.h:720
PetscInt rotateframe
Definition variables.h:715
IBMNodes * ibm
Definition variables.h:814
PetscReal AreaInSum
Definition variables.h:783
MomentumSolverType mom_solver_type
Definition variables.h:724
PetscReal summationRHS
Definition variables.h:827
PetscInt immersed
Definition variables.h:714
PetscInt64 maxTraversalFailCount
Definition variables.h:244
char PostprocessingControlFile[PETSC_MAX_PATH_LEN]
Definition variables.h:859
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:705
VerificationDiffusivityConfig verificationDiffusivity
Definition variables.h:755
PetscInt blank
Definition variables.h:715
PetscInt dgf_y
Definition variables.h:716
PetscReal walltimeGuardJobStartEpochSeconds
Definition variables.h:844
PetscReal pseudo_cfl
Definition variables.h:732
PetscInt LoggingFrequency
Definition variables.h:826
PetscReal CMx_c
Definition variables.h:761
PetscReal drivingForceMagnitude
Definition variables.h:779
PetscReal particleLoadImbalance
Definition variables.h:808
PetscInt j_periodic
Definition variables.h:769
PetscInt wing
Definition variables.h:720
FSInfo * fsi
Definition variables.h:816
The master context for the entire simulation.
Definition variables.h:684
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RuntimeWalltimeGuardParsePositiveSeconds()

PetscBool RuntimeWalltimeGuardParsePositiveSeconds ( const char *  text,
PetscReal *  seconds_out 
)

Parse a positive floating-point seconds value from runtime metadata.

This helper is used for shell-exported walltime metadata such as PICURV_JOB_START_EPOCH and PICURV_WALLTIME_LIMIT_SECONDS.

Parameters
[in]textString to parse.
[out]seconds_outParsed positive seconds value when successful.
Returns
PetscBool PETSC_TRUE when parsing succeeds, else PETSC_FALSE.

Parse a positive floating-point seconds value from runtime metadata.

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

See also
RuntimeWalltimeGuardParsePositiveSeconds()

Definition at line 18 of file setup.c.

19{
20 char *endptr = NULL;
21 double parsed_value;
22
23 if (seconds_out) *seconds_out = 0.0;
24 if (!text || text[0] == '\0') return PETSC_FALSE;
25
26 errno = 0;
27 parsed_value = strtod(text, &endptr);
28 if (endptr == text || errno == ERANGE || !isfinite(parsed_value) || parsed_value <= 0.0) {
29 return PETSC_FALSE;
30 }
31
32 while (*endptr != '\0' && isspace((unsigned char)*endptr)) {
33 endptr++;
34 }
35 if (*endptr != '\0') return PETSC_FALSE;
36
37 if (seconds_out) *seconds_out = (PetscReal)parsed_value;
38 return PETSC_TRUE;
39}
Here is the caller graph for this function:

◆ SetupSimulationEnvironment()

PetscErrorCode SetupSimulationEnvironment ( SimCtx simCtx)

Verifies and prepares the complete I/O environment for a simulation run.

This function performs a comprehensive series of checks and setup actions to ensure a valid and clean environment. It is parallel-safe; all filesystem operations and checks are performed by Rank 0, with collective error handling.

The function's responsibilities include:

  1. Checking Mandatory Inputs: Verifies existence of grid and BCs files.
  2. Checking Optional Inputs: Warns if optional config files (whitelist, profile) are missing.
  3. Validating Run Mode Paths: Ensures restart_dir or post-processing source directories exist when needed.
  4. Preparing Log Directory: Creates the log directory and cleans it of previous logs.
  5. Preparing Output Directories: Creates the main output directory and its required subdirectories.
Parameters
[in]simCtxThe fully configured SimulationContext object.
Returns
PetscErrorCode Returns 0 on success, or a non-zero error code if a mandatory file/directory is missing or a critical operation fails.

Verifies and prepares the complete I/O environment for a simulation run.

Local to this translation unit.

Definition at line 1026 of file setup.c.

1027{
1028 PetscErrorCode ierr;
1029 PetscMPIInt rank;
1030 PetscBool exists;
1031
1032 PetscFunctionBeginUser;
1033 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1034
1035 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Setting up simulation environment ---\n");
1036
1037 /* =====================================================================
1038 * Phase 1: Check for all required and optional INPUT files.
1039 * ===================================================================== */
1040 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 1: Verifying input files...\n");
1041
1042 // --- Mandatory Inputs ---
1043 if (!simCtx->generate_grid) {
1044 ierr = VerifyPathExistence(simCtx->grid_file, PETSC_FALSE, PETSC_FALSE, "Grid file", &exists); CHKERRQ(ierr);
1045 }
1046 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
1047 char desc[128];
1048 ierr = PetscSNPrintf(desc, sizeof(desc), "BCS file #%d", i + 1); CHKERRQ(ierr);
1049 ierr = VerifyPathExistence(simCtx->bcs_files[i], PETSC_FALSE, PETSC_FALSE, desc, &exists); CHKERRQ(ierr);
1050 }
1051
1052 // --- Optional Inputs (these produce warnings if missing) ---
1053 if (simCtx->useCfg) {
1054 ierr = VerifyPathExistence(simCtx->allowedFile, PETSC_FALSE, PETSC_TRUE, "Whitelist config file", &exists); CHKERRQ(ierr);
1055 }
1056 if (simCtx->useProfilingSelectedFuncsCfg) {
1057 ierr = VerifyPathExistence(simCtx->profilingSelectedFuncsFile, PETSC_FALSE, PETSC_TRUE, "Profiling config file", &exists); CHKERRQ(ierr);
1058 }
1059 if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
1060 ierr = VerifyPathExistence(simCtx->PostprocessingControlFile, PETSC_FALSE, PETSC_TRUE, "Post-processing control file", &exists); CHKERRQ(ierr);
1061 }
1062
1063
1064 /* =====================================================================
1065 * Phase 2: Validate directories specific to the execution mode.
1066 * ===================================================================== */
1067 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 2: Verifying execution mode directories...\n");
1068 // The data source directory must exist if we intend to load any data from it.
1069 // This is true if:
1070 // 1. We are restarting from a previous time step (StartStep > 0), which implies
1071 // loading Eulerian fields and/or particle fields.
1072 // 2. We are starting from t=0 but are explicitly told to load the initial
1073 // Eulerian fields from a file (eulerianSource == "load").
1074 if (simCtx->StartStep > 0 || strcmp(simCtx->eulerianSource,"load")== 0){ // If this is a restart run
1075 ierr = VerifyPathExistence(simCtx->restart_dir, PETSC_TRUE, PETSC_FALSE, "Restart source directory", &exists); CHKERRQ(ierr);
1076 }
1077 if (simCtx->StartStep == 0 && strcmp(simCtx->eulerianSource, "solve") == 0 &&
1079 ierr = VerifyPathExistence(simCtx->initialConditionDirectory, PETSC_TRUE, PETSC_FALSE,
1080 "Initial-condition source directory", &exists); CHKERRQ(ierr);
1081 }
1082 if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
1083 ierr = VerifyPathExistence(simCtx->pps->source_dir, PETSC_TRUE, PETSC_FALSE, "Post-processing source directory", &exists); CHKERRQ(ierr);
1084 }
1085
1086 /* =====================================================================
1087 * Phase 3: Create and prepare all OUTPUT directories.
1088 * ===================================================================== */
1089 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 3: Preparing output directories...\n");
1090
1091 if (rank == 0){
1092 if(simCtx->exec_mode == EXEC_MODE_SOLVER){
1093 // --- Prepare Log Directory ---
1094 if (!simCtx->continueMode) {
1095 // Only wipe logs on fresh runs; continue mode appends to existing logs.
1096 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating/cleaning log directory: %s\n", simCtx->log_dir);
1097 ierr = PetscRMTree(simCtx->log_dir); // Wipes the directory and its contents
1098 if (ierr) { /* Ignore file-not-found error, but fail on others */
1099 PetscError(PETSC_COMM_SELF, __LINE__, __FUNCT__, __FILE__, ierr, PETSC_ERROR_INITIAL, "Could not remove existing log directory '%s'. Check permissions.", simCtx->log_dir);
1100 }
1101 ierr = PetscMkdir(simCtx->log_dir); CHKERRQ(ierr);
1102 } else {
1103 // In continue mode, ensure log directory exists but don't wipe it.
1104 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Continue mode: preserving existing log directory: %s\n", simCtx->log_dir);
1105 ierr = PetscMkdir(simCtx->log_dir); CHKERRQ(ierr);
1106 }
1107
1108 // --- Prepare Output Directories ---
1109 char path_buffer[PETSC_MAX_PATH_LEN];
1110
1111 // 1. Check/Create the main output directory
1112 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying main output directory: %s\n", simCtx->output_dir);
1113 ierr = PetscTestDirectory(simCtx->output_dir, 'r', &exists); CHKERRQ(ierr);
1114 if (!exists) {
1115 LOG_ALLOW(GLOBAL, LOG_INFO, "Output directory not found. Creating: %s\n", simCtx->output_dir);
1116 ierr = PetscMkdir(simCtx->output_dir); CHKERRQ(ierr);
1117 }
1118
1119 // 2. Check/Create the Eulerian subdirectory
1120 ierr = PetscSNPrintf(path_buffer, sizeof(path_buffer), "%s/%s", simCtx->output_dir, simCtx->euler_subdir); CHKERRQ(ierr);
1121 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying Eulerian subdirectory: %s\n", path_buffer);
1122 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1123 if (!exists) {
1124 LOG_ALLOW(GLOBAL, LOG_INFO, "Eulerian subdirectory not found. Creating: %s\n", path_buffer);
1125 ierr = PetscMkdir(path_buffer); CHKERRQ(ierr);
1126 }
1127
1128 // 3. Check/Create the Particle subdirectory if needed
1129 if (simCtx->np > 0) {
1130 ierr = PetscSNPrintf(path_buffer, sizeof(path_buffer), "%s/%s", simCtx->output_dir, simCtx->particle_subdir); CHKERRQ(ierr);
1131 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying Particle subdirectory: %s\n", path_buffer);
1132 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1133 if (!exists) {
1134 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle subdirectory not found. Creating: %s\n", path_buffer);
1135 ierr = PetscMkdir(path_buffer); CHKERRQ(ierr);
1136 }
1137 }
1138 } else if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1139 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Preparing post-processing output directories ...\n");
1140
1141 PostProcessParams *pps = simCtx->pps;
1142 char path_buffer[PETSC_MAX_PATH_LEN];
1143
1144 const char *last_slash_euler = strrchr(pps->output_prefix, '/');
1145 if(last_slash_euler){
1146 size_t dir_len = last_slash_euler - pps->output_prefix;
1147 if(dir_len > 0){
1148 if(dir_len >= sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing output prefix path is too long.");
1149 strncpy(path_buffer, pps->output_prefix, dir_len);
1150 path_buffer[dir_len] = '\0';
1151
1152 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1153 if (!exists){
1154 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Eulerian output directory: %s\n", path_buffer);
1155 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
1156 }
1157 }
1158 }
1159
1160 // Particle output directory
1161 if(pps->outputParticles){
1162 const char *last_slash_particle = strrchr(pps->particle_output_prefix, '/');
1163 if(last_slash_particle){
1164 size_t dir_len = last_slash_particle - pps->particle_output_prefix;
1165 if(dir_len > 0){
1166 if(dir_len > sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing particle output prefix path is too long.");
1167 strncpy(path_buffer, pps->particle_output_prefix, dir_len);
1168 path_buffer[dir_len] = '\0';
1169
1170 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1171
1172 if (!exists){
1173 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Particle output directory: %s\n", path_buffer);
1174 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
1175 }
1176 }
1177 }
1178 }
1179
1180 // Statistics output directory
1181 if(pps->statistics_pipeline[0] != '\0'){
1182 const char *last_slash_stats = strrchr(pps->statistics_output_prefix, '/');
1183 if(last_slash_stats){
1184 size_t dir_len = last_slash_stats - pps->statistics_output_prefix;
1185 if(dir_len > 0){
1186 if(dir_len >= sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing statistics output prefix path is too long.");
1187 strncpy(path_buffer, pps->statistics_output_prefix, dir_len);
1188 path_buffer[dir_len] = '\0';
1189
1190 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1191 if (!exists){
1192 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Statistics output directory: %s\n", path_buffer);
1193 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
1194 }
1195 }
1196 }
1197 }
1198 }
1199 }
1200
1201 // Synchronize all processes before proceeding
1202 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRMPI(ierr);
1203
1204 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Environment setup complete ---\n");
1205
1206 PetscFunctionReturn(0);
1207}
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.
Definition io.c:741
static PetscErrorCode PetscMkdirRecursive(const char *path)
Internal helper implementation: PetscMkdirRecursive().
Definition setup.c:974
#define __FUNCT__
Definition setup.c:143
char statistics_output_prefix[256]
basename for CSV output, e.g.
Definition variables.h:616
char particle_output_prefix[256]
Definition variables.h:611
char output_prefix[256]
Definition variables.h:608
char statistics_pipeline[1024]
e.g.
Definition variables.h:615
char source_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:596
PetscBool outputParticles
Definition variables.h:602
@ EXEC_MODE_SOLVER
Definition variables.h:657
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:658
ExecutionMode exec_mode
Definition variables.h:703
Holds all configuration parameters for a post-processing run.
Definition variables.h:594
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetupGridAndSolvers()

PetscErrorCode SetupGridAndSolvers ( SimCtx simCtx)

The main orchestrator for setting up all grid-related components.

This function is the high-level driver for creating the entire computational domain, including the multigrid hierarchy, PETSc DMDA and Vec objects, and calculating all necessary grid metrics.

Parameters
simCtxThe fully configured SimulationContext.
Returns
PetscErrorCode

The main orchestrator for setting up all grid-related components.

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

See also
SetupGridAndSolvers()

Definition at line 1350 of file setup.c.

1351{
1352 PetscErrorCode ierr;
1353 PetscFunctionBeginUser;
1354
1356
1357 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Starting Grid and Solvers Setup ---\n");
1358
1359 // Phase 1: Allocate the UserMG and UserCtx hierarchy
1360 ierr = AllocateContextHierarchy(simCtx); CHKERRQ(ierr);
1361
1362 ierr = DefineAllGridDimensions(simCtx); CHKERRQ(ierr);
1363 ierr = InitializeAllGridDMs(simCtx); CHKERRQ(ierr);
1364 ierr = AssignAllGridCoordinates(simCtx); CHKERRQ(ierr);
1365 ierr = CreateAndInitializeAllVectors(simCtx); CHKERRQ(ierr);
1366 ierr = SetupSolverParameters(simCtx); CHKERRQ(ierr);
1367 ierr = InitializeSolutionConvergenceState(simCtx); CHKERRQ(ierr);
1368
1369 // NOTE: CalculateAllGridMetrics is now called inside SetupBoundaryConditions (not here) to ensure:
1370 // 1. Boundary condition configuration data (boundary_faces) is available for periodic BC corrections
1371 // 2. Computed metrics are available for inlet/outlet area calculations
1372 // This resolves the circular dependency between BC setup and metric calculations.
1373
1374 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Grid and Solvers Setup Complete ---\n");
1375
1377 PetscFunctionReturn(0);
1378}
PetscErrorCode DefineAllGridDimensions(SimCtx *simCtx)
Orchestrates the parsing and setting of grid dimensions for all blocks.
Definition grid.c:57
PetscErrorCode InitializeAllGridDMs(SimCtx *simCtx)
Orchestrates the creation of DMDA objects for every block and multigrid level.
Definition grid.c:235
PetscErrorCode AssignAllGridCoordinates(SimCtx *simCtx)
Orchestrates the assignment of physical coordinates to all DMDA objects.
Definition grid.c:317
static PetscErrorCode SetupSolverParameters(SimCtx *simCtx)
Internal helper implementation: SetupSolverParameters().
Definition setup.c:1318
PetscErrorCode CreateAndInitializeAllVectors(SimCtx *simCtx)
Internal helper implementation: CreateAndInitializeAllVectors().
Definition setup.c:1387
PetscErrorCode InitializeSolutionConvergenceState(SimCtx *simCtx)
Implementation of InitializeSolutionConvergenceState().
Definition setup.c:47
static PetscErrorCode AllocateContextHierarchy(SimCtx *simCtx)
Internal helper implementation: AllocateContextHierarchy().
Definition setup.c:1215
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CreateAndInitializeAllVectors()

PetscErrorCode CreateAndInitializeAllVectors ( SimCtx simCtx)

Creates and initializes all PETSc Vec objects for all fields.

This function iterates through every UserCtx in the multigrid and multi-block hierarchy. For each context, it creates the comprehensive set of global and local PETSc Vecs required by the flow solver (e.g., Ucont, P, Nvert, metrics, turbulence fields, etc.). Each vector is initialized to zero.

Parameters
simCtxThe master SimCtx, containing the configured UserCtx hierarchy.
Returns
PetscErrorCode

Creates and initializes all PETSc Vec objects for all fields.

Local to this translation unit.

Definition at line 1387 of file setup.c.

1388{
1389 PetscErrorCode ierr;
1390 UserMG *usermg = &simCtx->usermg;
1391 MGCtx *mgctx = usermg->mgctx;
1392 PetscInt nblk = simCtx->block_number;
1393
1394 PetscFunctionBeginUser;
1395
1397
1398 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating and initializing all simulation vectors...\n");
1399
1400 for (PetscInt level = usermg->mglevels-1; level >=0; level--) {
1401 for (PetscInt bi = 0; bi < nblk; bi++) {
1402 UserCtx *user = &mgctx[level].user[bi];
1403
1404 if(!user->da || !user->fda) {
1405 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "DMs not properly initialized in UserCtx before vector creation.");
1406 }
1407
1408 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Rank %d: Creating vectors for level %d, block %d\n", simCtx->rank, level, bi);
1409
1410 // --- Group A: Primary Flow Fields (Global and Local) ---
1411 // These are the core solution variables.
1412 ierr = DMCreateGlobalVector(user->fda, &user->Ucont); CHKERRQ(ierr); ierr = VecSet(user->Ucont, 0.0); CHKERRQ(ierr);
1413 ierr = DMCreateGlobalVector(user->fda, &user->Ucat); CHKERRQ(ierr); ierr = VecSet(user->Ucat, 0.0); CHKERRQ(ierr);
1414 ierr = DMCreateGlobalVector(user->da, &user->P); CHKERRQ(ierr); ierr = VecSet(user->P, 0.0); CHKERRQ(ierr);
1415 ierr = DMCreateGlobalVector(user->da, &user->Nvert); CHKERRQ(ierr); ierr = VecSet(user->Nvert, 0.0); CHKERRQ(ierr);
1416
1417 ierr = DMCreateLocalVector(user->fda, &user->lUcont); CHKERRQ(ierr); ierr = VecSet(user->lUcont, 0.0); CHKERRQ(ierr);
1418 ierr = DMCreateLocalVector(user->fda, &user->lUcat); CHKERRQ(ierr); ierr = VecSet(user->lUcat, 0.0); CHKERRQ(ierr);
1419 ierr = DMCreateLocalVector(user->da, &user->lP); CHKERRQ(ierr); ierr = VecSet(user->lP, 0.0); CHKERRQ(ierr);
1420 ierr = DMCreateLocalVector(user->da, &user->lNvert); CHKERRQ(ierr); ierr = VecSet(user->lNvert, 0.0); CHKERRQ(ierr);
1421
1422 // -- Group A2: Derived Flow Fields (Global and Local) ---
1423 ierr = VecDuplicate(user->P,&user->Diffusivity); CHKERRQ(ierr); ierr = VecSet(user->Diffusivity, 0.0); CHKERRQ(ierr);
1424 ierr = VecDuplicate(user->lP,&user->lDiffusivity); CHKERRQ(ierr); ierr = VecSet(user->lDiffusivity, 0.0); CHKERRQ(ierr);
1425 ierr = VecDuplicate(user->Ucat,&user->DiffusivityGradient); CHKERRQ(ierr); ierr = VecSet(user->DiffusivityGradient, 0.0); CHKERRQ(ierr);
1426 ierr = VecDuplicate(user->lUcat,&user->lDiffusivityGradient); CHKERRQ(ierr); ierr = VecSet(user->lDiffusivityGradient, 0.0); CHKERRQ(ierr);
1427
1428 // -- Group B: Solver Work Vectors (Global and Local) ---
1429 ierr = VecDuplicate(user->P, &user->Phi); CHKERRQ(ierr); ierr = VecSet(user->Phi, 0.0); CHKERRQ(ierr);
1430 ierr = VecDuplicate(user->lP, &user->lPhi); CHKERRQ(ierr); ierr = VecSet(user->lPhi, 0.0); CHKERRQ(ierr);
1431
1432 // --- Group C: Time-Stepping & Workspace Fields (Finest Level Only) ---
1433 if (level == usermg->mglevels - 1) {
1434 ierr = VecDuplicate(user->Ucont, &user->Ucont_o); CHKERRQ(ierr); ierr = VecSet(user->Ucont_o, 0.0); CHKERRQ(ierr);
1435 ierr = VecDuplicate(user->Ucont, &user->Ucont_rm1); CHKERRQ(ierr); ierr = VecSet(user->Ucont_rm1, 0.0); CHKERRQ(ierr);
1436 ierr = VecDuplicate(user->Ucat, &user->Ucat_o); CHKERRQ(ierr); ierr = VecSet(user->Ucat_o, 0.0); CHKERRQ(ierr);
1437 ierr = VecDuplicate(user->P, &user->P_o); CHKERRQ(ierr); ierr = VecSet(user->P_o, 0.0); CHKERRQ(ierr);
1438 ierr = VecDuplicate(user->lUcont, &user->lUcont_o); CHKERRQ(ierr); ierr = VecSet(user->lUcont_o, 0.0); CHKERRQ(ierr);
1439 ierr = VecDuplicate(user->lUcont, &user->lUcont_rm1); CHKERRQ(ierr); ierr = VecSet(user->lUcont_rm1, 0.0); CHKERRQ(ierr);
1440 ierr = DMCreateLocalVector(user->da, &user->lNvert_o); CHKERRQ(ierr); ierr = VecSet(user->lNvert_o, 0.0); CHKERRQ(ierr);
1441 ierr = VecDuplicate(user->Nvert, &user->Nvert_o); CHKERRQ(ierr); ierr = VecSet(user->Nvert_o, 0.0); CHKERRQ(ierr);
1442 }
1443
1444 // --- Group D: Grid Metrics (Face-Centered) ---
1445 ierr = DMCreateGlobalVector(user->fda, &user->Csi); CHKERRQ(ierr); ierr = VecSet(user->Csi, 0.0); CHKERRQ(ierr);
1446 ierr = VecDuplicate(user->Csi, &user->Eta); CHKERRQ(ierr); ierr = VecSet(user->Eta, 0.0); CHKERRQ(ierr);
1447 ierr = VecDuplicate(user->Csi, &user->Zet); CHKERRQ(ierr); ierr = VecSet(user->Zet, 0.0); CHKERRQ(ierr);
1448 ierr = DMCreateGlobalVector(user->da, &user->Aj); CHKERRQ(ierr); ierr = VecSet(user->Aj, 0.0); CHKERRQ(ierr);
1449
1450 ierr = DMCreateLocalVector(user->fda, &user->lCsi); CHKERRQ(ierr); ierr = VecSet(user->lCsi, 0.0); CHKERRQ(ierr);
1451 ierr = VecDuplicate(user->lCsi, &user->lEta); CHKERRQ(ierr); ierr = VecSet(user->lEta, 0.0); CHKERRQ(ierr);
1452 ierr = VecDuplicate(user->lCsi, &user->lZet); CHKERRQ(ierr); ierr = VecSet(user->lZet, 0.0); CHKERRQ(ierr);
1453 ierr = DMCreateLocalVector(user->da, &user->lAj); CHKERRQ(ierr); ierr = VecSet(user->lAj, 0.0); CHKERRQ(ierr);
1454
1455
1456 // --- Group E: Grid Metrics (Face-Centered) ---
1457 // Vector metrics are duplicated from Csi (DOF=3, fda-based)
1458 ierr = VecDuplicate(user->Csi, &user->ICsi); CHKERRQ(ierr); ierr = VecSet(user->ICsi, 0.0); CHKERRQ(ierr);
1459 ierr = VecDuplicate(user->Csi, &user->IEta); CHKERRQ(ierr); ierr = VecSet(user->IEta, 0.0); CHKERRQ(ierr);
1460 ierr = VecDuplicate(user->Csi, &user->IZet); CHKERRQ(ierr); ierr = VecSet(user->IZet, 0.0); CHKERRQ(ierr);
1461 ierr = VecDuplicate(user->Csi, &user->JCsi); CHKERRQ(ierr); ierr = VecSet(user->JCsi, 0.0); CHKERRQ(ierr);
1462 ierr = VecDuplicate(user->Csi, &user->JEta); CHKERRQ(ierr); ierr = VecSet(user->JEta, 0.0); CHKERRQ(ierr);
1463 ierr = VecDuplicate(user->Csi, &user->JZet); CHKERRQ(ierr); ierr = VecSet(user->JZet, 0.0); CHKERRQ(ierr);
1464 ierr = VecDuplicate(user->Csi, &user->KCsi); CHKERRQ(ierr); ierr = VecSet(user->KCsi, 0.0); CHKERRQ(ierr);
1465 ierr = VecDuplicate(user->Csi, &user->KEta); CHKERRQ(ierr); ierr = VecSet(user->KEta, 0.0); CHKERRQ(ierr);
1466 ierr = VecDuplicate(user->Csi, &user->KZet); CHKERRQ(ierr); ierr = VecSet(user->KZet, 0.0); CHKERRQ(ierr);
1467 // Scalar metrics are duplicated from Aj (DOF=1, da-based)
1468 ierr = VecDuplicate(user->Aj, &user->IAj); CHKERRQ(ierr); ierr = VecSet(user->IAj, 0.0); CHKERRQ(ierr);
1469 ierr = VecDuplicate(user->Aj, &user->JAj); CHKERRQ(ierr); ierr = VecSet(user->JAj, 0.0); CHKERRQ(ierr);
1470 ierr = VecDuplicate(user->Aj, &user->KAj); CHKERRQ(ierr); ierr = VecSet(user->KAj, 0.0); CHKERRQ(ierr);
1471
1472 ierr = VecDuplicate(user->lCsi, &user->lICsi); CHKERRQ(ierr); ierr = VecSet(user->lICsi, 0.0); CHKERRQ(ierr);
1473 ierr = VecDuplicate(user->lCsi, &user->lIEta); CHKERRQ(ierr); ierr = VecSet(user->lIEta, 0.0); CHKERRQ(ierr);
1474 ierr = VecDuplicate(user->lCsi, &user->lIZet); CHKERRQ(ierr); ierr = VecSet(user->lIZet, 0.0); CHKERRQ(ierr);
1475 ierr = VecDuplicate(user->lCsi, &user->lJCsi); CHKERRQ(ierr); ierr = VecSet(user->lJCsi, 0.0); CHKERRQ(ierr);
1476 ierr = VecDuplicate(user->lCsi, &user->lJEta); CHKERRQ(ierr); ierr = VecSet(user->lJEta, 0.0); CHKERRQ(ierr);
1477 ierr = VecDuplicate(user->lCsi, &user->lJZet); CHKERRQ(ierr); ierr = VecSet(user->lJZet, 0.0); CHKERRQ(ierr);
1478 ierr = VecDuplicate(user->lCsi, &user->lKCsi); CHKERRQ(ierr); ierr = VecSet(user->lKCsi, 0.0); CHKERRQ(ierr);
1479 ierr = VecDuplicate(user->lCsi, &user->lKEta); CHKERRQ(ierr); ierr = VecSet(user->lKEta, 0.0); CHKERRQ(ierr);
1480 ierr = VecDuplicate(user->lCsi, &user->lKZet); CHKERRQ(ierr); ierr = VecSet(user->lKZet, 0.0); CHKERRQ(ierr);
1481
1482 ierr = VecDuplicate(user->lAj, &user->lIAj); CHKERRQ(ierr); ierr = VecSet(user->lIAj, 0.0); CHKERRQ(ierr);
1483 ierr = VecDuplicate(user->lAj, &user->lJAj); CHKERRQ(ierr); ierr = VecSet(user->lJAj, 0.0); CHKERRQ(ierr);
1484 ierr = VecDuplicate(user->lAj, &user->lKAj); CHKERRQ(ierr); ierr = VecSet(user->lKAj, 0.0); CHKERRQ(ierr);
1485
1486 // --- Group F: Cell/Face Center Coordinates and Grid Spacing ---
1487 ierr = DMCreateGlobalVector(user->fda, &user->Cent); CHKERRQ(ierr); ierr = VecSet(user->Cent, 0.0); CHKERRQ(ierr);
1488 ierr = DMCreateLocalVector(user->fda, &user->lCent); CHKERRQ(ierr); ierr = VecSet(user->lCent, 0.0); CHKERRQ(ierr);
1489
1490 ierr = VecDuplicate(user->Cent, &user->GridSpace); CHKERRQ(ierr); ierr = VecSet(user->GridSpace, 0.0); CHKERRQ(ierr);
1491 ierr = VecDuplicate(user->lCent, &user->lGridSpace); CHKERRQ(ierr); ierr = VecSet(user->lGridSpace, 0.0); CHKERRQ(ierr);
1492
1493 ierr = VecDuplicate(user->Cent, &user->Centx); CHKERRQ(ierr); ierr = VecSet(user->Centx, 0.0); CHKERRQ(ierr);
1494 ierr = VecDuplicate(user->Cent, &user->Centy); CHKERRQ(ierr); ierr = VecSet(user->Centy, 0.0); CHKERRQ(ierr);
1495 ierr = VecDuplicate(user->Cent, &user->Centz); CHKERRQ(ierr); ierr = VecSet(user->Centz, 0.0); CHKERRQ(ierr);
1496 ierr = VecDuplicate(user->lCent, &user->lCentx); CHKERRQ(ierr); ierr = VecSet(user->lCentx, 0.0); CHKERRQ(ierr);
1497 ierr = VecDuplicate(user->lCent, &user->lCenty); CHKERRQ(ierr); ierr = VecSet(user->lCenty, 0.0); CHKERRQ(ierr);
1498 ierr = VecDuplicate(user->lCent, &user->lCentz); CHKERRQ(ierr); ierr = VecSet(user->lCentz, 0.0); CHKERRQ(ierr);
1499
1500 if(level == usermg->mglevels -1){
1501 // --- Group G: Turbulence Models (Finest Level Only) ---
1502 if (simCtx->les || simCtx->rans) {
1503 ierr = DMCreateGlobalVector(user->da, &user->Nu_t); CHKERRQ(ierr); ierr = VecSet(user->Nu_t, 0.0); CHKERRQ(ierr);
1504 ierr = DMCreateLocalVector(user->da, &user->lNu_t); CHKERRQ(ierr); ierr = VecSet(user->lNu_t, 0.0); CHKERRQ(ierr);
1505 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Turbulence viscosity (Nu_t) vectors created for LES/RANS model.\n");
1506 if(simCtx->les){
1507 ierr = DMCreateGlobalVector(user->da,&user->CS); CHKERRQ(ierr); ierr = VecSet(user->CS,0.0); CHKERRQ(ierr);
1508 ierr = DMCreateLocalVector(user->da,&user->lCs); CHKERRQ(ierr); ierr = VecSet(user->lCs,0.0); CHKERRQ(ierr);
1509 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Smagorinsky constant (CS) vectors created for LES model.\n");
1510 }
1511
1512 if(simCtx->wallfunction){
1513 ierr = DMCreateLocalVector(user->fda,&user->lFriction_Velocity); CHKERRQ(ierr); ierr = VecSet(user->lFriction_Velocity,0.0);
1514 }
1515 // Add K_Omega etc. here as needed
1516
1517 // Note: Add any other vectors from the legacy MG_Initial here as needed.
1518 // For example: Rhs, Forcing, turbulence Vecs (K_Omega, Nu_t)...
1519
1520 }
1521 // --- Group H: Particle Methods
1522 if(simCtx->np>0){
1523 ierr = DMCreateGlobalVector(user->da,&user->ParticleCount); CHKERRQ(ierr); ierr = VecSet(user->ParticleCount,0.0); CHKERRQ(ierr);
1524 ierr = DMCreateLocalVector(user->da,&user->lParticleCount); CHKERRQ(ierr); ierr = VecSet(user->lParticleCount,0.0); CHKERRQ(ierr);
1525 // Scalar field to hold particle scalar property (e.g., temperature, concentration)
1526 ierr = DMCreateGlobalVector(user->da,&user->Psi); CHKERRQ(ierr); ierr = VecSet(user->Psi,0.0); CHKERRQ(ierr);
1527 ierr = DMCreateLocalVector(user->da,&user->lPsi); CHKERRQ(ierr); ierr = VecSet(user->lPsi,0.0); CHKERRQ(ierr);
1528 LOG_ALLOW(GLOBAL,LOG_DEBUG,"ParticleCount & Scalar(Psi) created for %d particles.\n",simCtx->np);
1529 }
1530 }
1531 // --- Group I: Boundary Condition vectors ---
1532 ierr = DMCreateGlobalVector(user->fda, &user->Bcs.Ubcs); CHKERRQ(ierr);
1533 ierr = VecSet(user->Bcs.Ubcs, 0.0); CHKERRQ(ierr);
1534 ierr = DMCreateGlobalVector(user->fda, &user->Bcs.Uch); CHKERRQ(ierr);
1535 ierr = VecSet(user->Bcs.Uch, 0.0); CHKERRQ(ierr);
1536
1537 if(level == usermg->mglevels - 1){
1538 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1539 LOG_ALLOW(LOCAL, LOG_DEBUG, "Post-processor mode detected. Allocating derived field vectors.\n");
1540
1541 ierr = VecDuplicate(user->P, &user->P_nodal); CHKERRQ(ierr);
1542 ierr = VecSet(user->P_nodal, 0.0); CHKERRQ(ierr);
1543
1544 ierr = VecDuplicate(user->Ucat, &user->Ucat_nodal); CHKERRQ(ierr);
1545 ierr = VecSet(user->Ucat_nodal, 0.0); CHKERRQ(ierr);
1546
1547 ierr = VecDuplicate(user->P, &user->Qcrit); CHKERRQ(ierr);
1548 ierr = VecSet(user->Qcrit, 0.0); CHKERRQ(ierr);
1549
1550 LOG_ALLOW(LOCAL, LOG_DEBUG, "Derived field vectors P_nodal, Ucat_nodal, and Qcrit created.\n");
1551
1552 if(simCtx->np>0){
1553 ierr = VecDuplicate(user->Psi, &user->Psi_nodal); CHKERRQ(ierr);
1554 ierr = VecSet(user->Psi_nodal, 0.0); CHKERRQ(ierr);
1555
1556 LOG_ALLOW(LOCAL, LOG_DEBUG, "Derived field vector Psi_nodal created for particle scalar property.\n");
1557
1558 }
1559 }else{
1560 user->P_nodal = NULL;
1561 user->Ucat_nodal = NULL;
1562 user->Qcrit = NULL;
1563 user->Psi_nodal = NULL;
1564 }
1565 }
1566
1567 }
1568}
1569
1570 LOG_ALLOW(GLOBAL, LOG_INFO, "All simulation vectors created and initialized.\n");
1571
1573 PetscFunctionReturn(0);
1574}
Vec lFriction_Velocity
Definition variables.h:900
Vec lDiffusivityGradient
Definition variables.h:908
Vec lCent
Definition variables.h:927
Vec GridSpace
Definition variables.h:927
Vec P_nodal
Definition variables.h:957
Vec JCsi
Definition variables.h:931
Vec KAj
Definition variables.h:932
UserCtx * user
Definition variables.h:569
Vec JEta
Definition variables.h:931
Vec Zet
Definition variables.h:927
Vec lIEta
Definition variables.h:930
Vec lIZet
Definition variables.h:930
Vec lNvert
Definition variables.h:904
Vec Phi
Definition variables.h:904
Vec IZet
Definition variables.h:930
Vec Centz
Definition variables.h:928
Vec IEta
Definition variables.h:930
Vec lZet
Definition variables.h:927
UserMG usermg
Definition variables.h:821
Vec Csi
Definition variables.h:927
Vec lUcont_rm1
Definition variables.h:912
Vec lIAj
Definition variables.h:930
Vec lKEta
Definition variables.h:932
Vec Ucat_nodal
Definition variables.h:958
Vec lPsi
Definition variables.h:953
Vec DiffusivityGradient
Definition variables.h:908
Vec lJCsi
Definition variables.h:931
Vec lCs
Definition variables.h:935
Vec Ucont
Definition variables.h:904
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
Definition variables.h:121
Vec Qcrit
Definition variables.h:959
Vec JZet
Definition variables.h:931
Vec Centx
Definition variables.h:928
BCS Bcs
Definition variables.h:899
Vec lPhi
Definition variables.h:904
Vec lParticleCount
Definition variables.h:952
Vec lUcont_o
Definition variables.h:911
Vec Ucat_o
Definition variables.h:911
Vec lKZet
Definition variables.h:932
Vec Eta
Definition variables.h:927
Vec lNu_t
Definition variables.h:935
Vec Nu_t
Definition variables.h:935
Vec lJEta
Definition variables.h:931
Vec lCsi
Definition variables.h:927
Vec lGridSpace
Definition variables.h:927
Vec ICsi
Definition variables.h:930
Vec lKCsi
Definition variables.h:932
Vec Ucat
Definition variables.h:904
Vec ParticleCount
Definition variables.h:952
Vec Ucont_o
Definition variables.h:911
Vec lCenty
Definition variables.h:929
PetscInt mglevels
Definition variables.h:576
Vec lJZet
Definition variables.h:931
Vec Nvert_o
Definition variables.h:911
Vec IAj
Definition variables.h:930
Vec Psi_nodal
Definition variables.h:960
Vec JAj
Definition variables.h:931
Vec KEta
Definition variables.h:932
Vec lCentx
Definition variables.h:929
Vec Ucont_rm1
Definition variables.h:912
Vec lUcont
Definition variables.h:904
Vec Diffusivity
Definition variables.h:907
Vec lAj
Definition variables.h:927
Vec lICsi
Definition variables.h:930
Vec lUcat
Definition variables.h:904
Vec lEta
Definition variables.h:927
Vec KZet
Definition variables.h:932
Vec Cent
Definition variables.h:927
Vec Nvert
Definition variables.h:904
Vec KCsi
Definition variables.h:932
MGCtx * mgctx
Definition variables.h:579
Vec lDiffusivity
Definition variables.h:907
Vec lNvert_o
Definition variables.h:911
Vec Centy
Definition variables.h:928
Vec lCentz
Definition variables.h:929
Vec lJAj
Definition variables.h:931
Vec lKAj
Definition variables.h:932
Vec Psi
Definition variables.h:953
Vec P_o
Definition variables.h:911
Vec Uch
Characteristic velocity for boundary conditions.
Definition variables.h:122
Context for Multigrid operations.
Definition variables.h:568
User-defined context containing data specific to a single computational grid level.
Definition variables.h:876
User-level context for managing the entire multigrid hierarchy.
Definition variables.h:575
Here is the caller graph for this function:

◆ UpdateLocalGhosts()

PetscErrorCode UpdateLocalGhosts ( UserCtx user,
const char *  fieldName 
)

Updates the local vector (including ghost points) from its corresponding global vector.

This function identifies the correct global vector, local vector, and DM based on the provided fieldName and performs the standard PETSc DMGlobalToLocalBegin/End sequence. For registered single-face-family and component-staggered fields, it then repairs the adjacent periodic ghost in each normal direction so central differences see the correct neighboring face. Cell-centered fields and tangential face directions retain PETSc's native periodic wraparound. Includes optional debugging output (max norms before/after).

Parameters
userThe UserCtx structure containing the vectors and DMs.
fieldNameThe name of the field to update ("Coordinates", "Ucat", "Ucont", "Ucont_o", "Ucont_rm1", "P", "Nvert", "Centx", etc.).
Returns
PetscErrorCode 0 on success, non-zero on failure.
Note
This function assumes the global vector associated with fieldName has already been populated with the desired data (including any boundary conditions and periodic duplicate planes). It scatters that current global state into the local vector; it does not repair stale global periodic duplicate planes.
Wider QUICK-style normal ghost layers require a separate dedicated exchange; this function repairs the adjacent layer used by central stencils.

Updates the local vector (including ghost points) from its corresponding global vector.

Local to this translation unit.

Definition at line 1755 of file setup.c.

1756{
1757 PetscErrorCode ierr;
1758 PetscMPIInt rank;
1759 Vec globalVec = NULL;
1760 Vec localVec = NULL;
1761 DM dm = NULL; // The DM associated with this field pair
1762 PetscInt dof = 0;
1763 char face_direction = '\0';
1764 PetscBool component_staggered = PETSC_FALSE;
1765
1766 PetscFunctionBeginUser; // Use User version for application code
1768 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1769 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Starting ghost update for field '%s'.\n", rank, fieldName);
1770
1771 // --- 1. Identify the correct Vectors and DM ---
1772 if (strcmp(fieldName, "Coordinates") == 0) {
1773 ierr = DMGetCoordinates(user->da, &globalVec); CHKERRQ(ierr);
1774 ierr = DMGetCoordinatesLocal(user->da, &localVec); CHKERRQ(ierr);
1775 dm = user->fda;
1776 dof = 3;
1777 } else if (strcmp(fieldName, "Ucat") == 0) {
1778 globalVec = user->Ucat;
1779 localVec = user->lUcat;
1780 dm = user->fda;
1781 dof = 3;
1782 } else if (strcmp(fieldName, "Ucont") == 0) {
1783 globalVec = user->Ucont;
1784 localVec = user->lUcont;
1785 dm = user->fda;
1786 dof = 3;
1787 component_staggered = PETSC_TRUE;
1788 } else if (strcmp(fieldName, "Ucont_o") == 0) {
1789 globalVec = user->Ucont_o;
1790 localVec = user->lUcont_o;
1791 dm = user->fda;
1792 dof = 3;
1793 component_staggered = PETSC_TRUE;
1794 } else if (strcmp(fieldName, "Ucont_rm1") == 0) {
1795 globalVec = user->Ucont_rm1;
1796 localVec = user->lUcont_rm1;
1797 dm = user->fda;
1798 dof = 3;
1799 component_staggered = PETSC_TRUE;
1800 } else if (strcmp(fieldName, "P") == 0) {
1801 globalVec = user->P;
1802 localVec = user->lP;
1803 dm = user->da;
1804 } else if (strcmp(fieldName, "Nu_t") == 0 || strcmp(fieldName, "Eddy Viscosity") == 0) {
1805 globalVec = user->Nu_t;
1806 localVec = user->lNu_t;
1807 dm = user->da;
1808 } else if (strcmp(fieldName, "CS") == 0 || strcmp(fieldName, "Cs") == 0) {
1809 globalVec = user->CS;
1810 localVec = user->lCs;
1811 dm = user->da;
1812 } else if (strcmp(fieldName, "Diffusivity") == 0) {
1813 globalVec = user->Diffusivity;
1814 localVec = user->lDiffusivity;
1815 dm = user->da;
1816 } else if (strcmp(fieldName, "DiffusivityGradient") == 0) {
1817 globalVec = user->DiffusivityGradient;
1818 localVec = user->lDiffusivityGradient;
1819 dm = user->fda;
1820 } else if (strcmp(fieldName, "Csi") == 0) {
1821 globalVec = user->Csi;
1822 localVec = user->lCsi;
1823 dm = user->fda;
1824 dof = 3;
1825 face_direction = 'i';
1826 } else if (strcmp(fieldName, "Eta") == 0) {
1827 globalVec = user->Eta;
1828 localVec = user->lEta;
1829 dm = user->fda;
1830 dof = 3;
1831 face_direction = 'j';
1832 } else if (strcmp(fieldName, "Zet") == 0) {
1833 globalVec = user->Zet;
1834 localVec = user->lZet;
1835 dm = user->fda;
1836 dof = 3;
1837 face_direction = 'k';
1838 }else if (strcmp(fieldName, "Nvert") == 0) {
1839 globalVec = user->Nvert;
1840 localVec = user->lNvert;
1841 dm = user->da;
1842 // Add other fields as needed
1843 } else if (strcmp(fieldName, "Aj") == 0) {
1844 globalVec = user->Aj;
1845 localVec = user->lAj;
1846 dm = user->da;
1847 } else if (strcmp(fieldName, "Cent") == 0) {
1848 globalVec = user->Cent;
1849 localVec = user->lCent;
1850 dm = user->fda;
1851 }else if (strcmp(fieldName, "GridSpace") == 0) {
1852 globalVec = user->GridSpace;
1853 localVec = user->lGridSpace;
1854 dm = user->fda;
1855 }else if (strcmp(fieldName, "Centx") == 0) {
1856 globalVec = user->Centx;
1857 localVec = user->lCentx;
1858 dm = user->fda;
1859 dof = 3;
1860 face_direction = 'i';
1861 }else if (strcmp(fieldName, "Centy") == 0) {
1862 globalVec = user->Centy;
1863 localVec = user->lCenty;
1864 dm = user->fda;
1865 dof = 3;
1866 face_direction = 'j';
1867 }else if (strcmp(fieldName, "Centz") == 0) {
1868 globalVec = user->Centz;
1869 localVec = user->lCentz;
1870 dm = user->fda;
1871 dof = 3;
1872 face_direction = 'k';
1873 }else if (strcmp(fieldName,"ICsi") == 0){
1874 globalVec = user->ICsi;
1875 localVec = user->lICsi;
1876 dm = user->fda;
1877 dof = 3;
1878 face_direction = 'i';
1879 }else if (strcmp(fieldName,"IEta") == 0){
1880 globalVec = user->IEta;
1881 localVec = user->lIEta;
1882 dm = user->fda;
1883 dof = 3;
1884 face_direction = 'i';
1885 }else if (strcmp(fieldName,"IZet") == 0){
1886 globalVec = user->IZet;
1887 localVec = user->lIZet;
1888 dm = user->fda;
1889 dof = 3;
1890 face_direction = 'i';
1891 }else if (strcmp(fieldName,"JCsi") == 0){
1892 globalVec = user->JCsi;
1893 localVec = user->lJCsi;
1894 dm = user->fda;
1895 dof = 3;
1896 face_direction = 'j';
1897 }else if (strcmp(fieldName,"JEta") == 0){
1898 globalVec = user->JEta;
1899 localVec = user->lJEta;
1900 dm = user->fda;
1901 dof = 3;
1902 face_direction = 'j';
1903 }else if (strcmp(fieldName,"JZet") == 0){
1904 globalVec = user->JZet;
1905 localVec = user->lJZet;
1906 dm = user->fda;
1907 dof = 3;
1908 face_direction = 'j';
1909 }else if (strcmp(fieldName,"KCsi") == 0){
1910 globalVec = user->KCsi;
1911 localVec = user->lKCsi;
1912 dm = user->fda;
1913 dof = 3;
1914 face_direction = 'k';
1915 }else if (strcmp(fieldName,"KEta") == 0){
1916 globalVec = user->KEta;
1917 localVec = user->lKEta;
1918 dm = user->fda;
1919 dof = 3;
1920 face_direction = 'k';
1921 }else if (strcmp(fieldName,"KZet") == 0){
1922 globalVec = user->KZet;
1923 localVec = user->lKZet;
1924 dm = user->fda;
1925 dof = 3;
1926 face_direction = 'k';
1927 }else if (strcmp(fieldName,"IAj") == 0){
1928 globalVec = user->IAj;
1929 localVec = user->lIAj;
1930 dm = user->da;
1931 dof = 1;
1932 face_direction = 'i';
1933 }else if (strcmp(fieldName,"JAj") == 0){
1934 globalVec = user->JAj;
1935 localVec = user->lJAj;
1936 dm = user->da;
1937 dof = 1;
1938 face_direction = 'j';
1939 }else if (strcmp(fieldName,"KAj") == 0){
1940 globalVec = user->KAj;
1941 localVec = user->lKAj;
1942 dm = user->da;
1943 dof = 1;
1944 face_direction = 'k';
1945 }else if (strcmp(fieldName,"Phi") == 0){ // Pressure correction term.
1946 globalVec = user->Phi;
1947 localVec = user->lPhi;
1948 dm = user->da;
1949 }else if (strcmp(fieldName,"Psi") == 0){ // Particle scalar property.
1950 globalVec = user->Psi;
1951 localVec = user->lPsi;
1952 dm = user->da;
1953 }else if (strcmp(fieldName,"Nvert_o") == 0){
1954 globalVec = user->Nvert_o;
1955 localVec = user->lNvert_o;
1956 dm = user->da;
1957 }else if (strcmp(fieldName,"ParticleCount") == 0){
1958 globalVec = user->ParticleCount;
1959 localVec = user->lParticleCount;
1960 dm = user->da;
1961 }else if (strcmp(fieldName,"K_Omega") == 0){
1962 globalVec = user->K_Omega;
1963 localVec = user->lK_Omega;
1964 dm = user->fda2;
1965 }else if (strcmp(fieldName,"K_Omega_o") == 0){
1966 globalVec = user->K_Omega_o;
1967 localVec = user->lK_Omega_o;
1968 dm = user->fda2;
1969 }else {
1970 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Field '%s' not recognized for ghost update.", fieldName);
1971 }
1972
1973 // --- 2. Check if components were found ---
1974 if (!globalVec) {
1975 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Global vector for field '%s' is NULL.", fieldName);
1976 }
1977 if (!localVec) {
1978 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Local vector for field '%s' is NULL.", fieldName);
1979 }
1980 if (!dm) {
1981 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM for field '%s' is NULL.", fieldName);
1982 }
1983
1984 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Identified components for '%s': DM=%p, GlobalVec=%p, LocalVec=%p.\n",
1985 rank, fieldName, (void*)dm, (void*)globalVec, (void*)localVec);
1986
1987 // --- 3. Optional Debugging: Norm Before Update ---
1988 // Use your logging convention check
1989 // if (get_log_level() >= LOG_LEVEL_DEBUG && is_function_allowed("UpdateLocalGhosts")) { // Example check
1990 if(get_log_level() == LOG_DEBUG && is_function_allowed(__func__)){
1991 PetscReal norm_global_before;
1992 ierr = VecNorm(globalVec, NORM_INFINITY, &norm_global_before); CHKERRQ(ierr);
1993 LOG_ALLOW(GLOBAL, LOG_INFO,"Max norm '%s' (Global) BEFORE Ghost Update: %g\n", fieldName, norm_global_before);
1994 // Optional: Norm of local vector before update (might contain old ghost values)
1995 // PetscReal norm_local_before;
1996 // ierr = VecNorm(localVec, NORM_INFINITY, &norm_local_before); CHKERRQ(ierr);
1997 // LOG_ALLOW(GLOBAL, LOG_DEBUG,"Max norm '%s' (Local) BEFORE Ghost Update: %g\n", fieldName, norm_local_before);
1998 }
1999
2000 // --- 4. Perform the Global-to-Local Transfer (Ghost Update) ---
2001 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Calling DMGlobalToLocalBegin/End for '%s'.\n", rank, fieldName);
2002 ierr = DMGlobalToLocalBegin(dm, globalVec, INSERT_VALUES, localVec); CHKERRQ(ierr);
2003 ierr = DMGlobalToLocalEnd(dm, globalVec, INSERT_VALUES, localVec); CHKERRQ(ierr);
2004 ierr = RepairPeriodicNormalFaceGhosts(user, dm, localVec, dof, face_direction,
2005 component_staggered); CHKERRQ(ierr);
2006 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Completed DMGlobalToLocalBegin/End for '%s'.\n", rank, fieldName);
2007
2008 // --- 5. Optional Debugging: Norm After Update ---
2009 // Use your logging convention check
2010 // if (get_log_level() >= LOG_LEVEL_DEBUG && is_function_allowed("UpdateLocalGhosts")) { // Example check
2011 if(get_log_level() == LOG_DEBUG && is_function_allowed(__func__)){ // Using your specific check
2012 PetscReal norm_local_after;
2013 ierr = VecNorm(localVec, NORM_INFINITY, &norm_local_after); CHKERRQ(ierr);
2014 LOG_ALLOW(GLOBAL, LOG_INFO,"Max norm '%s' (Local) AFTER Ghost Update: %g\n", fieldName, norm_local_after);
2015
2016 // --- 6. Optional Debugging: Specific Point Checks (Example for Ucat on Rank 0/1) ---
2017 // (Keep this conditional if it's only for specific debug scenarios)
2018 if (strcmp(fieldName, "Ucat") == 0) { // Only do detailed checks for Ucat for now
2019 PetscMPIInt rank_test;
2020 MPI_Comm_rank(PETSC_COMM_WORLD, &rank_test);
2021
2022 // Get Local Info needed for indexing checks
2023 DMDALocalInfo info_check;
2024 ierr = DMDAGetLocalInfo(dm, &info_check); CHKERRQ(ierr); // Use the correct dm
2025
2026 // Buffer for array pointer
2027 Cmpnts ***lUcat_arr_test = NULL;
2028 PetscErrorCode ierr_test = 0;
2029
2030 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Testing '%s' access immediately after ghost update...\n", rank_test, fieldName);
2031 ierr_test = DMDAVecGetArrayDOFRead(dm, localVec, &lUcat_arr_test); // Use correct dm and localVec
2032
2033 if (ierr_test) {
2034 LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR %d getting '%s' array after ghost update!\n", rank_test, ierr_test, fieldName);
2035 } else if (!lUcat_arr_test) {
2036 LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR NULL pointer getting '%s' array after ghost update!\n", rank_test, fieldName);
2037 }
2038 else {
2039 // Check owned interior point (e.g., first interior point)
2040 PetscInt k_int = info_check.zs + (info_check.zm > 1 ? 1 : 0); // Global k index (at least zs+1 if possible)
2041 PetscInt j_int = info_check.ys + (info_check.ym > 1 ? 1 : 0); // Global j index
2042 PetscInt i_int = info_check.xs + (info_check.xm > 1 ? 1 : 0); // Global i index
2043 // Ensure indices are within global bounds if domain is very small
2044 //if (k_int >= info_check.mz-1) k_int = info_check.mz-2; if (k_int < 1) k_int = 1;
2045 //if (j_int >= info_check.my-1) j_int = info_check.my-2; if (j_int < 1) j_int = 1;
2046 // if (i_int >= info_check.mx-1) i_int = info_check.mx-2; if (i_int < 1) i_int = 1;
2047 // clamp k_int to [1 .. mz-2]
2048 if (k_int >= info_check.mz - 1) {
2049 k_int = info_check.mz - 2;
2050 }
2051 if (k_int < 1) {
2052 k_int = 1;
2053 }
2054
2055 // clamp j_int to [1 .. my-2]
2056 if (j_int >= info_check.my - 1) {
2057 j_int = info_check.my - 2;
2058 }
2059 if (j_int < 1) {
2060 j_int = 1;
2061 }
2062
2063 // clamp i_int to [1 .. mx-2]
2064 if (i_int >= info_check.mx - 1) {
2065 i_int = info_check.mx - 2;
2066 }
2067 if (i_int < 1) {
2068 i_int = 1;
2069 }
2070
2071 // Only attempt read if indices are actually owned (relevant for multi-rank)
2072 if (k_int >= info_check.zs && k_int < info_check.zs + info_check.zm &&
2073 j_int >= info_check.ys && j_int < info_check.ys + info_check.ym &&
2074 i_int >= info_check.xs && i_int < info_check.xs + info_check.xm)
2075 {
2076 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Attempting test read OWNED INTERIOR [%d][%d][%d] (Global)\n", rank_test, k_int, j_int, i_int);
2077 Cmpnts test_val_owned_interior = lUcat_arr_test[k_int][j_int][i_int];
2078 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading owned interior: x=%g\n", rank_test, test_val_owned_interior.x);
2079 } else {
2080 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Skipping interior test read for non-owned index [%d][%d][%d].\n", rank_test, k_int, j_int, i_int);
2081 }
2082
2083
2084 // Check owned boundary point (e.g., first owned point)
2085 PetscInt k_bnd = info_check.zs; // Global k index
2086 PetscInt j_bnd = info_check.ys; // Global j index
2087 PetscInt i_bnd = info_check.xs; // Global i index
2088 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Attempting test read OWNED BOUNDARY [%d][%d][%d] (Global)\n", rank_test, k_bnd, j_bnd, i_bnd);
2089 Cmpnts test_val_owned_boundary = lUcat_arr_test[k_bnd][j_bnd][i_bnd];
2090 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading owned boundary: x=%g\n", rank_test, test_val_owned_boundary.x);
2091
2092
2093 // Check ghost point (e.g., one layer below in k, if applicable)
2094 if (info_check.zs > 0) { // Only if there's a rank below
2095 PetscInt k_ghost = info_check.zs - 1;
2096 PetscInt j_ghost = info_check.ys; // Use start of owned y, simple example
2097 PetscInt i_ghost = info_check.xs; // Use start of owned x, simple example
2098 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Attempting test read GHOST [%d][%d][%d] (Global)\n", rank_test, k_ghost, j_ghost, i_ghost);
2099 Cmpnts test_val_ghost = lUcat_arr_test[k_ghost][j_ghost][i_ghost];
2100 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading ghost: x=%g\n", rank_test, test_val_ghost.x);
2101 } else {
2102 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Skipping ghost test read (zs=0).\n", rank_test);
2103 }
2104
2105 // Restore the array
2106 ierr_test = DMDAVecRestoreArrayDOFRead(dm, localVec, &lUcat_arr_test);
2107 if(ierr_test){ LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR %d restoring '%s' array after test read!\n", rank_test, ierr_test, fieldName); }
2108 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Finished testing '%s' access.\n", rank_test, fieldName);
2109 }
2110 } // end if Ucat
2111 } // end debug logging check
2112
2113 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Completed ghost update for field '%s'.\n", rank, fieldName);
2115 PetscFunctionReturn(0);
2116}
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:183
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:84
static PetscErrorCode RepairPeriodicNormalFaceGhosts(UserCtx *user, DM dm, Vec local_vec, PetscInt dof, char face_direction, PetscBool component_staggered)
Repairs the adjacent normal ghost layer for periodic face-staggered data.
Definition setup.c:1586
Vec K_Omega_o
Definition variables.h:935
Vec K_Omega
Definition variables.h:935
Vec lK_Omega_o
Definition variables.h:935
Vec lK_Omega
Definition variables.h:935
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetupBoundaryConditions()

PetscErrorCode SetupBoundaryConditions ( SimCtx simCtx)

(Orchestrator) Sets up all boundary conditions for the simulation.

Parameters
simCtxSimulation context controlling the operation.
Returns
PetscErrorCode 0 on success.

(Orchestrator) Sets up all boundary conditions for the simulation.

Local to this translation unit.

Definition at line 2124 of file setup.c.

2125{
2126 PetscErrorCode ierr;
2127 PetscFunctionBeginUser;
2128
2130
2131 LOG_ALLOW(GLOBAL,LOG_INFO, "--- Setting up Boundary Conditions ---\n");
2132 // --- Phase 1: Parse and initialize BC configuration for all blocks ---
2133 LOG_ALLOW(GLOBAL,LOG_INFO,"Parsing BC configuration files and initializing boundary condition data structures.\n");
2134 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels-1].user;
2135 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
2136 LOG_ALLOW(GLOBAL,LOG_DEBUG, " -> Processing Block %d:\n", bi);
2137
2138 // --- Generate the filename for the current block ---
2139 const char *current_bc_filename = simCtx->bcs_files[bi];
2140 LOG_ALLOW(GLOBAL,LOG_DEBUG," -> Processing Block %d using config file '%s'\n", bi, current_bc_filename);
2141 // This will populate user_finest[bi].boundary_faces
2142
2143 //ierr = ParseAllBoundaryConditions(&user_finest[bi],current_bc_filename); CHKERRQ(ierr);
2144
2145 ierr = BoundarySystem_Initialize(&user_finest[bi], current_bc_filename); CHKERRQ(ierr);
2146 }
2147
2148 // Propogate BC Configuration to coarser levels.
2149 ierr = PropagateBoundaryConfigToCoarserLevels(simCtx); CHKERRQ(ierr);
2150
2151 // Validate the geometric contract before any metric consumes periodic geometry.
2152 for (PetscInt level = simCtx->usermg.mglevels - 1; level >= 0; level--) {
2153 UserCtx *level_users = simCtx->usermg.mgctx[level].user;
2154 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
2155 ierr = ValidatePeriodicGeometry(&level_users[bi]); CHKERRQ(ierr);
2156 }
2157 }
2158
2159 // --- Calculate Grid Metrics (requires BC configuration) ---
2160 // NOTE: This MUST be called here (after BC initialization but before inlet/outlet calculations) because:
2161 // 1. Periodic BC corrections in metric calculations need boundary_faces data to be populated
2162 // 2. Inlet/Outlet area calculations (below) require computed metrics (Csi, Eta, Zet) to be available
2163 // Previously this was in SetupGridAndSolvers, but that caused metrics to be computed without BC info.
2164 LOG_ALLOW(GLOBAL,LOG_INFO,"Computing grid metrics with boundary condition information.\n");
2165 ierr = CalculateAllGridMetrics(simCtx); CHKERRQ(ierr);
2166
2167 // --- Phase 2: Calculate inlet/outlet properties (requires computed metrics) ---
2168 LOG_ALLOW(GLOBAL,LOG_INFO,"Calculating inlet and outlet face properties.\n");
2169 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
2170 // Call the function to calculate the center of the inlet face & the inlet area, which may be used to calculate Boundary values.
2171 ierr = CalculateInletProperties(&user_finest[bi]); CHKERRQ(ierr);
2172
2173 // Call the function to calculate the center of the outlet face & the outlet area, which may be used to calculate Boundary values.
2174 ierr = CalculateOutletProperties(&user_finest[bi]); CHKERRQ(ierr);
2175 }
2176
2177 LOG_ALLOW(GLOBAL,LOG_INFO, "--- Boundary Conditions setup complete ---\n");
2178
2179
2181 PetscFunctionReturn(0);
2182}
PetscErrorCode BoundarySystem_Initialize(UserCtx *user, const char *bcs_filename)
Initializes the entire boundary system.
Definition Boundaries.c:891
PetscErrorCode PropagateBoundaryConfigToCoarserLevels(SimCtx *simCtx)
Propagates boundary condition configuration from finest to all coarser multigrid levels.
Definition Boundaries.c:988
PetscErrorCode CalculateAllGridMetrics(SimCtx *simCtx)
Orchestrates the calculation of all grid metrics.
Definition Metric.c:1942
PetscErrorCode CalculateOutletProperties(UserCtx *user)
Calculates the center and area of the primary OUTLET face.
Definition grid.c:1119
PetscErrorCode ValidatePeriodicGeometry(UserCtx *user)
Validates that configured geometric periodic seams match by translation.
Definition grid.c:380
PetscErrorCode CalculateInletProperties(UserCtx *user)
Calculates the center and area of the primary INLET face.
Definition grid.c:1066
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitializeSolutionConvergenceState()

PetscErrorCode InitializeSolutionConvergenceState ( SimCtx simCtx)

Allocates any runtime storage required by solution-convergence logging.

This helper is setup-owned because it allocates mode-specific buffers once the finest-level Eulerian vectors already exist. It does not compute or log any metrics; it only prepares storage for later use by LOG_SOLUTION_CONVERGENCE().

Allocation depends on the active solution-convergence mode:

  • steady/transient: no extra storage beyond counters
  • periodic_deterministic: one phase-aligned Ucat / P reference slot per configured period step and per block
  • statistical_steady: rolling scalar histories sized for two adjacent windows of mean_speed and mean_ke

The helper also resets the recorded-sample counter so warmup behavior starts from a clean state each time solver setup is rebuilt.

Parameters
[in,out]simCtxMaster simulation context owning the runtime storage.
Returns
PetscErrorCode 0 on success.

Allocates any runtime storage required by solution-convergence logging.

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

See also
InitializeSolutionConvergenceState()

Definition at line 47 of file setup.c.

48{
49 UserCtx *user = NULL;
50 PetscInt history_capacity = 0;
51
52 PetscFunctionBeginUser;
53 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL.");
54 if (simCtx->exec_mode != EXEC_MODE_SOLVER) PetscFunctionReturn(0);
55 if (!simCtx->usermg.mgctx) {
56 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
57 "Multigrid hierarchy must exist before initializing solution convergence storage.");
58 }
59
60 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
61 if (!user) {
62 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
63 "Finest-level UserCtx must exist before initializing solution convergence storage.");
64 }
65
67
69 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
70 PetscCall(PetscCalloc1((size_t)simCtx->solutionConvergencePeriodSteps,
71 &user[bi].solutionConvergencePeriodicUcatRef));
72 PetscCall(PetscCalloc1((size_t)simCtx->solutionConvergencePeriodSteps,
73 &user[bi].solutionConvergencePeriodicPRef));
74 for (PetscInt phase = 0; phase < simCtx->solutionConvergencePeriodSteps; ++phase) {
75 PetscCall(VecDuplicate(user[bi].Ucat, &user[bi].solutionConvergencePeriodicUcatRef[phase]));
76 PetscCall(VecSet(user[bi].solutionConvergencePeriodicUcatRef[phase], 0.0));
77 PetscCall(VecDuplicate(user[bi].P, &user[bi].solutionConvergencePeriodicPRef[phase]));
78 PetscCall(VecSet(user[bi].solutionConvergencePeriodicPRef[phase], 0.0));
79 }
80 }
81 }
82
84 history_capacity = 2 * simCtx->solutionConvergenceWindowSteps;
85 PetscCall(PetscCalloc1((size_t)history_capacity, &simCtx->solutionConvergenceMeanSpeedHistory));
86 PetscCall(PetscCalloc1((size_t)history_capacity, &simCtx->solutionConvergenceMeanKEHistory));
87 }
88
89 PetscFunctionReturn(0);
90}
Here is the caller graph for this function:

◆ DestroySolutionConvergenceState()

PetscErrorCode DestroySolutionConvergenceState ( SimCtx simCtx)

Frees any runtime storage allocated for solution-convergence logging.

This helper is the cleanup counterpart to InitializeSolutionConvergenceState(). It releases periodic reference buffers and statistical-history arrays, then resets the associated pointers and counters. It is safe to call during teardown even if a given mode never allocated optional storage.

Parameters
[in,out]simCtxMaster simulation context owning the runtime storage.
Returns
PetscErrorCode 0 on success.

Frees any runtime storage allocated for solution-convergence logging.

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

See also
DestroySolutionConvergenceState()

Definition at line 98 of file setup.c.

99{
100 UserCtx *user = NULL;
101
102 PetscFunctionBeginUser;
103 if (!simCtx || !simCtx->usermg.mgctx) PetscFunctionReturn(0);
104
105 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
106 if (user) {
107 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
108 if (user[bi].solutionConvergencePeriodicUcatRef) {
109 for (PetscInt phase = 0; phase < simCtx->solutionConvergencePeriodSteps; ++phase) {
110 if (user[bi].solutionConvergencePeriodicUcatRef[phase]) {
111 PetscCall(VecDestroy(&user[bi].solutionConvergencePeriodicUcatRef[phase]));
112 }
113 }
114 PetscCall(PetscFree(user[bi].solutionConvergencePeriodicUcatRef));
116 }
117 if (user[bi].solutionConvergencePeriodicPRef) {
118 for (PetscInt phase = 0; phase < simCtx->solutionConvergencePeriodSteps; ++phase) {
119 if (user[bi].solutionConvergencePeriodicPRef[phase]) {
120 PetscCall(VecDestroy(&user[bi].solutionConvergencePeriodicPRef[phase]));
121 }
122 }
123 PetscCall(PetscFree(user[bi].solutionConvergencePeriodicPRef));
124 user[bi].solutionConvergencePeriodicPRef = NULL;
125 }
126 }
127 }
128
130 PetscCall(PetscFree(simCtx->solutionConvergenceMeanSpeedHistory));
132 }
134 PetscCall(PetscFree(simCtx->solutionConvergenceMeanKEHistory));
136 }
138
139 PetscFunctionReturn(0);
140}
Vec * solutionConvergencePeriodicPRef
Definition variables.h:914
Vec * solutionConvergencePeriodicUcatRef
Definition variables.h:913
Here is the caller graph for this function:

◆ Allocate3DArrayScalar()

PetscErrorCode Allocate3DArrayScalar ( PetscReal ****  array,
PetscInt  nz,
PetscInt  ny,
PetscInt  nx 
)

Allocates a 3D array of PetscReal values using PetscCalloc.

This function dynamically allocates memory for a 3D array of PetscReal values with dimensions nz (layers) x ny (rows) x nx (columns). It uses PetscCalloc1 to ensure the memory is zero-initialized.

The allocation is done in three steps:

  1. Allocate an array of nz pointers (one for each layer).
  2. Allocate a contiguous block for nz*ny row pointers and assign each layer’s row pointers.
  3. Allocate a contiguous block for all nz*ny*nx PetscReal values.

This setup allows the array to be accessed as array[k][j][i], and the memory for the data is contiguous, which improves cache efficiency.

Parameters
[out]arrayPointer to the 3D array to be allocated.
[in]nzNumber of layers (z-direction).
[in]nyNumber of rows (y-direction).
[in]nxNumber of columns (x-direction).
Returns
PetscErrorCode 0 on success, nonzero on failure.

Allocates a 3D array of PetscReal values using PetscCalloc.

Local to this translation unit.

Definition at line 2188 of file setup.c.

2189{
2190 PetscErrorCode ierr;
2191 PetscReal ***data;
2192 PetscReal *dataContiguous;
2193 PetscInt k, j;
2194
2195 PetscFunctionBegin;
2196 /* Step 1: Allocate memory for an array of nz layer pointers (zero-initialized) */
2197 ierr = PetscCalloc1(nz, &data); CHKERRQ(ierr);
2198
2199 /* Step 2: Allocate memory for all row pointers (nz * ny pointers) */
2200 ierr = PetscCalloc1(nz * ny, &data[0]); CHKERRQ(ierr);
2201 for (k = 1; k < nz; k++) {
2202 data[k] = data[0] + k * ny;
2203 }
2204
2205 /* Step 3: Allocate one contiguous block for all data elements (nz*ny*nx) */
2206 ierr = PetscCalloc1(nz * ny * nx, &dataContiguous); CHKERRQ(ierr);
2207
2208 /* Build the 3D pointer structure: each row pointer gets the correct segment of data */
2209 for (k = 0; k < nz; k++) {
2210 for (j = 0; j < ny; j++) {
2211 data[k][j] = dataContiguous + (k * ny + j) * nx;
2212 /* Memory is already zeroed by PetscCalloc1, so no manual initialization is needed */
2213 }
2214 }
2215 *array = data;
2216 PetscFunctionReturn(0);
2217}

◆ Deallocate3DArrayScalar()

PetscErrorCode Deallocate3DArrayScalar ( PetscReal ***  array,
PetscInt  nz,
PetscInt  ny 
)

Deallocates a 3D array of PetscReal values allocated by Allocate3DArrayScalar.

This function frees the memory allocated for a 3D array of PetscReal values. It assumes the memory was allocated using Allocate3DArrayScalar, which allocated three separate memory blocks: one for the contiguous data, one for the row pointers, and one for the layer pointers.

Parameters
[in]arrayPointer to the 3D array to be deallocated.
[in]nzNumber of layers (z-direction).
[in]nyNumber of rows (y-direction).
Returns
PetscErrorCode 0 on success, nonzero on failure.

Deallocates a 3D array of PetscReal values allocated by Allocate3DArrayScalar.

Local to this translation unit.

Definition at line 2223 of file setup.c.

2224{
2225 PetscErrorCode ierr;
2226 (void)nz;
2227 (void)ny;
2228
2229 PetscFunctionBegin;
2230 if (!array || !array[0] || !array[0][0] ) { // Added more robust check
2231 LOG_ALLOW(GLOBAL, LOG_WARNING, "Deallocate3DArrayScalar called with potentially unallocated or NULL array.\n");
2232 if (array) {
2233 if (array[0]) { // Check if row pointers might exist
2234 // Cannot safely access array[0][0] if array[0] might be invalid/freed
2235 // Standard deallocation below assumes valid pointers.
2236 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free row pointers if they exist
2237 }
2238 ierr = PetscFree(array); CHKERRQ(ierr); // Free layer pointers if they exist
2239 }
2240 PetscFunctionReturn(0);
2241 }
2242
2243 // --- Standard Deallocation (assuming valid allocation) ---
2244
2245 /* 1. Free the contiguous block of PetscReal values.
2246 The starting address was stored in array[0][0]. */
2247 ierr = PetscFree(array[0][0]); CHKERRQ(ierr); // Free the ACTUAL DATA
2248
2249 /* 2. Free the contiguous block of row pointers.
2250 The starting address was stored in array[0]. */
2251 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free the ROW POINTERS
2252
2253 /* 3. Free the layer pointer array.
2254 The starting address is 'array' itself. */
2255 ierr = PetscFree(array); CHKERRQ(ierr); // Free the LAYER POINTERS
2256
2257 PetscFunctionReturn(0);
2258}

◆ Allocate3DArrayVector()

PetscErrorCode Allocate3DArrayVector ( Cmpnts ****  array,
PetscInt  nz,
PetscInt  ny,
PetscInt  nx 
)

Allocates a contiguous 3D array of Cmpnts values.

The memory layout mirrors Allocate3DArrayScalar: layer pointers, row pointers, and contiguous payload are allocated such that indexing as array[k][j][i] is valid while keeping payload data contiguous.

Parameters
[out]arrayPointer to the 3D vector array to allocate.
[in]nzNumber of layers in the z-direction.
[in]nyNumber of rows in the y-direction.
[in]nxNumber of columns in the x-direction.
Returns
PetscErrorCode 0 on success, nonzero on failure.

Allocates a contiguous 3D array of Cmpnts values.

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

See also
Allocate3DArrayVector()

Definition at line 2266 of file setup.c.

2267{
2268 PetscErrorCode ierr;
2269 Cmpnts ***data;
2270 Cmpnts *dataContiguous;
2271 PetscInt k, j;
2272 PetscMPIInt rank;
2273
2274 PetscFunctionBegin;
2275
2276 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
2277
2278 /* Step 1: Allocate memory for nz layer pointers (zeroed) */
2279 ierr = PetscCalloc1(nz, &data); CHKERRQ(ierr);
2280
2281 LOG_ALLOW(LOCAL,LOG_DEBUG," [Rank %d] memory allocated for outermost layer (%d k-layer pointers).\n",rank,nz);
2282
2283 /* Step 2: Allocate memory for all row pointers (nz * ny pointers) */
2284 ierr = PetscCalloc1(nz * ny, &data[0]); CHKERRQ(ierr);
2285 for (k = 1; k < nz; k++) {
2286 data[k] = data[0] + k * ny;
2287 }
2288
2289 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d] memory allocated for %dx%d row pointers.\n",rank,nz,ny);
2290
2291 /* Step 3: Allocate one contiguous block for nz*ny*nx Cmpnts structures (zeroed) */
2292 ierr = PetscCalloc1(nz * ny * nx, &dataContiguous); CHKERRQ(ierr);
2293
2294 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[Rank %d] memory allocated for contigous block of %dx%dx%d Cmpnts structures).\n",rank,nz,ny,nx);
2295
2296 /* Build the 3D pointer structure for vector data */
2297 for (k = 0; k < nz; k++) {
2298 for (j = 0; j < ny; j++) {
2299 data[k][j] = dataContiguous + (k * ny + j) * nx;
2300 /* The PetscCalloc1 call has already initialized each Cmpnts to zero. */
2301 }
2302 }
2303
2304 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[Rank %d] 3D pointer structure for vector data created. \n",rank);
2305
2306 *array = data;
2307 PetscFunctionReturn(0);
2308}

◆ Deallocate3DArrayVector()

PetscErrorCode Deallocate3DArrayVector ( Cmpnts ***  array,
PetscInt  nz,
PetscInt  ny 
)

Deallocates a 3D array of Cmpnts structures allocated by Allocate3DArrayVector.

This function frees the memory allocated for a 3D array of Cmpnts structures. It assumes the memory was allocated using Allocate3DArrayVector, which created three separate memory blocks: one for the contiguous vector data, one for the row pointers, and one for the layer pointers.

Parameters
[in]arrayPointer to the 3D array to be deallocated.
[in]nzNumber of layers in the z-direction.
[in]nyNumber of rows in the y-direction.
Returns
PetscErrorCode 0 on success, nonzero on failure.

Deallocates a 3D array of Cmpnts structures allocated by Allocate3DArrayVector.

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

See also
Deallocate3DArrayVector()

Definition at line 2316 of file setup.c.

2317{
2318 PetscErrorCode ierr;
2319 (void)nz;
2320 (void)ny;
2321
2322 PetscFunctionBegin;
2323 // If array is NULL or hasn't been allocated properly, just return.
2324 if (!array || !array[0] || !array[0][0] ) {
2325 LOG_ALLOW(GLOBAL, LOG_WARNING, "Deallocate3DArrayVector called with potentially unallocated or NULL array.\n");
2326 // Attempt to free what might exist, but be cautious
2327 if (array) {
2328 if (array[0]) { // Check if row pointers were allocated
2329 // We don't have a direct pointer to the contiguous data block
2330 // saved separately in this allocation scheme. The allocation relies
2331 // on array[0][0] pointing to it. If array[0] was freed first,
2332 // accessing array[0][0] is unsafe.
2333 // The allocation scheme where the contiguous data block is not
2334 // stored separately makes safe deallocation tricky if freeing
2335 // happens out of order or if parts are NULL.
2336
2337 // A SAFER ALLOCATION/DEALLOCATION would store the data pointer separately.
2338 // Given the current allocation scheme, the order MUST be:
2339 // 1. Free the data block (pointed to by array[0][0])
2340 // 2. Free the row pointer block (pointed to by array[0])
2341 // 3. Free the layer pointer block (pointed to by array)
2342
2343 // Let's assume the allocation was successful and pointers are valid.
2344 // Get pointer to the contiguous data block *before* freeing row pointers
2345 Cmpnts *dataContiguous = array[0][0];
2346 ierr = PetscFree(dataContiguous); CHKERRQ(ierr); // Free data block
2347
2348 // Now free the row pointers block
2349 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free row pointers
2350
2351 }
2352 // Finally, free the array of layer pointers
2353 ierr = PetscFree(array); CHKERRQ(ierr);
2354 }
2355 PetscFunctionReturn(0); // Return gracefully if input was NULL initially
2356 }
2357
2358
2359 // --- Standard Deallocation (assuming valid allocation) ---
2360
2361 /* 1. Free the contiguous block of Cmpnts structures.
2362 The starting address was stored in array[0][0] by Allocate3DArrayVector. */
2363 ierr = PetscFree(array[0][0]); CHKERRQ(ierr); // Free the ACTUAL DATA
2364
2365 /* 2. Free the contiguous block of row pointers.
2366 The starting address was stored in array[0]. */
2367 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free the ROW POINTERS
2368
2369 /* 3. Free the layer pointer array.
2370 The starting address is 'array' itself. */
2371 ierr = PetscFree(array); CHKERRQ(ierr); // Free the LAYER POINTERS
2372
2373 PetscFunctionReturn(0);
2374}

◆ GetOwnedCellRange()

PetscErrorCode GetOwnedCellRange ( const DMDALocalInfo *  info_nodes,
PetscInt  dim,
PetscInt *  xs_cell_global_out,
PetscInt *  xm_cell_local_out 
)

Determines the global starting index and number of CELLS owned by the current processor in a specified dimension.

Ownership is defined by the rank owning the cell's origin node (min i,j,k corner).

Parameters
[in]info_nodesPointer to the DMDALocalInfo struct obtained from the NODE-based DMDA (e.g., user->da or user->fda, assuming they have consistent nodal partitioning for defining cell origins).
[in]dimThe dimension to compute the range for (0 for x/i, 1 for y/j, 2 for z/k).
[out]xs_cell_global_outPointer to store the starting global cell index owned by this process.
[out]xm_cell_local_outPointer to store the number of owned cells in this dimension.
Returns
PetscErrorCode 0 on success.

Determines the global starting index and number of CELLS owned by the current processor in a specified dimension.

Local to this translation unit.

Definition at line 2382 of file setup.c.

2386{
2387 PetscErrorCode ierr = 0; // Standard PETSc error code, not explicitly set here but good practice.
2388 PetscInt xs_node_global_rank; // Global index of the first node owned by this rank in the specified dimension.
2389 PetscInt num_nodes_owned_rank; // Number of nodes owned by this rank in this dimension (local count, excluding ghosts).
2390 PetscInt GlobalNodesInDim_from_info; // Total number of DA points in this dimension, from DMDALocalInfo.
2391
2392 PetscFunctionBeginUser;
2393
2394 // --- 1. Input Validation ---
2395 if (!info_nodes || !xs_cell_global_out || !xm_cell_local_out) {
2396 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null pointer passed to GetOwnedCellRange.");
2397 }
2398
2399 // --- 2. Extract Node Ownership and Global Dimension Information from DMDALocalInfo ---
2400 if (dim == 0) { // I-direction
2401 xs_node_global_rank = info_nodes->xs;
2402 num_nodes_owned_rank = info_nodes->xm;
2403 GlobalNodesInDim_from_info = info_nodes->mx;
2404 } else if (dim == 1) { // J-direction
2405 xs_node_global_rank = info_nodes->ys;
2406 num_nodes_owned_rank = info_nodes->ym;
2407 GlobalNodesInDim_from_info = info_nodes->my;
2408 } else if (dim == 2) { // K-direction
2409 xs_node_global_rank = info_nodes->zs;
2410 num_nodes_owned_rank = info_nodes->zm;
2411 GlobalNodesInDim_from_info = info_nodes->mz;
2412 } else {
2413 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d in GetOwnedCellRange. Must be 0, 1, or 2.", dim);
2414 }
2415
2416 // --- 3. Correct for User-Defined Ghost Node ---
2417 // Per the function's contract (@warning), the DA size includes an extra, non-physical
2418 // node. We subtract 1 to get the true number of physical nodes for cell calculations.
2419 const PetscInt physical_nodes_in_dim = GlobalNodesInDim_from_info - 1;
2420
2421 // --- 4. Handle Edge Cases for Physical Domain Size ---
2422 // If the physical domain has 0 or 1 node, no cells can be formed.
2423 if (physical_nodes_in_dim <= 1) {
2424 *xs_cell_global_out = xs_node_global_rank; // Still report the rank's starting node
2425 *xm_cell_local_out = 0; // But 0 cells
2426 PetscFunctionReturn(0);
2427 }
2428
2429 // --- 5. Determine Cell Ownership Based on Corrected Node Ownership ---
2430 // The first cell this rank *could* define has its origin at the first node this rank owns.
2431 *xs_cell_global_out = xs_node_global_rank;
2432
2433 // If the rank owns no nodes in this dimension, it can't form any cell origins.
2434 if (num_nodes_owned_rank == 0) {
2435 *xm_cell_local_out = 0;
2436 } else {
2437 // --- BUG FIX APPLIED HERE ---
2438 // The previous logic incorrectly assumed a cell's end node (N_{k+1}) must be on the
2439 // same rank as its origin node (N_k). The correct logic is to find the intersection
2440 // between the nodes this rank owns and the nodes that are valid origins globally.
2441
2442 // The first node owned by the rank is its first potential origin.
2443 PetscInt first_owned_origin = xs_node_global_rank;
2444
2445 // The absolute last node owned by this rank. Any node up to and including this one
2446 // is a potential cell origin from this rank's perspective.
2447 PetscInt last_node_owned_by_rank = xs_node_global_rank + num_nodes_owned_rank - 1;
2448
2449 // The absolute last node in the entire PHYSICAL domain that can serve as a cell origin.
2450 // If there are `N` physical nodes (0 to N-1), this index is `N-2`.
2451 PetscInt last_possible_origin_global_idx = physical_nodes_in_dim - 2;
2452
2453 // The actual last origin this rank can provide is the *minimum* of what it owns
2454 // and what is globally possible. This correctly handles both ranks in the middle of
2455 // the domain and the very last rank.
2456 PetscInt actual_last_origin_this_rank_can_form = PetscMin(last_node_owned_by_rank, last_possible_origin_global_idx);
2457
2458 // If the first potential origin this rank owns is already beyond the actual last
2459 // origin it can form, then this rank forms no valid cell origins. This happens if
2460 // the rank only owns the very last physical node.
2461 if (first_owned_origin > actual_last_origin_this_rank_can_form) {
2462 *xm_cell_local_out = 0;
2463 } else {
2464 // The number of cells is the count of valid origins this rank owns.
2465 // (Count = Last Index - First Index + 1)
2466 *xm_cell_local_out = actual_last_origin_this_rank_can_form - first_owned_origin + 1;
2467 }
2468 }
2469
2470 PetscFunctionReturn(ierr);
2471}
Here is the caller graph for this function:

◆ ComputeAndStoreNeighborRanks()

PetscErrorCode ComputeAndStoreNeighborRanks ( UserCtx user)

Computes and stores the Cartesian neighbor ranks for the DMDA decomposition.

This function retrieves the neighbor information from the primary DMDA (user->da) and stores the face neighbors (xm, xp, ym, yp, zm, zp) in the user->neighbors structure. It assumes a standard PETSc ordering for the neighbors array returned by DMDAGetNeighbors. Logs warnings if the assumed indices seem incorrect (e.g., center rank mismatch).

Parameters
[in,out]userPointer to the UserCtx structure where neighbor info will be stored.
Returns
PetscErrorCode 0 on success, non-zero on failure.

Computes and stores the Cartesian neighbor ranks for the DMDA decomposition.

Local to this translation unit.

Definition at line 2479 of file setup.c.

2480{
2481 PetscErrorCode ierr;
2482 PetscMPIInt rank;
2483 PetscMPIInt size; // MPI communicator size
2484 const PetscMPIInt *neighbor_ranks_ptr; // Pointer to raw neighbor data from PETSc
2485
2486 PetscFunctionBeginUser;
2488 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2489 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr); // Get MPI size for validation
2490
2491 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Computing DMDA neighbor ranks.\n", rank);
2492
2493 if (!user || !user->da) {
2494 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx or user->da is NULL in ComputeAndStoreNeighborRanks.");
2495 }
2496
2497 // Get the neighbor information from the DMDA
2498 // neighbor_ranks_ptr will point to an internal PETSc array of 27 ranks.
2499 ierr = DMDAGetNeighbors(user->da, &neighbor_ranks_ptr); CHKERRQ(ierr);
2500
2501 // Log the raw values from DMDAGetNeighbors for boundary-relevant directions for debugging
2502 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "[Rank %d]Raw DMDAGetNeighbors: xm_raw=%d, xp_raw=%d, ym_raw=%d, yp_raw=%d, zm_raw=%d, zp_raw=%d. MPI_PROC_NULL is %d.\n",
2503 rank,
2504 neighbor_ranks_ptr[12], neighbor_ranks_ptr[14],
2505 neighbor_ranks_ptr[10], neighbor_ranks_ptr[16],
2506 neighbor_ranks_ptr[4], neighbor_ranks_ptr[22],
2507 (int)MPI_PROC_NULL);
2508
2509 // PETSc standard indices for 3D face neighbors from the 27-point stencil:
2510 // Index = k_offset*9 + j_offset*3 + i_offset (where offsets -1,0,1 map to 0,1,2)
2511 // Center: (i_off=1, j_off=1, k_off=1) => 1*9 + 1*3 + 1 = 13
2512 // X-min: (i_off=0, j_off=1, k_off=1) => 1*9 + 1*3 + 0 = 12
2513 // X-plus: (i_off=2, j_off=1, k_off=1) => 1*9 + 1*3 + 2 = 14
2514 // Y-min: (i_off=1, j_off=0, k_off=1) => 1*9 + 0*3 + 1 = 10
2515 // Y-plus: (i_off=1, j_off=2, k_off=1) => 1*9 + 2*3 + 1 = 16
2516 // Z-min: (i_off=1, j_off=1, k_off=0) => 0*9 + 1*3 + 1 = 4
2517 // Z-plus: (i_off=1, j_off=1, k_off=2) => 2*9 + 1*3 + 1 = 22
2518
2519 if (neighbor_ranks_ptr[13] != rank) {
2520 LOG_ALLOW(GLOBAL, LOG_WARNING, "Rank %d: DMDAGetNeighbors center index (13) is %d, expected current rank %d. Neighbor indexing might be non-standard or DMDA small.\n",
2521 rank, neighbor_ranks_ptr[13], rank);
2522 // This warning is important. If the center isn't the current rank, the offsets are likely wrong.
2523 // However, PETSc should ensure this unless the DM is too small for a 3x3x3 stencil.
2524 }
2525
2526 // Assign and sanitize each neighbor rank
2527 PetscMPIInt temp_neighbor;
2528
2529 temp_neighbor = neighbor_ranks_ptr[12]; // xm
2530 if (temp_neighbor < 0 || temp_neighbor >= size) {
2531 LOG_ALLOW(GLOBAL, LOG_WARNING, "[Rank %d] Correcting invalid xm neighbor %d to MPI_PROC_NULL (%d).\n", rank, temp_neighbor, (int)MPI_PROC_NULL);
2532 user->neighbors.rank_xm = MPI_PROC_NULL;
2533 } else {
2534 user->neighbors.rank_xm = temp_neighbor;
2535 }
2536
2537 temp_neighbor = neighbor_ranks_ptr[14]; // xp
2538 if (temp_neighbor < 0 || temp_neighbor >= size) {
2539 LOG_ALLOW(GLOBAL, LOG_WARNING, "[Rank %d] Correcting invalid xp neighbor %d to MPI_PROC_NULL (%d).\n", rank, temp_neighbor, (int)MPI_PROC_NULL);
2540 user->neighbors.rank_xp = MPI_PROC_NULL;
2541 } else {
2542 user->neighbors.rank_xp = temp_neighbor;
2543 }
2544
2545 temp_neighbor = neighbor_ranks_ptr[10]; // ym
2546 if (temp_neighbor < 0 || temp_neighbor >= size) {
2547 LOG_ALLOW(GLOBAL, LOG_WARNING, "[Rank %d] Correcting invalid ym neighbor %d to MPI_PROC_NULL (%d).\n", rank, temp_neighbor, (int)MPI_PROC_NULL);
2548 user->neighbors.rank_ym = MPI_PROC_NULL;
2549 } else {
2550 user->neighbors.rank_ym = temp_neighbor;
2551 }
2552
2553 temp_neighbor = neighbor_ranks_ptr[16]; // yp
2554 if (temp_neighbor < 0 || temp_neighbor >= size) {
2555 // The log for index 16 was "zm" in your output, should be yp
2556 LOG_ALLOW(GLOBAL, LOG_WARNING, "[Rank %d] Correcting invalid yp neighbor (raw index 16) %d to MPI_PROC_NULL (%d).\n", rank, temp_neighbor, (int)MPI_PROC_NULL);
2557 user->neighbors.rank_yp = MPI_PROC_NULL;
2558 } else {
2559 user->neighbors.rank_yp = temp_neighbor;
2560 }
2561
2562 temp_neighbor = neighbor_ranks_ptr[4]; // zm
2563 if (temp_neighbor < 0 || temp_neighbor >= size) {
2564 LOG_ALLOW(GLOBAL, LOG_WARNING, "[Rank %d] Correcting invalid zm neighbor %d to MPI_PROC_NULL (%d).\n", rank, temp_neighbor, (int)MPI_PROC_NULL);
2565 user->neighbors.rank_zm = MPI_PROC_NULL;
2566 } else {
2567 user->neighbors.rank_zm = temp_neighbor;
2568 }
2569
2570 temp_neighbor = neighbor_ranks_ptr[22]; // zp
2571 if (temp_neighbor < 0 || temp_neighbor >= size) {
2572 LOG_ALLOW(GLOBAL, LOG_WARNING, "[Rank %d] Correcting invalid zp neighbor %d to MPI_PROC_NULL (%d).\n", rank, temp_neighbor, (int)MPI_PROC_NULL);
2573 user->neighbors.rank_zp = MPI_PROC_NULL;
2574 } else {
2575 user->neighbors.rank_zp = temp_neighbor;
2576 }
2577
2578 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "[Rank %d] Stored user->neighbors: xm=%d, xp=%d, ym=%d, yp=%d, zm=%d, zp=%d\n", rank,
2579 user->neighbors.rank_xm, user->neighbors.rank_xp,
2580 user->neighbors.rank_ym, user->neighbors.rank_yp,
2581 user->neighbors.rank_zm, user->neighbors.rank_zp);
2582 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); // Ensure logs are flushed
2583
2584 // Note: neighbor_ranks_ptr memory is managed by PETSc, do not free it.
2586 PetscFunctionReturn(0);
2587}
PetscMPIInt rank_zm
Definition variables.h:197
PetscMPIInt rank_yp
Definition variables.h:196
PetscMPIInt rank_ym
Definition variables.h:196
PetscMPIInt rank_xp
Definition variables.h:195
RankNeighbors neighbors
Definition variables.h:888
PetscMPIInt rank_xm
Definition variables.h:195
PetscMPIInt rank_zp
Definition variables.h:197
Here is the caller graph for this function:

◆ SetDMDAProcLayout()

PetscErrorCode SetDMDAProcLayout ( DM  dm,
UserCtx user 
)

Sets the processor layout for a given DMDA based on PETSc options.

Reads the desired number of processors in x, y, and z directions using PETSc options (e.g., -dm_processors_x, -dm_processors_y, -dm_processors_z). If an option is not provided for a direction, PETSC_DECIDE is used for that direction. Applies the layout using DMDASetNumProcs.

Also stores the retrieved/decided values in user->procs_x/y/z if user context is provided.

Parameters
dmThe DMDA object to configure the layout for.
userPointer to the UserCtx structure (optional, used to store layout values).
Returns
PetscErrorCode 0 on success, non-zero on failure.

Sets the processor layout for a given DMDA based on PETSc options.

Local to this translation unit.

Definition at line 2595 of file setup.c.

2596{
2597 PetscErrorCode ierr;
2598 PetscMPIInt size, rank;
2599 PetscInt px = PETSC_DECIDE, py = PETSC_DECIDE, pz = PETSC_DECIDE;
2600 PetscBool px_set = PETSC_FALSE, py_set = PETSC_FALSE, pz_set = PETSC_FALSE;
2601 SimCtx *simCtx = user->simCtx;
2602
2603 // Set no.of processors in direction 1
2604 if(simCtx->da_procs_x) {
2605 px_set = PETSC_TRUE;
2606 px = simCtx->da_procs_x;
2607 }
2608 // Set no.of processors in direction 2
2609 if(simCtx->da_procs_y) {
2610 py_set = PETSC_TRUE;
2611 py = simCtx->da_procs_y;
2612 }
2613 // Set no.of processors in direction 1
2614 if(simCtx->da_procs_z) {
2615 pz_set = PETSC_TRUE;
2616 pz = simCtx->da_procs_z;
2617 }
2618
2619 PetscFunctionBeginUser;
2621 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size); CHKERRQ(ierr);
2622 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank); CHKERRQ(ierr);
2623 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Configuring DMDA processor layout for %d total processes.\n", rank, size);
2624
2625 // --- Validate User Input (Optional but Recommended) ---
2626 // Check if specified processor counts multiply to the total MPI size
2627 if (px_set && py_set && pz_set) {
2628 if (px * py * pz != size) {
2629 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP,
2630 "Specified processor layout %d x %d x %d = %d does not match MPI size %d",
2631 px, py, pz, px * py * pz, size);
2632 }
2633 LOG_ALLOW(GLOBAL, LOG_INFO, "Using specified processor layout: %d x %d x %d\n", px, py, pz);
2634 } else if (px_set || py_set || pz_set) {
2635 // If only some are set, PETSC_DECIDE will be used for others
2636 LOG_ALLOW(GLOBAL, LOG_INFO, "Using partially specified processor layout: %d x %d x %d (PETSC_DECIDE for unspecified)\n", px, py, pz);
2637 } else {
2638 LOG_ALLOW(GLOBAL, LOG_INFO, "Using fully automatic processor layout (PETSC_DECIDE x PETSC_DECIDE x PETSC_DECIDE)\n");
2639 }
2640 // Additional checks: Ensure px, py, pz are positive if set
2641 if ((px_set && px <= 0) || (py_set && py <= 0) || (pz_set && pz <= 0)) {
2642 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Specified processor counts must be positive.");
2643 }
2644
2645
2646 // --- Apply the layout to the DMDA ---
2647 ierr = DMDASetNumProcs(dm, px, py, pz); CHKERRQ(ierr);
2648 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Rank %d: DMDASetNumProcs called with px=%d, py=%d, pz=%d.\n", rank, px, py, pz);
2649
2650 // --- Store the values in UserCtx (Optional) ---
2651 // Note: If PETSC_DECIDE was used, PETSc calculates the actual values during DMSetUp.
2652 // We store the *requested* values here. To get the *actual* values used,
2653 // you would need to call DMDAGetInfo after DMSetUp.
2654 /*
2655 if (user) {
2656 user->procs_x = px;
2657 user->procs_y = py;
2658 user->procs_z = pz;
2659 }
2660 */
2662 PetscFunctionReturn(0);
2663}
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:879

◆ SetupDomainRankInfo()

PetscErrorCode SetupDomainRankInfo ( SimCtx simCtx)

Sets up the full rank communication infrastructure, including neighbor ranks and bounding box exchange.

This function orchestrates the following steps:

  1. Compute and store the neighbor ranks in the user context.
  2. Gather all local bounding boxes to rank 0.
  3. Broadcast the complete bounding box list to all ranks.

The final result is that each rank has access to its immediate neighbors and the bounding box information of all ranks.

Parameters
[in,out]simCtxPointer to initialized simulation context that owns all block UserCtx objects.
Returns
PetscErrorCode Returns 0 on success or non-zero PETSc error code.

Sets up the full rank communication infrastructure, including neighbor ranks and bounding box exchange.

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

See also
SetupDomainRankInfo()

Definition at line 2673 of file setup.c.

2674{
2675 PetscErrorCode ierr;
2676 PetscInt nblk = simCtx->block_number;
2677 PetscInt size = simCtx->size;
2678 BoundingBox *final_bboxlist = NULL;
2679
2680 PetscFunctionBeginUser;
2682
2683 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting full rank communication setup for %d block(s).\n", nblk);
2684
2685 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
2686
2687 // --- Step 1: Compute neighbor ranks (unchanged) ---
2688 for (int bi = 0; bi < nblk; bi++) {
2689 ierr = ComputeAndStoreNeighborRanks(&user_finest[bi]); CHKERRQ(ierr);
2690 }
2691 LOG_ALLOW(GLOBAL, LOG_INFO, "Neighbor ranks computed and stored for all blocks.\n");
2692
2693 // --- Step 2: Allocate the final, unified list on ALL ranks ---
2694 // Every rank will build this list in parallel.
2695 ierr = PetscMalloc1(size * nblk, &final_bboxlist); CHKERRQ(ierr);
2696
2697 // --- Step 3: Loop through each block, gather then broadcast its bbox list ---
2698 for (int bi = 0; bi < nblk; bi++) {
2699 // This is a temporary pointer for the current block's list.
2700 BoundingBox *block_bboxlist = NULL;
2701
2702 LOG_ALLOW(GLOBAL, LOG_INFO, "Processing bounding boxes for block %d...\n", bi);
2703
2704 // A) GATHER: On rank 0, block_bboxlist is allocated and filled. On others, it's NULL.
2705 ierr = GatherAllBoundingBoxes(&user_finest[bi], &block_bboxlist); CHKERRQ(ierr);
2706 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Gather complete for block %d.\n", bi);
2707
2708 // B) BROADCAST: On non-root ranks, block_bboxlist is allocated. Then, the data
2709 // from rank 0 is broadcast to all ranks. After this call, ALL ranks have
2710 // an identical, complete copy of the bounding boxes for the current block.
2711 ierr = BroadcastAllBoundingBoxes(&user_finest[bi], &block_bboxlist); CHKERRQ(ierr);
2712 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Broadcast complete for block %d.\n", bi);
2713
2714 // C) ASSEMBLE: Every rank now copies the data for this block into the
2715 // correct segment of its final, unified list.
2716 for (int r = 0; r < size; r++) {
2717 // The layout is [r0b0, r1b0, ..., r(size-1)b0, r0b1, r1b1, ...]
2718 final_bboxlist[bi * size + r] = block_bboxlist[r];
2719 }
2720 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Assembly into final list complete for block %d.\n", bi);
2721
2722 // D) CLEANUP: Free the temporary list for this block on ALL ranks before the next iteration.
2723 // Your helper functions use malloc, so we must use free.
2724 free(block_bboxlist);
2725 }
2726
2727 // --- Step 4: Assign the final pointer and run the last setup step ---
2728 simCtx->bboxlist = final_bboxlist;
2729 LOG_ALLOW(GLOBAL, LOG_INFO, "Final unified bboxlist created on all ranks and stored in SimCtx.\n");
2730
2731 ierr = SetupDomainCellDecompositionMap(&user_finest[0]); CHKERRQ(ierr);
2732 LOG_ALLOW(GLOBAL, LOG_INFO, "Domain Cell Composition set and broadcasted.\n");
2733
2734 LOG_ALLOW(GLOBAL, LOG_INFO, "SetupDomainRankInfo: Completed successfully.\n");
2735
2737 PetscFunctionReturn(0);
2738}
PetscErrorCode BroadcastAllBoundingBoxes(UserCtx *user, BoundingBox **bboxlist)
Broadcasts the bounding box information collected on rank 0 to all other ranks.
Definition grid.c:1016
PetscErrorCode GatherAllBoundingBoxes(UserCtx *user, BoundingBox **allBBoxes)
Gathers local bounding boxes from all MPI processes to rank 0.
Definition grid.c:954
PetscErrorCode ComputeAndStoreNeighborRanks(UserCtx *user)
Internal helper implementation: ComputeAndStoreNeighborRanks().
Definition setup.c:2479
PetscErrorCode SetupDomainCellDecompositionMap(UserCtx *user)
Internal helper implementation: SetupDomainCellDecompositionMap().
Definition setup.c:3000
Defines a 3D axis-aligned bounding box.
Definition variables.h:169
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Contra2Cart()

PetscErrorCode Contra2Cart ( UserCtx user)

Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on cell faces.

This function performs the transformation from a contravariant velocity representation (which is natural on a curvilinear grid) to a Cartesian (x,y,z) representation. For each interior computational cell owned by the rank, it performs the following:

  1. It averages the contravariant velocity components (U¹, U², U³) from the surrounding faces to get an estimate of the contravariant velocity at the cell center.
  2. It averages the metric vectors (Csi, Eta, Zet) from the surrounding faces to get an estimate of the metric tensor at the cell center. This tensor forms the transformation matrix.
  3. It solves the linear system [MetricTensor] * [ucat] = [ucont] for the Cartesian velocity vector ucat = (u,v,w) using Cramer's rule.
  4. The computed Cartesian velocity is stored only at independent owned cells in the global user->Ucat vector.

The function operates on local, ghosted versions of the input vectors (user->lUcont, user->lCsi, etc.) to ensure stencils are valid across processor boundaries.

Parameters
[in,out]userPointer to the UserCtx structure. The function reads from user->lUcont, user->lCsi, user->lEta, user->lZet, user->lNvert and writes to the global user->Ucat vector.
Returns
PetscErrorCode 0 on success.
Note
  • This function should be called AFTER user->lUcont and all local metric vectors (user->lCsi, etc.) have been populated with up-to-date ghost values via UpdateLocalGhosts.
  • It only computes Ucat for interior cells (not on physical boundaries) and for cells not marked as solid/blanked by user->lNvert.
  • The function performs no communication, does not synchronize periodic duplicate planes, and does not refresh user->lUcat.
  • Before stencil consumption, the caller must synchronize periodic cell values with SynchronizePeriodicCellFields(user, 1, {"Ucat"}) and then call UpdateLocalGhosts(user, "Ucat"). The latter remains necessary for the fully nonperiodic case because periodic synchronization is then a no-op.

Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on cell faces.

Local to this translation unit.

Definition at line 2746 of file setup.c.

2747{
2748 PetscErrorCode ierr;
2749 DMDALocalInfo info;
2750 Cmpnts ***lcsi_arr, ***leta_arr, ***lzet_arr; // Local metric arrays
2751 Cmpnts ***lucont_arr; // Local contravariant velocity array
2752 Cmpnts ***gucat_arr; // Global Cartesian velocity array
2753 PetscReal ***lnvert_arr; // Local Nvert array
2754 PetscReal ***laj_arr; // Local Jacobian Determinant inverse array
2755
2756 PetscFunctionBeginUser;
2758 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Starting Contravariant-to-Cartesian velocity transformation.\n");
2759
2760 // --- 1. Get DMDA Info and Check for Valid Inputs ---
2761 // All inputs (lUcont, lCsi, etc.) and outputs (Ucat) are on DMs from the UserCtx.
2762 // We get local info from fda, which governs the layout of most arrays here.
2763 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2764 if (!user->lUcont || !user->lCsi || !user->lEta || !user->lZet || !user->lNvert || !user->Ucat) {
2765 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Contra2Cart requires lUcont, lCsi/Eta/Zet, lNvert, and Ucat to be non-NULL.");
2766 }
2767
2768
2769 // --- 2. Get Read-Only Array Access to Local Input Vectors (with ghosts) ---
2770 ierr = DMDAVecGetArrayRead(user->fda, user->lUcont, &lucont_arr); CHKERRQ(ierr);
2771 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &lcsi_arr); CHKERRQ(ierr);
2772 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &leta_arr); CHKERRQ(ierr);
2773 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &lzet_arr); CHKERRQ(ierr);
2774 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, &lnvert_arr); CHKERRQ(ierr);
2775 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &laj_arr); CHKERRQ(ierr);
2776
2777 // --- 3. Get Write-Only Array Access to the Global Output Vector ---
2778 // We compute for local owned cells and write into the global vector.
2779 // PETSc handles mapping the global indices to the correct local memory locations.
2780 ierr = DMDAVecGetArray(user->fda, user->Ucat, &gucat_arr); CHKERRQ(ierr);
2781
2782
2783 // --- 4. Define Loop Bounds for INTERIOR Cells ---
2784 // We use adjusted bounds to avoid calculating Ucat on the physical domain boundaries,
2785 // as these are typically set explicitly by boundary condition functions.
2786 // The stencils use indices like i-1, j-1, k-1, so we must start loops at least at index 1.
2787 PetscInt i_start = (info.xs == 0) ? info.xs + 1 : info.xs;
2788 PetscInt i_end = (info.xs + info.xm == info.mx) ? info.xs + info.xm - 1 : info.xs + info.xm;
2789
2790 PetscInt j_start = (info.ys == 0) ? info.ys + 1 : info.ys;
2791 PetscInt j_end = (info.ys + info.ym == info.my) ? info.ys + info.ym - 1 : info.ys + info.ym;
2792
2793 PetscInt k_start = (info.zs == 0) ? info.zs + 1 : info.zs;
2794 PetscInt k_end = (info.zs + info.zm == info.mz) ? info.zs + info.zm - 1 : info.zs + info.zm;
2795
2796 // --- 5. Main Computation Loop ---
2797 // Loops over the GLOBAL indices of interior cells owned by this rank.
2798 for (PetscInt k_cell = k_start; k_cell < k_end; ++k_cell) {
2799 for (PetscInt j_cell = j_start; j_cell < j_end; ++j_cell) {
2800 for (PetscInt i_cell = i_start; i_cell < i_end; ++i_cell) {
2801
2802 // Check if the cell is a fluid cell (not solid/blanked)
2803 // if (lnvert_arr[k_cell][j_cell][i_cell] > 0.1) continue; // Skip solid/blanked cells
2804
2805 // Transformation matrix [mat] is the metric tensor at the cell center,
2806 // estimated by averaging metrics from adjacent faces.
2807 PetscReal mat[3][3];
2808
2809 // PetscReal aj_center = laj_arr[k_cell+1][j_cell+1][i_cell+1];
2810
2811 mat[0][0] = 0.5 * (lcsi_arr[k_cell][j_cell][i_cell-1].x + lcsi_arr[k_cell][j_cell][i_cell].x); //* aj_center;
2812 mat[0][1] = 0.5 * (lcsi_arr[k_cell][j_cell][i_cell-1].y + lcsi_arr[k_cell][j_cell][i_cell].y); //* aj_center;
2813 mat[0][2] = 0.5 * (lcsi_arr[k_cell][j_cell][i_cell-1].z + lcsi_arr[k_cell][j_cell][i_cell].z); //* aj_center;
2814
2815 mat[1][0] = 0.5 * (leta_arr[k_cell][j_cell-1][i_cell].x + leta_arr[k_cell][j_cell][i_cell].x); //* aj_center;
2816 mat[1][1] = 0.5 * (leta_arr[k_cell][j_cell-1][i_cell].y + leta_arr[k_cell][j_cell][i_cell].y); //* aj_center;
2817 mat[1][2] = 0.5 * (leta_arr[k_cell][j_cell-1][i_cell].z + leta_arr[k_cell][j_cell][i_cell].z); //* aj_center;
2818
2819 mat[2][0] = 0.5 * (lzet_arr[k_cell-1][j_cell][i_cell].x + lzet_arr[k_cell][j_cell][i_cell].x); //* aj_center;
2820 mat[2][1] = 0.5 * (lzet_arr[k_cell-1][j_cell][i_cell].y + lzet_arr[k_cell][j_cell][i_cell].y); //* aj_center;
2821 mat[2][2] = 0.5 * (lzet_arr[k_cell-1][j_cell][i_cell].z + lzet_arr[k_cell][j_cell][i_cell].z); //* aj_center;
2822
2823 // Contravariant velocity vector `q` at the cell center,
2824 // estimated by averaging face-based contravariant velocities.
2825 PetscReal q[3];
2826 q[0] = 0.5 * (lucont_arr[k_cell][j_cell][i_cell-1].x + lucont_arr[k_cell][j_cell][i_cell].x); // U¹ at cell center
2827 q[1] = 0.5 * (lucont_arr[k_cell][j_cell-1][i_cell].y + lucont_arr[k_cell][j_cell][i_cell].y); // U² at cell center
2828 q[2] = 0.5 * (lucont_arr[k_cell-1][j_cell][i_cell].z + lucont_arr[k_cell][j_cell][i_cell].z); // U³ at cell center
2829
2830 // Solve the 3x3 system `mat * ucat = q` using Cramer's rule.
2831 PetscReal det = mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
2832 mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
2833 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]);
2834
2835 if (PetscAbsReal(det) < 1.0e-18) {
2836 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FLOP_COUNT, "Transformation matrix determinant is near zero at cell (%d,%d,%d) \n", i_cell, j_cell, k_cell);
2837 }
2838
2839 PetscReal det_inv = 1.0 / det;
2840
2841 PetscReal det0 = q[0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
2842 q[1] * (mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) +
2843 q[2] * (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]);
2844
2845 PetscReal det1 = -q[0] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
2846 q[1] * (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) -
2847 q[2] * (mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]);
2848
2849 PetscReal det2 = q[0] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) -
2850 q[1] * (mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) +
2851 q[2] * (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]);
2852
2853 // Store computed Cartesian velocity in the GLOBAL Ucat array at the
2854 // array index corresponding to the cell's origin node.
2855 gucat_arr[k_cell][j_cell][i_cell].x = det0 * det_inv;
2856 gucat_arr[k_cell][j_cell][i_cell].y = det1 * det_inv;
2857 gucat_arr[k_cell][j_cell][i_cell].z = det2 * det_inv;
2858 }
2859 }
2860 }
2861
2862 // --- 6. Restore Array Access ---
2863 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcont, &lucont_arr); CHKERRQ(ierr);
2864 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &lcsi_arr); CHKERRQ(ierr);
2865 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &leta_arr); CHKERRQ(ierr);
2866 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &lzet_arr); CHKERRQ(ierr);
2867 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, &lnvert_arr); CHKERRQ(ierr);
2868 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &laj_arr); CHKERRQ(ierr);
2869 ierr = DMDAVecRestoreArray(user->fda, user->Ucat, &gucat_arr); CHKERRQ(ierr);
2870
2871 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed Contravariant-to-Cartesian velocity transformation. \n");
2873 PetscFunctionReturn(0);
2874}
Here is the caller graph for this function:

◆ Cart2Contra()

PetscErrorCode Cart2Contra ( UserCtx user)

Convert the ghosted Cartesian velocity field to contravariant face fluxes.

Interpolates user->lUcat to each logical face and dots it with the corresponding face-area metric vector. Writes independent entries of user->Ucont. Periodic and physical endpoint values in user->lUcat must be finalized and its MPI ghosts current before entry. The resulting Ucont is not synchronized; callers must use the staggered-field workflow before stencil use.

Parameters
[in,out]userUserCtx for the block; Ucont is written in place.
Returns
PetscErrorCode 0 on success.

Convert the ghosted Cartesian velocity field to contravariant face fluxes.

Definition at line 2881 of file setup.c.

2882{
2883 PetscErrorCode ierr;
2884 DMDALocalInfo info;
2885 const Cmpnts ***ucat_arr, ***csi_arr, ***eta_arr, ***zet_arr;
2886 Cmpnts ***ucont_arr;
2887
2888 PetscFunctionBeginUser;
2890
2891 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2892 ierr = DMDAVecGetArrayRead(user->fda, user->lUcat, &ucat_arr); CHKERRQ(ierr);
2893 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
2894 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
2895 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
2896 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
2897
2898 const PetscInt i_start = PetscMax(info.xs, 1);
2899 const PetscInt j_start = PetscMax(info.ys, 1);
2900 const PetscInt k_start = PetscMax(info.zs, 1);
2901 const PetscInt i_end = PetscMin(info.xs + info.xm, info.mx - 1);
2902 const PetscInt j_end = PetscMin(info.ys + info.ym, info.my - 1);
2903 const PetscInt k_end = PetscMin(info.zs + info.zm, info.mz - 1);
2904
2905 for (PetscInt k = k_start; k < k_end; k++) {
2906 for (PetscInt j = j_start; j < j_end; j++) {
2907 for (PetscInt i = i_start; i < i_end; i++) {
2908 const Cmpnts u_xi = {
2909 0.5 * (ucat_arr[k][j][i].x + ucat_arr[k][j][i + 1].x),
2910 0.5 * (ucat_arr[k][j][i].y + ucat_arr[k][j][i + 1].y),
2911 0.5 * (ucat_arr[k][j][i].z + ucat_arr[k][j][i + 1].z)
2912 };
2913 const Cmpnts u_eta = {
2914 0.5 * (ucat_arr[k][j][i].x + ucat_arr[k][j + 1][i].x),
2915 0.5 * (ucat_arr[k][j][i].y + ucat_arr[k][j + 1][i].y),
2916 0.5 * (ucat_arr[k][j][i].z + ucat_arr[k][j + 1][i].z)
2917 };
2918 const Cmpnts u_zeta = {
2919 0.5 * (ucat_arr[k][j][i].x + ucat_arr[k + 1][j][i].x),
2920 0.5 * (ucat_arr[k][j][i].y + ucat_arr[k + 1][j][i].y),
2921 0.5 * (ucat_arr[k][j][i].z + ucat_arr[k + 1][j][i].z)
2922 };
2923 ucont_arr[k][j][i].x = csi_arr[k][j][i].x * u_xi.x + csi_arr[k][j][i].y * u_xi.y + csi_arr[k][j][i].z * u_xi.z;
2924 ucont_arr[k][j][i].y = eta_arr[k][j][i].x * u_eta.x + eta_arr[k][j][i].y * u_eta.y + eta_arr[k][j][i].z * u_eta.z;
2925 ucont_arr[k][j][i].z = zet_arr[k][j][i].x * u_zeta.x + zet_arr[k][j][i].y * u_zeta.y + zet_arr[k][j][i].z * u_zeta.z;
2926 }
2927 }
2928 }
2929
2930 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
2931 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
2932 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
2933 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
2934 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcat, &ucat_arr); CHKERRQ(ierr);
2935
2937 PetscFunctionReturn(0);
2938}
Here is the caller graph for this function:

◆ UniformCart2Contra()

PetscErrorCode UniformCart2Contra ( UserCtx user,
PetscReal  u,
PetscReal  v,
PetscReal  w 
)

Populate contravariant fluxes from one uniform Cartesian velocity.

Parameters
[in,out]userUserCtx for the block; Ucont is written in place.
[in]uPhysical x-velocity component.
[in]vPhysical y-velocity component.
[in]wPhysical z-velocity component.
Returns
PetscErrorCode 0 on success.

Populate contravariant fluxes from one uniform Cartesian velocity.

Computes the dot product of the physical velocity with each face-area vector: U^xi = csi · (u,v,w), U^eta = eta · (u,v,w), U^zeta = zet · (u,v,w). Writes to all owned nodes (xs..xe, ys..ye, zs..ze); boundary ghosts are overwritten later by ApplyBoundaryConditions.

Parameters
userUserCtx with fda, Ucont, lCsi, lEta, lZet populated.
uPhysical Cartesian x-velocity.
vPhysical Cartesian y-velocity.
wPhysical Cartesian z-velocity.

Definition at line 2953 of file setup.c.

2954{
2955 PetscErrorCode ierr;
2956 PetscFunctionBeginUser;
2958
2959 DMDALocalInfo info;
2960 Cmpnts ***ucont_arr;
2961 const Cmpnts ***csi_arr, ***eta_arr, ***zet_arr;
2962
2963 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2964 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
2965 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
2966 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
2967 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
2968
2969 const PetscInt xs = info.xs, xe = info.xs + info.xm;
2970 const PetscInt ys = info.ys, ye = info.ys + info.ym;
2971 const PetscInt zs = info.zs, ze = info.zs + info.zm;
2972
2973 for (PetscInt k = zs; k < ze; k++) {
2974 for (PetscInt j = ys; j < ye; j++) {
2975 for (PetscInt i = xs; i < xe; i++) {
2976 ucont_arr[k][j][i].x = csi_arr[k][j][i].x * u + csi_arr[k][j][i].y * v + csi_arr[k][j][i].z * w;
2977 ucont_arr[k][j][i].y = eta_arr[k][j][i].x * u + eta_arr[k][j][i].y * v + eta_arr[k][j][i].z * w;
2978 ucont_arr[k][j][i].z = zet_arr[k][j][i].x * u + zet_arr[k][j][i].y * v + zet_arr[k][j][i].z * w;
2979 }
2980 }
2981 }
2982
2983 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
2984 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
2985 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
2986 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
2987
2988 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Cart2Contra: set Ucont from Cartesian (%.3f, %.3f, %.3f).\n",
2989 (double)u, (double)v, (double)w);
2991 PetscFunctionReturn(0);
2992}
Here is the caller graph for this function:

◆ SetupDomainCellDecompositionMap()

PetscErrorCode SetupDomainCellDecompositionMap ( UserCtx user)

Creates and distributes a map of the domain's cell decomposition to all ranks.

This function is a critical part of the simulation setup. It determines the global cell ownership for each MPI rank and makes this information available to all other ranks. This "decomposition map" is essential for the robust "Walk and Handoff" particle migration strategy, allowing any rank to quickly identify the owner of a target cell.

The process involves:

  1. Each rank gets its own node ownership information from the DMDA.
  2. It converts this node information into cell ownership ranges using the GetOwnedCellRange helper function.
  3. It participates in an MPI_Allgather collective operation to build a complete array (user->RankCellInfoMap) containing the ownership information for every rank.

This function should be called once during initialization after the primary DMDA (user->da) has been set up.

Parameters
[in,out]userPointer to the UserCtx structure. The function will allocate and populate user->RankCellInfoMap and set user->num_ranks.
Returns
PetscErrorCode 0 on success, or a non-zero PETSc error code on failure. Errors can occur if input pointers are NULL or if MPI communication fails.

Creates and distributes a map of the domain's cell decomposition to all ranks.

Local to this translation unit.

Definition at line 3000 of file setup.c.

3001{
3002 PetscErrorCode ierr;
3003 DMDALocalInfo local_node_info;
3004 RankCellInfo my_cell_info;
3005 PetscMPIInt rank, size;
3006
3007 PetscFunctionBeginUser;
3009
3010 // --- 1. Input Validation and MPI Info ---
3011 if (!user) {
3012 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx pointer is NULL in SetupDomainCellDecompositionMap.");
3013 }
3014 if (!user->da) {
3015 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "user->da is not initialized in SetupDomainCellDecompositionMap.");
3016 }
3017
3018 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3019 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
3020
3021 LOG_ALLOW(GLOBAL, LOG_INFO, "Setting up domain cell decomposition map for %d ranks.\n", size);
3022
3023 // --- 2. Determine Local Cell Ownership ---
3024 // Get the local node ownership information from the primary DMDA.
3025 ierr = DMDAGetLocalInfo(user->da, &local_node_info); CHKERRQ(ierr);
3026
3027 // Use the robust helper function to convert node ownership to cell ownership.
3028 // A cell's index is defined by its origin node.
3029
3030 ierr = GetOwnedCellRange(&local_node_info, 0, &my_cell_info.xs_cell, &my_cell_info.xm_cell); CHKERRQ(ierr);
3031 ierr = GetOwnedCellRange(&local_node_info, 1, &my_cell_info.ys_cell, &my_cell_info.ym_cell); CHKERRQ(ierr);
3032 ierr = GetOwnedCellRange(&local_node_info, 2, &my_cell_info.zs_cell, &my_cell_info.zm_cell); CHKERRQ(ierr);
3033
3034 // Log the calculated local ownership for debugging purposes.
3035 LOG_ALLOW(LOCAL, LOG_DEBUG, "[Rank %d] Owns cells: i[%d, %d), j[%d, %d), k[%d, %d)\n",
3036 rank, my_cell_info.xs_cell, my_cell_info.xs_cell + my_cell_info.xm_cell,
3037 my_cell_info.ys_cell, my_cell_info.ys_cell + my_cell_info.ym_cell,
3038 my_cell_info.zs_cell, my_cell_info.zs_cell + my_cell_info.zm_cell);
3039
3040 // --- 3. Allocate and Distribute the Global Map ---
3041 // Allocate memory for the global map that will hold information from all ranks.
3042 ierr = PetscMalloc1(size, &user->RankCellInfoMap); CHKERRQ(ierr);
3043
3044 // Perform the collective communication to gather the `RankCellInfo` struct from every rank.
3045 // Each rank sends its `my_cell_info` and receives the complete array in `user->RankCellInfoMap`.
3046 // We use MPI_BYTE to ensure portability across different systems and struct padding.
3047 ierr = MPI_Allgather(&my_cell_info, sizeof(RankCellInfo), MPI_BYTE,
3048 user->RankCellInfoMap, sizeof(RankCellInfo), MPI_BYTE,
3049 PETSC_COMM_WORLD); CHKERRQ(ierr);
3050
3051 LOG_ALLOW(GLOBAL, LOG_INFO, "Domain cell decomposition map created and distributed successfully.\n");
3052
3054 PetscFunctionReturn(0);
3055}
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global_out, PetscInt *xm_cell_local_out)
Internal helper implementation: GetOwnedCellRange().
Definition setup.c:2382
PetscInt ys_cell
Definition variables.h:202
PetscInt xs_cell
Definition variables.h:202
PetscInt zm_cell
Definition variables.h:203
PetscInt zs_cell
Definition variables.h:202
PetscInt xm_cell
Definition variables.h:203
RankCellInfo * RankCellInfoMap
Definition variables.h:951
PetscInt ym_cell
Definition variables.h:203
A lean struct to hold the global cell ownership range for a single MPI rank.
Definition variables.h:201
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BinarySearchInt64()

PetscErrorCode BinarySearchInt64 ( PetscInt  n,
const PetscInt64  arr[],
PetscInt64  key,
PetscBool *  found 
)

Performs a binary search for a key in a sorted array of PetscInt64.

This is a standard binary search algorithm implemented as a PETSc-style helper function. It efficiently determines if a given key exists within a sorted array.

Parameters
[in]nThe number of elements in the array.
[in]arrA pointer to the sorted array of PetscInt64 values to be searched.
[in]keyThe PetscInt64 value to search for.
[out]foundA pointer to a PetscBool that will be set to PETSC_TRUE if the key is found, and PETSC_FALSE otherwise.
Returns
PetscErrorCode 0 on success, or a non-zero PETSc error code on failure.
Note
The input array arr must be sorted in ascending order for the algorithm to work correctly.

Performs a binary search for a key in a sorted array of PetscInt64.

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

See also
BinarySearchInt64()

Definition at line 3065 of file setup.c.

3066{
3067 PetscInt low = 0, high = n - 1;
3068
3069 PetscFunctionBeginUser;
3071
3072 // --- 1. Input Validation ---
3073 if (!found) {
3074 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Output pointer 'found' is NULL in PetscBinarySearchInt64.");
3075 }
3076 if (n > 0 && !arr) {
3077 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input array 'arr' is NULL for n > 0.");
3078 }
3079
3080 // Initialize output
3081 *found = PETSC_FALSE;
3082
3083 // --- 2. Binary Search Algorithm ---
3084 while (low <= high) {
3085 // Use this form to prevent potential integer overflow on very large arrays
3086 PetscInt mid = low + (high - low) / 2;
3087
3088 if (arr[mid] == key) {
3089 *found = PETSC_TRUE; // Key found!
3090 break; // Exit the loop
3091 }
3092
3093 if (arr[mid] < key) {
3094 low = mid + 1; // Search in the right half
3095 } else {
3096 high = mid - 1; // Search in the left half
3097 }
3098 }
3099
3101 PetscFunctionReturn(0);
3102}
Here is the caller graph for this function:

◆ ComputeDivergence()

PetscErrorCode ComputeDivergence ( UserCtx user)

Computes the discrete divergence of the contravariant velocity field.

This diagnostic/kernel routine evaluates continuity residuals on the local block and writes the resulting divergence field into the configured output vector(s).

Parameters
[in,out]userBlock-level context containing velocity and metric fields.
Returns
PetscErrorCode 0 on success.

Computes the discrete divergence of the contravariant velocity field.

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

See also
ComputeDivergence()

Definition at line 3135 of file setup.c.

3136{
3137 DM da = user->da, fda = user->fda;
3138 DMDALocalInfo info = user->info;
3139
3140 PetscInt ti = user->simCtx->step;
3141
3142 PetscInt xs = info.xs, xe = info.xs + info.xm;
3143 PetscInt ys = info.ys, ye = info.ys + info.ym;
3144 PetscInt zs = info.zs, ze = info.zs + info.zm;
3145 PetscInt mx = info.mx, my = info.my, mz = info.mz;
3146
3147 PetscInt lxs, lys, lzs, lxe, lye, lze;
3148 PetscInt i, j, k;
3149
3150 Vec Div;
3151 PetscReal ***div, ***aj, ***nvert,***p;
3152 Cmpnts ***ucont;
3153 PetscReal maxdiv;
3154
3155 lxs = xs; lxe = xe;
3156 lys = ys; lye = ye;
3157 lzs = zs; lze = ze;
3158
3159 if (xs==0) lxs = xs+1;
3160 if (ys==0) lys = ys+1;
3161 if (zs==0) lzs = zs+1;
3162
3163 if (xe==mx) lxe = xe-1;
3164 if (ye==my) lye = ye-1;
3165 if (ze==mz) lze = ze-1;
3166
3167 PetscFunctionBeginUser;
3169
3170 DMDAVecGetArray(fda,user->lUcont, &ucont);
3171 DMDAVecGetArray(da, user->lAj, &aj);
3172 VecDuplicate(user->P, &Div);
3173 DMDAVecGetArray(da, Div, &div);
3174 DMDAVecGetArray(da, user->lNvert, &nvert);
3175 DMDAVecGetArray(da, user->P, &p);
3176 for (k=lzs; k<lze; k++) {
3177 for (j=lys; j<lye; j++){
3178 for (i=lxs; i<lxe; i++) {
3179 if (k==10 && j==10 && i==1){
3180 LOG_ALLOW(LOCAL,LOG_INFO,"Pressure[10][10][1] = %f | Pressure[10][10][0] = %f \n ",p[k][j][i],p[k][j][i-1]);
3181 }
3182
3183 if (k==10 && j==10 && i==mx-3)
3184 LOG_ALLOW(LOCAL,LOG_INFO,"Pressure[10][10][%d] = %f | Pressure[10][10][%d] = %f \n ",mx-2,p[k][j][mx-2],mx-1,p[k][j][mx-1]);
3185 }
3186 }
3187 }
3188 DMDAVecRestoreArray(da, user->P, &p);
3189
3190
3191 for (k=lzs; k<lze; k++) {
3192 for (j=lys; j<lye; j++) {
3193 for (i=lxs; i<lxe; i++) {
3194 maxdiv = fabs((ucont[k][j][i].x - ucont[k][j][i-1].x +
3195 ucont[k][j][i].y - ucont[k][j-1][i].y +
3196 ucont[k][j][i].z - ucont[k-1][j][i].z)*aj[k][j][i]);
3197 if (nvert[k][j][i] + nvert[k+1][j][i] + nvert[k-1][j][i] +
3198 nvert[k][j+1][i] + nvert[k][j-1][i] +
3199 nvert[k][j][i+1] + nvert[k][j][i-1] > 0.1) maxdiv = 0.;
3200 div[k][j][i] = maxdiv;
3201
3202 }
3203 }
3204 }
3205
3206 if (zs==0) {
3207 k=0;
3208 for (j=ys; j<ye; j++) {
3209 for (i=xs; i<xe; i++) {
3210 div[k][j][i] = 0.;
3211 }
3212 }
3213 }
3214
3215 if (ze == mz) {
3216 k=mz-1;
3217 for (j=ys; j<ye; j++) {
3218 for (i=xs; i<xe; i++) {
3219 div[k][j][i] = 0.;
3220 }
3221 }
3222 }
3223
3224 if (xs==0) {
3225 i=0;
3226 for (k=zs; k<ze; k++) {
3227 for (j=ys; j<ye; j++) {
3228 div[k][j][i] = 0.;
3229 }
3230 }
3231 }
3232
3233 if (xe==mx) {
3234 i=mx-1;
3235 for (k=zs; k<ze; k++) {
3236 for (j=ys; j<ye; j++) {
3237 div[k][j][i] = 0;
3238 }
3239 }
3240 }
3241
3242 if (ys==0) {
3243 j=0;
3244 for (k=zs; k<ze; k++) {
3245 for (i=xs; i<xe; i++) {
3246 div[k][j][i] = 0.;
3247 }
3248 }
3249 }
3250
3251 if (ye==my) {
3252 j=my-1;
3253 for (k=zs; k<ze; k++) {
3254 for (i=xs; i<xe; i++) {
3255 div[k][j][i] = 0.;
3256 }
3257 }
3258 }
3259 DMDAVecRestoreArray(da, Div, &div);
3260 PetscInt MaxFlatIndex;
3261
3262 VecMax(Div, &MaxFlatIndex, &maxdiv);
3263
3264 LOG_ALLOW(GLOBAL,LOG_INFO,"[Step %d]] The Maximum Divergence is %e at flat index %d.\n",ti,maxdiv,MaxFlatIndex);
3265
3266 user->simCtx->MaxDivFlatArg = MaxFlatIndex;
3267 user->simCtx->MaxDiv = maxdiv;
3268
3269 for (k=zs; k<ze; k++) {
3270 for (j=ys; j<ye; j++) {
3271 for (i=xs; i<xe; i++) {
3272 if (Gidx(i,j,k,user) == MaxFlatIndex) {
3273 LOG_ALLOW(GLOBAL,LOG_INFO,"[Step %d] The Maximum Divergence(%e) is at location [%d][%d][%d]. \n", ti, maxdiv,k,j,i);
3274 user->simCtx->MaxDivz = k;
3275 user->simCtx->MaxDivy = j;
3276 user->simCtx->MaxDivx = i;
3277 }
3278 }
3279 }
3280 }
3281
3282
3283 DMDAVecRestoreArray(da, user->lNvert, &nvert);
3284 DMDAVecRestoreArray(fda, user->lUcont, &ucont);
3285 DMDAVecRestoreArray(da, user->lAj, &aj);
3286 VecDestroy(&Div);
3287
3289 PetscFunctionReturn(0);
3290}
static PetscInt Gidx(PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
Internal helper implementation: Gidx().
Definition setup.c:3109
DMDALocalInfo info
Definition variables.h:883
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitializeRandomGenerators()

PetscErrorCode InitializeRandomGenerators ( UserCtx user,
PetscRandom *  randx,
PetscRandom *  randy,
PetscRandom *  randz 
)

Initializes random number generators for assigning particle properties.

This function creates and configures separate PETSc random number generators for the x, y, and z coordinates.

Parameters
[in,out]userPointer to the UserCtx structure containing simulation context.
[out]randxPointer to store the RNG for the x-coordinate.
[out]randyPointer to store the RNG for the y-coordinate.
[out]randzPointer to store the RNG for the z-coordinate.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Initializes random number generators for assigning particle properties.

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

See also
InitializeRandomGenerators()

Definition at line 3301 of file setup.c.

3301 {
3302 PetscErrorCode ierr; // Error code for PETSc functions
3303 PetscMPIInt rank;
3304 PetscFunctionBeginUser;
3306 MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
3307
3308 // Initialize RNG for x-coordinate
3309 ierr = PetscRandomCreate(PETSC_COMM_SELF, randx); CHKERRQ(ierr);
3310 ierr = PetscRandomSetType((*randx), PETSCRAND48); CHKERRQ(ierr);
3311 ierr = PetscRandomSetInterval(*randx, user->bbox.min_coords.x, user->bbox.max_coords.x); CHKERRQ(ierr);
3312 ierr = PetscRandomSetSeed(*randx, rank + 12345); CHKERRQ(ierr); // Unique seed per rank
3313 ierr = PetscRandomSeed(*randx); CHKERRQ(ierr);
3314 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for X-axis.\n",rank);
3315
3316 // Initialize RNG for y-coordinate
3317 ierr = PetscRandomCreate(PETSC_COMM_SELF, randy); CHKERRQ(ierr);
3318 ierr = PetscRandomSetType((*randy), PETSCRAND48); CHKERRQ(ierr);
3319 ierr = PetscRandomSetInterval(*randy, user->bbox.min_coords.y, user->bbox.max_coords.y); CHKERRQ(ierr);
3320 ierr = PetscRandomSetSeed(*randy, rank + 67890); CHKERRQ(ierr); // Unique seed per rank
3321 ierr = PetscRandomSeed(*randy); CHKERRQ(ierr);
3322 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for Y-axis.\n",rank);
3323
3324 // Initialize RNG for z-coordinate
3325 ierr = PetscRandomCreate(PETSC_COMM_SELF, randz); CHKERRQ(ierr);
3326 ierr = PetscRandomSetType((*randz), PETSCRAND48); CHKERRQ(ierr);
3327 ierr = PetscRandomSetInterval(*randz, user->bbox.min_coords.z, user->bbox.max_coords.z); CHKERRQ(ierr);
3328 ierr = PetscRandomSetSeed(*randz, rank + 54321); CHKERRQ(ierr); // Unique seed per rank
3329 ierr = PetscRandomSeed(*randz); CHKERRQ(ierr);
3330 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for Z-axis.\n",rank);
3331
3333 PetscFunctionReturn(0);
3334}
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:33
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:171
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:170
BoundingBox bbox
Definition variables.h:887
Here is the caller graph for this function:

◆ InitializeLogicalSpaceRNGs()

PetscErrorCode InitializeLogicalSpaceRNGs ( PetscRandom *  rand_logic_i,
PetscRandom *  rand_logic_j,
PetscRandom *  rand_logic_k 
)

Initializes random number generators for logical space operations [0.0, 1.0).

This function creates and configures three separate PETSc random number generators, one for each logical dimension (i, j, k or xi, eta, zeta equivalent). Each RNG is configured to produce uniformly distributed real numbers in the interval [0.0, 1.0). These are typically used for selecting owned cells or generating intra-cell logical coordinates.

Parameters
[out]rand_logic_iPointer to store the RNG for the i-logical dimension.
[out]rand_logic_jPointer to store the RNG for the j-logical dimension.
[out]rand_logic_kPointer to store the RNG for the k-logical dimension.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Initializes random number generators for logical space operations [0.0, 1.0).

Local to this translation unit.

Definition at line 3342 of file setup.c.

3342 {
3343 PetscErrorCode ierr;
3344 PetscMPIInt rank;
3345 PetscFunctionBeginUser;
3346
3348
3349 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3350
3351 // --- RNG for i-logical dimension ---
3352 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_i); CHKERRQ(ierr);
3353 ierr = PetscRandomSetType((*rand_logic_i), PETSCRAND48); CHKERRQ(ierr);
3354 ierr = PetscRandomSetInterval(*rand_logic_i, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
3355 ierr = PetscRandomSetSeed(*rand_logic_i, rank + 202401); CHKERRQ(ierr); // Unique seed
3356 ierr = PetscRandomSeed(*rand_logic_i); CHKERRQ(ierr);
3357 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for i-logical dimension [0,1).\n",rank);
3358
3359 // --- RNG for j-logical dimension ---
3360 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_j); CHKERRQ(ierr);
3361 ierr = PetscRandomSetType((*rand_logic_j), PETSCRAND48); CHKERRQ(ierr);
3362 ierr = PetscRandomSetInterval(*rand_logic_j, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
3363 ierr = PetscRandomSetSeed(*rand_logic_j, rank + 202402); CHKERRQ(ierr);
3364 ierr = PetscRandomSeed(*rand_logic_j); CHKERRQ(ierr);
3365 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for j-logical dimension [0,1).\n",rank);
3366
3367 // --- RNG for k-logical dimension ---
3368 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_k); CHKERRQ(ierr);
3369 ierr = PetscRandomSetType((*rand_logic_k), PETSCRAND48); CHKERRQ(ierr);
3370 ierr = PetscRandomSetInterval(*rand_logic_k, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
3371 ierr = PetscRandomSetSeed(*rand_logic_k, rank + 202403); CHKERRQ(ierr);
3372 ierr = PetscRandomSeed(*rand_logic_k); CHKERRQ(ierr);
3373 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for k-logical dimension [0,1).\n",rank);
3374
3375
3377 PetscFunctionReturn(0);
3378}
Here is the caller graph for this function:

◆ InitializeBrownianRNG()

PetscErrorCode InitializeBrownianRNG ( SimCtx simCtx)

Initializes a single master RNG for time-stepping physics (Brownian motion).

Configures it for Uniform [0, 1) which is required for Box-Muller transformation.

Parameters
[in,out]simCtxPointer to the Simulation Context.
Returns
PetscErrorCode

Initializes a single master RNG for time-stepping physics (Brownian motion).

Local to this translation unit.

Definition at line 3386 of file setup.c.

3386 {
3387 PetscErrorCode ierr;
3388 PetscMPIInt rank;
3389
3390 PetscFunctionBeginUser;
3392
3393 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3394
3395 // 1. Create the generator (stored in SimCtx, not UserCtx, as it is global physics)
3396 ierr = PetscRandomCreate(PETSC_COMM_WORLD, &simCtx->BrownianMotionRNG); CHKERRQ(ierr);
3397 ierr = PetscRandomSetType(simCtx->BrownianMotionRNG, PETSCRAND48); CHKERRQ(ierr);
3398
3399 // 2. CRITICAL: Set interval to [0, 1).
3400 // This is required for the Gaussian math to work.
3401 ierr = PetscRandomSetInterval(simCtx->BrownianMotionRNG, 0.0, 1.0); CHKERRQ(ierr);
3402
3403 // 3. Seed based on Rank to ensure spatial randomness
3404 // Multiplying by a large prime helps separate the streams significantly
3405 unsigned long seed = (unsigned long)rank * 987654321 + (unsigned long)time(NULL);
3406 ierr = PetscRandomSetSeed(simCtx->BrownianMotionRNG, seed); CHKERRQ(ierr);
3407 ierr = PetscRandomSeed(simCtx->BrownianMotionRNG); CHKERRQ(ierr);
3408
3409 LOG_ALLOW(LOCAL, LOG_VERBOSE, "[Rank %d] Initialized Brownian Physics RNG.\n", rank);
3410
3412 PetscFunctionReturn(0);
3413}
Here is the caller graph for this function:

◆ TransformScalarDerivativesToPhysical()

void TransformScalarDerivativesToPhysical ( PetscReal  jacobian,
Cmpnts  csi_metrics,
Cmpnts  eta_metrics,
Cmpnts  zet_metrics,
PetscReal  dPhi_dcsi,
PetscReal  dPhi_deta,
PetscReal  dPhi_dzet,
Cmpnts gradPhi 
)

Transforms scalar derivatives from computational space to physical space.

using the chain rule. Formula: dPhi/dx = J * ( dPhi/dCsi * dCsi/dx + dPhi/dEta * dEta/dx + ... )

Parameters
jacobianParameter jacobian passed to TransformScalarDerivativesToPhysical().
csi_metricsParameter csi_metrics passed to TransformScalarDerivativesToPhysical().
eta_metricsParameter eta_metrics passed to TransformScalarDerivativesToPhysical().
zet_metricsParameter zet_metrics passed to TransformScalarDerivativesToPhysical().
dPhi_dcsiParameter dPhi_dcsi passed to TransformScalarDerivativesToPhysical().
dPhi_detaParameter dPhi_deta passed to TransformScalarDerivativesToPhysical().
dPhi_dzetParameter dPhi_dzet passed to TransformScalarDerivativesToPhysical().
gradPhiParameter gradPhi passed to TransformScalarDerivativesToPhysical().

Transforms scalar derivatives from computational space to physical space.

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

See also
TransformScalarDerivativesToPhysical()

Definition at line 3425 of file setup.c.

3433{
3434 // Gradient X component
3435 gradPhi->x = jacobian * (dPhi_dcsi * csi_metrics.x + dPhi_deta * eta_metrics.x + dPhi_dzet * zet_metrics.x);
3436
3437 // Gradient Y component
3438 gradPhi->y = jacobian * (dPhi_dcsi * csi_metrics.y + dPhi_deta * eta_metrics.y + dPhi_dzet * zet_metrics.y);
3439
3440 // Gradient Z component
3441 gradPhi->z = jacobian * (dPhi_dcsi * csi_metrics.z + dPhi_deta * eta_metrics.z + dPhi_dzet * zet_metrics.z);
3442}
Here is the caller graph for this function:

◆ ComputeScalarFieldDerivatives()

PetscErrorCode ComputeScalarFieldDerivatives ( UserCtx user,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscReal ***  field_data,
Cmpnts grad 
)

Computes the gradient of a cell-centered SCALAR field at a specific grid point.

Parameters
userThe
iParameter i passed to ComputeScalarFieldDerivatives().
jParameter j passed to ComputeScalarFieldDerivatives().
kParameter k passed to ComputeScalarFieldDerivatives().
field_data3D
gradOutput:
Returns
PetscErrorCode

Computes the gradient of a cell-centered SCALAR field at a specific grid point.

Local to this translation unit.

Definition at line 3474 of file setup.c.

3476{
3477 PetscErrorCode ierr;
3478 Cmpnts ***csi, ***eta, ***zet;
3479 PetscReal ***jac;
3480 PetscReal d_csi, d_eta, d_zet;
3481
3482 PetscFunctionBeginUser;
3483
3484 // 1. Get read-only access to metrics
3485 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
3486 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
3487 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
3488 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
3489
3490 // 2. Compute derivatives in computational space (Central Difference)
3491 // Assumes ghosts are available at i+/-1
3492 d_csi = 0.5 * (field_data[k][j][i+1] - field_data[k][j][i-1]);
3493 d_eta = 0.5 * (field_data[k][j+1][i] - field_data[k][j-1][i]);
3494 d_zet = 0.5 * (field_data[k+1][j][i] - field_data[k-1][j][i]);
3495
3496 // 3. Transform to physical space
3498 csi[k][j][i], eta[k][j][i], zet[k][j][i],
3499 d_csi, d_eta, d_zet,
3500 grad);
3501
3502 // 4. Restore arrays
3503 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
3504 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
3505 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
3506 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
3507
3508 PetscFunctionReturn(0);
3509}
void TransformScalarDerivativesToPhysical(PetscReal jacobian, Cmpnts csi_metrics, Cmpnts eta_metrics, Cmpnts zet_metrics, PetscReal dPhi_dcsi, PetscReal dPhi_deta, PetscReal dPhi_dzet, Cmpnts *gradPhi)
Implementation of TransformScalarDerivativesToPhysical().
Definition setup.c:3425
Here is the call graph for this function:

◆ ComputeVectorFieldDerivatives()

PetscErrorCode ComputeVectorFieldDerivatives ( UserCtx user,
PetscInt  i,
PetscInt  j,
PetscInt  k,
Cmpnts ***  field_data,
Cmpnts dudx,
Cmpnts dvdx,
Cmpnts dwdx 
)

Computes the derivatives of a cell-centered vector field at a specific grid point.

This function orchestrates the calculation of spatial derivatives. It first computes the derivatives in computational space (d/dcsi, d/deta, d/dzet) using a central difference scheme and then transforms them into physical space (d/dx, d/dy, d/dz).

Parameters
userThe
iParameter i passed to ComputeVectorFieldDerivatives().
jParameter j passed to ComputeVectorFieldDerivatives().
kParameter k passed to ComputeVectorFieldDerivatives().
field_dataA
dudxOutput:
dvdxOutput:
dwdxOutput:
Returns
PetscErrorCode 0 on success.

Computes the derivatives of a cell-centered vector field at a specific grid point.

Local to this translation unit.

Definition at line 3517 of file setup.c.

3519{
3520 PetscErrorCode ierr;
3521 Cmpnts ***csi, ***eta, ***zet;
3522 PetscReal ***jac;
3523 PetscFunctionBeginUser;
3524
3525 // 1. Get read-only access to the necessary metric data arrays
3526 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
3527 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
3528 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
3529 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
3530
3531 // 2. Calculate derivatives in computational space using central differencing
3532 Cmpnts deriv_csi, deriv_eta, deriv_zet;
3533 deriv_csi.x = (field_data[k][j][i+1].x - field_data[k][j][i-1].x) * 0.5;
3534 deriv_csi.y = (field_data[k][j][i+1].y - field_data[k][j][i-1].y) * 0.5;
3535 deriv_csi.z = (field_data[k][j][i+1].z - field_data[k][j][i-1].z) * 0.5;
3536
3537 deriv_eta.x = (field_data[k][j+1][i].x - field_data[k][j-1][i].x) * 0.5;
3538 deriv_eta.y = (field_data[k][j+1][i].y - field_data[k][j-1][i].y) * 0.5;
3539 deriv_eta.z = (field_data[k][j+1][i].z - field_data[k][j-1][i].z) * 0.5;
3540
3541 deriv_zet.x = (field_data[k+1][j][i].x - field_data[k-1][j][i].x) * 0.5;
3542 deriv_zet.y = (field_data[k+1][j][i].y - field_data[k-1][j][i].y) * 0.5;
3543 deriv_zet.z = (field_data[k+1][j][i].z - field_data[k-1][j][i].z) * 0.5;
3544
3545 // 3. Transform derivatives to physical space
3546 TransformDerivativesToPhysical(jac[k][j][i], csi[k][j][i], eta[k][j][i], zet[k][j][i],
3547 deriv_csi, deriv_eta, deriv_zet,
3548 dudx, dvdx, dwdx);
3549
3550 // 4. Restore access to the PETSc data arrays
3551 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
3552 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
3553 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
3554 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
3555
3556 PetscFunctionReturn(0);
3557}
static void TransformDerivativesToPhysical(PetscReal jacobian, Cmpnts csi_metrics, Cmpnts eta_metrics, Cmpnts zet_metrics, Cmpnts deriv_csi, Cmpnts deriv_eta, Cmpnts deriv_zet, Cmpnts *dudx, Cmpnts *dvdx, Cmpnts *dwdx)
Internal helper implementation: TransformDerivativesToPhysical().
Definition setup.c:3450
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DestroyUserVectors()

PetscErrorCode DestroyUserVectors ( UserCtx user)

Destroys all PETSc Vec objects within a single UserCtx structure.

This helper function systematically destroys all ~74 Vec objects stored in a UserCtx. The vectors are organized into 14 groups (A-N) for clarity:

  • Primary flow fields (Ucont, Ucat, P, Nvert)
  • Solver work vectors (Phi)
  • Time-stepping vectors (Ucont_o, Ucont_rm1, etc.)
  • Grid metrics (cell-centered, face-centered, coordinates)
  • Turbulence vectors (Nu_t, CS, lFriction_Velocity)
  • Particle vectors (ParticleCount, Psi)
  • Boundary condition vectors (Ubcs, Uch)
  • Post-processing vectors (P_nodal, Qcrit)
  • Statistical averaging vectors (Ucat_sum, etc.)
  • And more...

All destroys are protected with NULL checks to handle conditional allocations safely.

Parameters
[in,out]userPointer to the UserCtx containing the vectors to destroy.
Returns
PetscErrorCode 0 on success.

Destroys all PETSc Vec objects within a single UserCtx structure.

Local to this translation unit.

Definition at line 3571 of file setup.c.

3572{
3573 PetscErrorCode ierr;
3574 PetscFunctionBeginUser;
3575
3576 // --- Group A: Primary Flow Fields (Always allocated at all levels) ---
3577 if (user->Ucont) { ierr = VecDestroy(&user->Ucont); CHKERRQ(ierr); }
3578 if (user->lUcont) { ierr = VecDestroy(&user->lUcont); CHKERRQ(ierr); }
3579 if (user->Ucat) { ierr = VecDestroy(&user->Ucat); CHKERRQ(ierr); }
3580 if (user->lUcat) { ierr = VecDestroy(&user->lUcat); CHKERRQ(ierr); }
3581 if (user->P) { ierr = VecDestroy(&user->P); CHKERRQ(ierr); }
3582 if (user->lP) { ierr = VecDestroy(&user->lP); CHKERRQ(ierr); }
3583 if (user->Nvert) { ierr = VecDestroy(&user->Nvert); CHKERRQ(ierr); }
3584 if (user->lNvert) { ierr = VecDestroy(&user->lNvert); CHKERRQ(ierr); }
3585
3586 // --- Group A2: Derived Flow Fields (Conditional) ---
3587 if(user->Diffusivity) {ierr = VecDestroy(&user->Diffusivity); CHKERRQ(ierr);}
3588 if(user->lDiffusivity){ierr = VecDestroy(&user->lDiffusivity); CHKERRQ(ierr);}
3589 if(user->DiffusivityGradient){ierr = VecDestroy(&user->DiffusivityGradient); CHKERRQ(ierr);}
3590 if(user->lDiffusivityGradient){ierr = VecDestroy(&user->lDiffusivityGradient); CHKERRQ(ierr);}
3591
3592 // --- Group B: Solver Work Vectors (All levels) ---
3593 if (user->Phi) { ierr = VecDestroy(&user->Phi); CHKERRQ(ierr); }
3594 if (user->lPhi) { ierr = VecDestroy(&user->lPhi); CHKERRQ(ierr); }
3595
3596 // --- Group C: Time-Stepping Vectors (Finest level only) ---
3597 if (user->Ucont_o) { ierr = VecDestroy(&user->Ucont_o); CHKERRQ(ierr); }
3598 if (user->Ucont_rm1) { ierr = VecDestroy(&user->Ucont_rm1); CHKERRQ(ierr); }
3599 if (user->Ucat_o) { ierr = VecDestroy(&user->Ucat_o); CHKERRQ(ierr); }
3600 if (user->P_o) { ierr = VecDestroy(&user->P_o); CHKERRQ(ierr); }
3601 if (user->Nvert_o) { ierr = VecDestroy(&user->Nvert_o); CHKERRQ(ierr); }
3602 if (user->lUcont_o) { ierr = VecDestroy(&user->lUcont_o); CHKERRQ(ierr); }
3603 if (user->lUcont_rm1) { ierr = VecDestroy(&user->lUcont_rm1); CHKERRQ(ierr); }
3604 if (user->lNvert_o) { ierr = VecDestroy(&user->lNvert_o); CHKERRQ(ierr); }
3605
3606 // --- Group D: Grid Metrics - Face Centered (All levels) ---
3607 if (user->Csi) { ierr = VecDestroy(&user->Csi); CHKERRQ(ierr); }
3608 if (user->Eta) { ierr = VecDestroy(&user->Eta); CHKERRQ(ierr); }
3609 if (user->Zet) { ierr = VecDestroy(&user->Zet); CHKERRQ(ierr); }
3610 if (user->Aj) { ierr = VecDestroy(&user->Aj); CHKERRQ(ierr); }
3611 if (user->lCsi) { ierr = VecDestroy(&user->lCsi); CHKERRQ(ierr); }
3612 if (user->lEta) { ierr = VecDestroy(&user->lEta); CHKERRQ(ierr); }
3613 if (user->lZet) { ierr = VecDestroy(&user->lZet); CHKERRQ(ierr); }
3614 if (user->lAj) { ierr = VecDestroy(&user->lAj); CHKERRQ(ierr); }
3615
3616 // --- Group E: Grid Metrics - Face Centered (All levels) ---
3617 if (user->ICsi) { ierr = VecDestroy(&user->ICsi); CHKERRQ(ierr); }
3618 if (user->IEta) { ierr = VecDestroy(&user->IEta); CHKERRQ(ierr); }
3619 if (user->IZet) { ierr = VecDestroy(&user->IZet); CHKERRQ(ierr); }
3620 if (user->JCsi) { ierr = VecDestroy(&user->JCsi); CHKERRQ(ierr); }
3621 if (user->JEta) { ierr = VecDestroy(&user->JEta); CHKERRQ(ierr); }
3622 if (user->JZet) { ierr = VecDestroy(&user->JZet); CHKERRQ(ierr); }
3623 if (user->KCsi) { ierr = VecDestroy(&user->KCsi); CHKERRQ(ierr); }
3624 if (user->KEta) { ierr = VecDestroy(&user->KEta); CHKERRQ(ierr); }
3625 if (user->KZet) { ierr = VecDestroy(&user->KZet); CHKERRQ(ierr); }
3626 if (user->IAj) { ierr = VecDestroy(&user->IAj); CHKERRQ(ierr); }
3627 if (user->JAj) { ierr = VecDestroy(&user->JAj); CHKERRQ(ierr); }
3628 if (user->KAj) { ierr = VecDestroy(&user->KAj); CHKERRQ(ierr); }
3629 if (user->lICsi) { ierr = VecDestroy(&user->lICsi); CHKERRQ(ierr); }
3630 if (user->lIEta) { ierr = VecDestroy(&user->lIEta); CHKERRQ(ierr); }
3631 if (user->lIZet) { ierr = VecDestroy(&user->lIZet); CHKERRQ(ierr); }
3632 if (user->lJCsi) { ierr = VecDestroy(&user->lJCsi); CHKERRQ(ierr); }
3633 if (user->lJEta) { ierr = VecDestroy(&user->lJEta); CHKERRQ(ierr); }
3634 if (user->lJZet) { ierr = VecDestroy(&user->lJZet); CHKERRQ(ierr); }
3635 if (user->lKCsi) { ierr = VecDestroy(&user->lKCsi); CHKERRQ(ierr); }
3636 if (user->lKEta) { ierr = VecDestroy(&user->lKEta); CHKERRQ(ierr); }
3637 if (user->lKZet) { ierr = VecDestroy(&user->lKZet); CHKERRQ(ierr); }
3638 if (user->lIAj) { ierr = VecDestroy(&user->lIAj); CHKERRQ(ierr); }
3639 if (user->lJAj) { ierr = VecDestroy(&user->lJAj); CHKERRQ(ierr); }
3640 if (user->lKAj) { ierr = VecDestroy(&user->lKAj); CHKERRQ(ierr); }
3641
3642 // --- Group F: Cell/Face Coordinates and Grid Spacing (All levels) ---
3643 if (user->Cent) { ierr = VecDestroy(&user->Cent); CHKERRQ(ierr); }
3644 if (user->lCent) { ierr = VecDestroy(&user->lCent); CHKERRQ(ierr); }
3645 if (user->GridSpace) { ierr = VecDestroy(&user->GridSpace); CHKERRQ(ierr); }
3646 if (user->lGridSpace) { ierr = VecDestroy(&user->lGridSpace); CHKERRQ(ierr); }
3647 if (user->Centx) { ierr = VecDestroy(&user->Centx); CHKERRQ(ierr); }
3648 if (user->Centy) { ierr = VecDestroy(&user->Centy); CHKERRQ(ierr); }
3649 if (user->Centz) { ierr = VecDestroy(&user->Centz); CHKERRQ(ierr); }
3650 if (user->lCentx) { ierr = VecDestroy(&user->lCentx); CHKERRQ(ierr); }
3651 if (user->lCenty) { ierr = VecDestroy(&user->lCenty); CHKERRQ(ierr); }
3652 if (user->lCentz) { ierr = VecDestroy(&user->lCentz); CHKERRQ(ierr); }
3653
3654 // --- Group G: Turbulence Model Vectors (Finest level, conditional on les/rans) ---
3655 if (user->Nu_t) { ierr = VecDestroy(&user->Nu_t); CHKERRQ(ierr); }
3656 if (user->lNu_t) { ierr = VecDestroy(&user->lNu_t); CHKERRQ(ierr); }
3657 if (user->CS) { ierr = VecDestroy(&user->CS); CHKERRQ(ierr); }
3658 if (user->lCs) { ierr = VecDestroy(&user->lCs); CHKERRQ(ierr); }
3659 if (user->lFriction_Velocity) { ierr = VecDestroy(&user->lFriction_Velocity); CHKERRQ(ierr); }
3660 if (user->K_Omega) { ierr = VecDestroy(&user->K_Omega); CHKERRQ(ierr); }
3661 if (user->lK_Omega) { ierr = VecDestroy(&user->lK_Omega); CHKERRQ(ierr); }
3662 if (user->K_Omega_o) { ierr = VecDestroy(&user->K_Omega_o); CHKERRQ(ierr); }
3663 if (user->lK_Omega_o) { ierr = VecDestroy(&user->lK_Omega_o); CHKERRQ(ierr); }
3664
3665 // --- Group H: Particle Vectors (Finest level, conditional on np > 0) ---
3666 if (user->ParticleCount) { ierr = VecDestroy(&user->ParticleCount); CHKERRQ(ierr); }
3667 if (user->lParticleCount) { ierr = VecDestroy(&user->lParticleCount); CHKERRQ(ierr); }
3668 if (user->Psi) { ierr = VecDestroy(&user->Psi); CHKERRQ(ierr); }
3669 if (user->lPsi) { ierr = VecDestroy(&user->lPsi); CHKERRQ(ierr); }
3670
3671 // --- Group I: Boundary Condition Vectors (All levels) ---
3672 if (user->Bcs.Ubcs) { ierr = VecDestroy(&user->Bcs.Ubcs); CHKERRQ(ierr); }
3673 if (user->Bcs.Uch) { ierr = VecDestroy(&user->Bcs.Uch); CHKERRQ(ierr); }
3674
3675 // --- Group J: Post-Processing Vectors (Finest level, postprocessor mode) ---
3676 if (user->P_nodal) { ierr = VecDestroy(&user->P_nodal); CHKERRQ(ierr); }
3677 if (user->Ucat_nodal) { ierr = VecDestroy(&user->Ucat_nodal); CHKERRQ(ierr); }
3678 if (user->Qcrit) { ierr = VecDestroy(&user->Qcrit); CHKERRQ(ierr); }
3679 if (user->Psi_nodal) { ierr = VecDestroy(&user->Psi_nodal); CHKERRQ(ierr); }
3680
3681 // --- Group K: Interpolation Vectors (Lazy allocation) ---
3682 if (user->CellFieldAtCorner) { ierr = VecDestroy(&user->CellFieldAtCorner); CHKERRQ(ierr); }
3683 if (user->lCellFieldAtCorner) { ierr = VecDestroy(&user->lCellFieldAtCorner); CHKERRQ(ierr); }
3684
3685 // --- Group L: Statistical Averaging Vectors (If allocated) ---
3686 if (user->Ucat_sum) { ierr = VecDestroy(&user->Ucat_sum); CHKERRQ(ierr); }
3687 if (user->Ucat_cross_sum) { ierr = VecDestroy(&user->Ucat_cross_sum); CHKERRQ(ierr); }
3688 if (user->Ucat_square_sum) { ierr = VecDestroy(&user->Ucat_square_sum); CHKERRQ(ierr); }
3689 if (user->P_sum) { ierr = VecDestroy(&user->P_sum); CHKERRQ(ierr); }
3690
3691 // --- Group M: Implicit Solver Temporary Vectors (Destroyed after use, but check anyway) ---
3692 if (user->Rhs) { ierr = VecDestroy(&user->Rhs); CHKERRQ(ierr); }
3693 if (user->dUcont) { ierr = VecDestroy(&user->dUcont); CHKERRQ(ierr); }
3694 if (user->pUcont) { ierr = VecDestroy(&user->pUcont); CHKERRQ(ierr); }
3695
3696 // --- Group N: Poisson Solver Vectors (Destroyed after solve, but check anyway) ---
3697 if (user->B) { ierr = VecDestroy(&user->B); CHKERRQ(ierr); }
3698 if (user->R) { ierr = VecDestroy(&user->R); CHKERRQ(ierr); }
3699
3700 LOG_ALLOW(LOCAL, LOG_DEBUG, "All vectors destroyed for UserCtx.\n");
3701 PetscFunctionReturn(0);
3702}
Vec Rhs
Definition variables.h:912
Vec lCellFieldAtCorner
Definition variables.h:915
Vec Ucat_square_sum
Definition variables.h:938
Vec P_sum
Definition variables.h:938
Vec pUcont
Definition variables.h:912
Vec CellFieldAtCorner
Definition variables.h:915
Vec Ucat_sum
Definition variables.h:938
Vec dUcont
Definition variables.h:912
Vec Ucat_cross_sum
Definition variables.h:938
Here is the caller graph for this function:

◆ DestroyUserContext()

PetscErrorCode DestroyUserContext ( UserCtx user)

Destroys all resources allocated within a single UserCtx structure.

This function cleans up all memory and PETSc objects associated with a single UserCtx (grid level). It calls the helper functions and destroys remaining objects in the proper dependency order:

  1. Boundary conditions (handlers and their data)
  2. All PETSc vectors (via DestroyUserVectors)
  3. Matrix and solver objects (A, C, MR, MP, ksp, nullsp)
  4. Application ordering (AO)
  5. Distributed mesh objects (DMs) - most derived first
  6. Raw PetscMalloc'd arrays (RankCellInfoMap, KSKE)

This function should be called for each UserCtx in the multigrid hierarchy.

Parameters
[in,out]userPointer to the UserCtx to be destroyed.
Returns
PetscErrorCode 0 on success.

Destroys all resources allocated within a single UserCtx structure.

Local to this translation unit.

Definition at line 3709 of file setup.c.

3710{
3711 PetscErrorCode ierr;
3712 PetscFunctionBeginUser;
3713
3714 if (!user) {
3715 LOG_ALLOW(LOCAL, LOG_WARNING, "DestroyUserContext called with NULL user pointer.\n");
3716 PetscFunctionReturn(0);
3717 }
3718
3719 LOG_ALLOW(LOCAL, LOG_INFO, "Destroying UserCtx at level %d...\n", user->thislevel);
3720
3721 // --- Step 1: Destroy Boundary Condition System ---
3722 // This handles all BC handlers and their private data.
3723 ierr = BoundarySystem_Destroy(user); CHKERRQ(ierr);
3724 LOG_ALLOW(LOCAL, LOG_DEBUG, " Boundary system destroyed.\n");
3725
3726 // --- Step 2: Destroy All Vectors ---
3727 // Handles ~74 Vec objects with proper NULL checking.
3728 ierr = DestroyUserVectors(user); CHKERRQ(ierr);
3729 LOG_ALLOW(LOCAL, LOG_DEBUG, " All vectors destroyed.\n");
3730
3731 // --- Step 3: Destroy Matrix and Solver Objects ---
3732 // Destroy pressure-Poisson matrices and solver.
3733 if (user->A) {
3734 ierr = MatDestroy(&user->A); CHKERRQ(ierr);
3735 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix A destroyed.\n");
3736 }
3737 if (user->C) {
3738 ierr = MatDestroy(&user->C); CHKERRQ(ierr);
3739 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix C destroyed.\n");
3740 }
3741 if (user->MR) {
3742 ierr = MatDestroy(&user->MR); CHKERRQ(ierr);
3743 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix MR destroyed.\n");
3744 }
3745 if (user->MP) {
3746 ierr = MatDestroy(&user->MP); CHKERRQ(ierr);
3747 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix MP destroyed.\n");
3748 }
3749 if (user->ksp) {
3750 ierr = KSPDestroy(&user->ksp); CHKERRQ(ierr);
3751 LOG_ALLOW(LOCAL, LOG_DEBUG, " KSP solver destroyed.\n");
3752 }
3753 if (user->nullsp) {
3754 ierr = MatNullSpaceDestroy(&user->nullsp); CHKERRQ(ierr);
3755 LOG_ALLOW(LOCAL, LOG_DEBUG, " MatNullSpace destroyed.\n");
3756 }
3757
3758 // --- Step 4: Destroy Application Ordering ---
3759 if (user->ao) {
3760 ierr = AODestroy(&user->ao); CHKERRQ(ierr);
3761 LOG_ALLOW(LOCAL, LOG_DEBUG, " AO destroyed.\n");
3762 }
3763
3764 // --- Step 5: Destroy DM Objects ---
3765 // Destroy in reverse order of dependency: post_swarm, swarm, fda2, fda, da
3766 if (user->post_swarm) {
3767 ierr = DMDestroy(&user->post_swarm); CHKERRQ(ierr);
3768 LOG_ALLOW(LOCAL, LOG_DEBUG, " post_swarm DM destroyed.\n");
3769 }
3770 if (user->swarm) {
3771 ierr = DMDestroy(&user->swarm); CHKERRQ(ierr);
3772 LOG_ALLOW(LOCAL, LOG_DEBUG, " swarm DM destroyed.\n");
3773 }
3774 if (user->fda2) {
3775 ierr = DMDestroy(&user->fda2); CHKERRQ(ierr);
3776 LOG_ALLOW(LOCAL, LOG_DEBUG, " fda2 DM destroyed.\n");
3777 }
3778 if (user->da) {
3779 ierr = DMDestroy(&user->da); CHKERRQ(ierr);
3780 LOG_ALLOW(LOCAL, LOG_DEBUG, " da DM destroyed.\n");
3781 }
3782
3783 // --- Step 6: Free PetscMalloc'd Arrays ---
3784 // Free arrays allocated with PetscMalloc1
3785 if (user->RankCellInfoMap) {
3786 ierr = PetscFree(user->RankCellInfoMap); CHKERRQ(ierr);
3787 user->RankCellInfoMap = NULL;
3788 LOG_ALLOW(LOCAL, LOG_DEBUG, " RankCellInfoMap freed.\n");
3789 }
3790 if (user->KSKE) {
3791 ierr = PetscFree(user->KSKE); CHKERRQ(ierr);
3792 user->KSKE = NULL;
3793 LOG_ALLOW(LOCAL, LOG_DEBUG, " KSKE array freed.\n");
3794 }
3795
3796 LOG_ALLOW(LOCAL, LOG_INFO, "UserCtx at level %d fully destroyed.\n", user->thislevel);
3797 PetscFunctionReturn(0);
3798}
PetscErrorCode BoundarySystem_Destroy(UserCtx *user)
Cleans up and destroys all boundary system resources.
PetscErrorCode DestroyUserVectors(UserCtx *user)
Internal helper implementation: DestroyUserVectors().
Definition setup.c:3571
MatNullSpace nullsp
Definition variables.h:918
PetscInt * KSKE
Definition variables.h:919
DM post_swarm
Definition variables.h:956
PetscInt thislevel
Definition variables.h:944
KSP ksp
Definition variables.h:918
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FinalizeSimulation()

PetscErrorCode FinalizeSimulation ( SimCtx simCtx)

Main cleanup function for the entire simulation context.

This function is responsible for destroying ALL memory and PETSc objects allocated during the simulation, including:

  • All UserCtx structures in the multigrid hierarchy (via DestroyUserContext)
  • The multigrid management structures (UserMG, MGCtx array)
  • All SimCtx-level objects (logviewer, dm_swarm, bboxlist, string arrays, etc.)
  • The SimCtx allocation itself.

This function should be called ONCE at the end of the simulation, after all computation is complete, but BEFORE PetscFinalize().

Call order in main:

  1. [Simulation runs]
  2. ProfilingFinalize(simCtx);
  3. FinalizeSimulation(simCtx); <- This function
  4. PetscFinalize();
Parameters
[in,out]simCtxPointer to the master SimulationContext to be destroyed. The pointer is invalid after this call returns.
Returns
PetscErrorCode 0 on success.

Main cleanup function for the entire simulation context.

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

See also
FinalizeSimulation()

Definition at line 3808 of file setup.c.

3809{
3810 PetscErrorCode ierr;
3811 PetscFunctionBeginUser;
3812
3813 if (!simCtx) {
3814 LOG_ALLOW(GLOBAL, LOG_WARNING, "FinalizeSimulation called with NULL SimCtx pointer.\n");
3815 PetscFunctionReturn(0);
3816 }
3817
3818 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
3819 LOG_ALLOW(GLOBAL, LOG_INFO, "Beginning simulation memory cleanup...\n");
3820 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
3821
3822 // ============================================================================
3823 // PHASE 1: DESTROY MULTIGRID HIERARCHY (All UserCtx structures)
3824 // ============================================================================
3825
3826 ierr = DestroySolutionConvergenceState(simCtx); CHKERRQ(ierr);
3827
3828 if (simCtx->usermg.mgctx) {
3829 LOG_ALLOW(GLOBAL, LOG_INFO, "Destroying multigrid hierarchy (%d levels)...\n",
3830 simCtx->usermg.mglevels);
3831
3832 // Destroy each UserCtx from finest to coarsest (reverse order is safer)
3833 for (PetscInt level = simCtx->usermg.mglevels - 1; level >= 0; level--) {
3834 UserCtx *user = simCtx->usermg.mgctx[level].user;
3835 if (user) {
3836 LOG_ALLOW(LOCAL, LOG_INFO, " Destroying level %d of %d...\n",
3837 level, simCtx->usermg.mglevels - 1);
3838 ierr = DestroyUserContext(user); CHKERRQ(ierr);
3839
3840 // Free the UserCtx structure itself
3841 ierr = PetscFree(user); CHKERRQ(ierr);
3842 simCtx->usermg.mgctx[level].user = NULL;
3843 }
3844
3845 // Destroy the MGCtx-level packer DM
3846 if (simCtx->usermg.mgctx[level].packer) {
3847 ierr = DMDestroy(&simCtx->usermg.mgctx[level].packer); CHKERRQ(ierr);
3848 LOG_ALLOW(LOCAL, LOG_DEBUG, " MGCtx[%d].packer destroyed.\n", level);
3849 }
3850 }
3851
3852 // Free the MGCtx array itself
3853 ierr = PetscFree(simCtx->usermg.mgctx); CHKERRQ(ierr);
3854 simCtx->usermg.mgctx = NULL;
3855 LOG_ALLOW(GLOBAL, LOG_INFO, "All multigrid levels destroyed.\n");
3856 }
3857
3858 // ============================================================================
3859 // PHASE 2: DESTROY USERMG-LEVEL OBJECTS
3860 // ============================================================================
3861
3862 if (simCtx->usermg.packer) {
3863 ierr = DMDestroy(&simCtx->usermg.packer); CHKERRQ(ierr);
3864 LOG_ALLOW(LOCAL, LOG_DEBUG, "UserMG.packer DM destroyed.\n");
3865 }
3866
3867 if (simCtx->usermg.snespacker) {
3868 ierr = SNESDestroy(&simCtx->usermg.snespacker); CHKERRQ(ierr);
3869 LOG_ALLOW(LOCAL, LOG_DEBUG, "UserMG.snespacker SNES destroyed.\n");
3870 }
3871
3872 // ============================================================================
3873 // PHASE 3: DESTROY SIMCTX-LEVEL OBJECTS
3874 // ============================================================================
3875
3876 LOG_ALLOW(GLOBAL, LOG_INFO, "Destroying SimCtx-level objects...\n");
3877
3878 // --- PetscViewer for logging ---
3879 if (simCtx->logviewer) {
3880 ierr = PetscViewerDestroy(&simCtx->logviewer); CHKERRQ(ierr);
3881 LOG_ALLOW(LOCAL, LOG_DEBUG, " logviewer destroyed.\n");
3882 }
3883
3884 // --- Particle System DM ---
3885 if (simCtx->dm_swarm) {
3886 ierr = DMDestroy(&simCtx->dm_swarm); CHKERRQ(ierr);
3887 LOG_ALLOW(LOCAL, LOG_DEBUG, " dm_swarm destroyed.\n");
3888 }
3889
3890 // --- BoundingBox List (Array of BoundingBox structs) ---
3891 if (simCtx->bboxlist) {
3892 ierr = PetscFree(simCtx->bboxlist); CHKERRQ(ierr);
3893 simCtx->bboxlist = NULL;
3894 LOG_ALLOW(LOCAL, LOG_DEBUG, " bboxlist freed.\n");
3895 }
3896
3897 // --- Boundary Condition Files (Array of strings) ---
3898 if (simCtx->bcs_files) {
3899 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
3900 if (simCtx->bcs_files[i]) {
3901 ierr = PetscFree(simCtx->bcs_files[i]); CHKERRQ(ierr);
3902 }
3903 }
3904 ierr = PetscFree(simCtx->bcs_files); CHKERRQ(ierr);
3905 simCtx->bcs_files = NULL;
3906 LOG_ALLOW(LOCAL, LOG_DEBUG, " bcs_files array freed (%d files).\n", simCtx->num_bcs_files);
3907 }
3908
3909 // --- Brownian Motion RNG ---
3910 if (simCtx->BrownianMotionRNG) {
3911 ierr = PetscRandomDestroy(&simCtx->BrownianMotionRNG); CHKERRQ(ierr);
3912 LOG_ALLOW(LOCAL, LOG_DEBUG, " BrownianMotionRNG destroyed.\n");
3913 }
3914 // --- Post-Processing Parameters ---
3915 // pps is allocated with PetscNew and contains only static char arrays and basic types.
3916 // No internal dynamic allocations need to be freed.
3917 if (simCtx->pps) {
3918 ierr = PetscFree(simCtx->pps); CHKERRQ(ierr);
3919 simCtx->pps = NULL;
3920 LOG_ALLOW(LOCAL, LOG_DEBUG, " PostProcessParams freed.\n");
3921 }
3922
3923 // --- IBM/FSI Objects ---
3924 // Note: These are initialized to NULL and currently have no dedicated destroy functions.
3925 // If these modules are extended with cleanup routines, call them here.
3926 if (simCtx->ibm != NULL) {
3927 LOG_ALLOW(GLOBAL, LOG_WARNING, " WARNING: simCtx->ibm is non-NULL but no destroy function exists. Potential memory leak.\n");
3928 }
3929 if (simCtx->ibmv != NULL) {
3930 LOG_ALLOW(GLOBAL, LOG_WARNING, " WARNING: simCtx->ibmv is non-NULL but no destroy function exists. Potential memory leak.\n");
3931 }
3932 if (simCtx->fsi != NULL) {
3933 LOG_ALLOW(GLOBAL, LOG_WARNING, " WARNING: simCtx->fsi is non-NULL but no destroy function exists. Potential memory leak.\n");
3934 }
3935
3936 // --- Logging Allowed Functions (Array of strings) ---
3937 // Note: The logging system maintains its own copy via set_allowed_functions(),
3938 // so freeing simCtx->allowedFuncs will NOT affect LOG_ALLOW functionality.
3939 if (simCtx->allowedFuncs) {
3940 for (PetscInt i = 0; i < simCtx->nAllowed; i++) {
3941 if (simCtx->allowedFuncs[i]) {
3942 ierr = PetscFree(simCtx->allowedFuncs[i]); CHKERRQ(ierr);
3943 }
3944 }
3945 ierr = PetscFree(simCtx->allowedFuncs); CHKERRQ(ierr);
3946 simCtx->allowedFuncs = NULL;
3947 LOG_ALLOW(LOCAL, LOG_DEBUG, " allowedFuncs array freed (%d functions).\n", simCtx->nAllowed);
3948 }
3949
3950 // --- Profiling Critical Functions (Array of strings) ---
3951 if (simCtx->profilingSelectedFuncs) {
3952 for (PetscInt i = 0; i < simCtx->nProfilingSelectedFuncs; i++) {
3953 if (simCtx->profilingSelectedFuncs[i]) {
3954 ierr = PetscFree(simCtx->profilingSelectedFuncs[i]); CHKERRQ(ierr);
3955 }
3956 }
3957 ierr = PetscFree(simCtx->profilingSelectedFuncs); CHKERRQ(ierr);
3958 simCtx->profilingSelectedFuncs = NULL;
3959 LOG_ALLOW(LOCAL, LOG_DEBUG, " profilingSelectedFuncs array freed (%d functions).\n", simCtx->nProfilingSelectedFuncs);
3960 }
3961
3962 // ============================================================================
3963 // PHASE 4: FINAL SUMMARY
3964 // ============================================================================
3965
3966 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
3967 LOG_ALLOW(GLOBAL, LOG_INFO, "Simulation cleanup completed successfully.\n");
3968 LOG_ALLOW(GLOBAL, LOG_INFO, "All PETSc objects have been destroyed.\n");
3969 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
3970
3971 ierr = PetscFree(simCtx); CHKERRQ(ierr);
3972 PetscFunctionReturn(0);
3973}
PetscErrorCode DestroyUserContext(UserCtx *user)
Internal helper implementation: DestroyUserContext().
Definition setup.c:3709
PetscErrorCode DestroySolutionConvergenceState(SimCtx *simCtx)
Implementation of DestroySolutionConvergenceState().
Definition setup.c:98
DM packer
Definition variables.h:580
SNES snespacker
Definition variables.h:581
DM packer
Definition variables.h:571
Here is the call graph for this function:
Here is the caller graph for this function: