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 "field_catalog.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

int PicurvHandleVersionArgument (int argc, char **argv, const char *executable_name)
 Print the shared native build identity when a version flag is present.
 
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, FieldId field_id)
 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 (PetscInt base_seed, 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 LESConfigSetDefaults (LESConfig *config)
 Installs the shipped defaults for every LES closure parameter.
 
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:2742
PetscErrorCode Allocate3DArrayVector(Cmpnts ****array, PetscInt nz, PetscInt ny, PetscInt nx)
Allocates a contiguous 3D array of Cmpnts values.
Definition setup.c:2820
A 3D point or vector with PetscScalar components.
Definition variables.h:121

Definition at line 41 of file setup.h.

45 )(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:2870
PetscErrorCode Deallocate3DArrayScalar(PetscReal ***array, PetscInt nz, PetscInt ny)
Deallocates a 3D array of PetscReal values allocated by Allocate3DArrayScalar.
Definition setup.c:2777

Definition at line 48 of file setup.h.

52 )(array, nz, ny)

Function Documentation

◆ PicurvHandleVersionArgument()

int PicurvHandleVersionArgument ( int  argc,
char **  argv,
const char *  executable_name 
)

Print the shared native build identity when a version flag is present.

Prints two lines: <name> <release>+g<commit>[.dirty], then the PETSc this binary was compiled against, petsc <version> <debug|optimized> <arch> <dir>. The second line is also kept in the binary behind a PICURV_PETSC_BUILD: marker, so the conductor can read it from a binary that cannot start.

Parameters
[in]argcNative executable argument count.
[in]argvNative executable argument vector.
[in]executable_nameUser-facing executable name printed with the identity.
Returns
Nonzero when a version flag was handled and execution should stop.

Print the shared native build identity when a version flag is present.

The public argument and return contract is documented in include/setup.h.

See also
PicurvHandleVersionArgument()

Definition at line 47 of file setup.c.

48{
49 for (int index = 1; index < argc; ++index) {
50 if (!strcmp(argv[index], "--version") || !strcmp(argv[index], "-version")) {
51 printf("%s %s+g%.12s%s\n", executable_name, PICURV_RELEASE_VERSION,
53 !strcmp(PICURV_BUILD_DIRTY, "true") ? ".dirty" : "");
54 printf("%s\n", picurv_petsc_build_stamp + sizeof(PICURV_PETSC_STAMP_MARKER) - 1);
55 return 1;
56 }
57 }
58 return 0;
59}
#define PICURV_PETSC_STAMP_MARKER
Definition setup.c:32
static const char picurv_petsc_build_stamp[]
Definition setup.c:37
#define PICURV_BUILD_DIRTY
Definition variables.h:38
#define PICURV_GIT_COMMIT
Definition variables.h:35
#define PICURV_RELEASE_VERSION
Definition variables.h:32
Here is the caller graph for this function:

◆ 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 371 of file setup.c.

372{
373 PetscErrorCode ierr;
374 (void)argc;
375 (void)argv;
376 SimCtx *simCtx;
377 char control_filename[PETSC_MAX_PATH_LEN] = ""; // Temporary placeholder for control file name.
378 PetscBool control_flg; // Temporary placeholder for control file tag existence check flag.
379 PetscBool particle_console_output_freq_flg = PETSC_FALSE;
380
381 PetscFunctionBeginUser;
382
384
385 // === 1. Allocate the Context Struct and Set ALL Defaults ==================
386 ierr = PetscNew(p_simCtx); CHKERRQ(ierr);
387 simCtx = *p_simCtx;
388
389 // --- Group 1: Parallelism & MPI ---
390 simCtx->rank = 0; simCtx->size = 1;
391
392 // --- Group 2: Simulation Control, Time, and I/O ---
393 simCtx->step = 0; simCtx->ti = 0.0; simCtx->StartStep = 0; simCtx->StepsToRun = 10;
394 simCtx->tiout = 10; simCtx->particleConsoleOutputFreq = simCtx->tiout;
395 simCtx->StartTime = 0.0; simCtx->dt = 0.001;
396 simCtx->OnlySetup = PETSC_FALSE;
397 simCtx->continueMode = PETSC_FALSE;
398 simCtx->logviewer = NULL;
399 strcpy(simCtx->eulerianSource,"solve");
400 strcpy(simCtx->restart_dir,"restart");
401 strcpy(simCtx->output_dir,"output");
402 strcpy(simCtx->log_dir,"logs");
403 strcpy(simCtx->analysis_dir,"output/analysis/metrics");
404 simCtx->_io_context_buffer[0] = '\0';
405 simCtx->current_io_directory = NULL;
406 simCtx->checkpointGeometrySHA256[0] = '\0';
407 simCtx->checkpointGeometryHashReady = PETSC_FALSE;
408 simCtx->restartHistoryAvailable = PETSC_FALSE;
409
410 // --- Group 3: High-Level Physics & Model Selection Flags ---
411 simCtx->immersed = 0; simCtx->movefsi = 0; simCtx->rotatefsi = 0;
412 simCtx->invicid = 0;
413 simCtx->TwoD = 0; simCtx->moveframe = 0; simCtx->rotateframe = 0;
414 strcpy(simCtx->AnalyticalSolutionType,"TGV3D");
415
416 // --- Group 4: Immersed-body flux corrections (refused; see Group 3 parsing) ---
417 simCtx->MHV=0; simCtx->LV=0;
418
419 // --- Group 5: Solver & Numerics Parameters ---
421 simCtx->mom_dt_jameson_residual_norm_noise_allowance_factor = 1.1; // raised from 1.05; less aggressive rejection
422 simCtx->mom_atol = 1e-7; simCtx->mom_rtol = 1e-4;
423 /* Residual-based convergence is the default. Leaving both at 0.0 selected the
424 * update-only branch, where |dU| <= mom_atol can pass purely because dtau collapsed
425 * (|dU| ~ dtau*|R|), converging on a state that does not satisfy the equations.
426 * Shipped configs all set these explicitly; these defaults protect a minimal
427 * user-written config. Set both non-positive to opt back out deliberately. */
428 simCtx->mom_resid_atol = 1e-8; simCtx->mom_resid_rtol = 1e-3;
429 simCtx->imp_stol = 1.e-8;
430 simCtx->mglevels = 3;
431 simCtx->mg_preItr = 1; simCtx->mg_poItr = 1;
432 simCtx->poisson = 0;
433 simCtx->central=0;
434 /* pseudo_cfl and its bounds are now dimensionless Courant numbers: CFL = dtau * lambda_max,
435 where lambda_max is the global spectral radius computed at each physical timestep.
436 Stable range for 4-stage Jameson RK: ~0–2.83. Initial 0.5 gives a comfortable margin. */
437 simCtx->ren = 100.0; simCtx->pseudo_cfl = 0.5;
438 simCtx->max_pseudo_cfl = 2.0; simCtx->min_pseudo_cfl = 0.001;
439 simCtx->pseudo_cfl_reduction_factor = 0.75;
440 simCtx->pseudo_cfl_growth_factor = 1.1; // raised from 1.0; controller can now increase CFL
441 simCtx->no_pseudo_cfl_backtrack = PETSC_FALSE;
442 simCtx->mom_ratio_ema_alpha = 0.3; /* moderate smoothing; set to 1.0 to recover original raw-ratio behavior */
443 simCtx->mom_last_converged = PETSC_TRUE;
444 simCtx->mom_last_lambda_max = 0.0; /* populated after first momentum solve */
445 simCtx->mom_nk_monitor_history = PETSC_FALSE;
446 simCtx->ps_ksp_pic_monitor_true_residual = PETSC_FALSE;
447 simCtx->cdisx = 0.0; simCtx->cdisy = 0.0; simCtx->cdisz = 0.0;
450 strcpy(simCtx->initialConditionDirectory, "config/initial_condition");
451 simCtx->InitialConstantContra.x = 0.0;
452 simCtx->InitialConstantContra.y = 0.0;
453 simCtx->InitialConstantContra.z = 0.0;
455 simCtx->icVelocityPhysical = 0.0;
456 simCtx->AnalyticalUniformVelocity.x = 0.0;
457 simCtx->AnalyticalUniformVelocity.y = 0.0;
458 simCtx->AnalyticalUniformVelocity.z = 0.0;
459 simCtx->fieldStatisticsEnabled = PETSC_FALSE;
460 simCtx->fieldStatisticsWindowCount = 0;
461 simCtx->fieldStatisticsWindows = NULL;
462 simCtx->statisticsConsoleOutputFreq = 0;
463 simCtx->fieldStatisticsContinue = PETSC_FALSE;
464 simCtx->solutionConvergenceEnabled = PETSC_TRUE;
471 simCtx->verificationDiffusivity.enabled = PETSC_FALSE;
472 strcpy(simCtx->verificationDiffusivity.mode, "");
473 strcpy(simCtx->verificationDiffusivity.profile, "");
474 simCtx->verificationDiffusivity.gamma0 = 0.0;
475 simCtx->verificationDiffusivity.slope_x = 0.0;
476
477 // --- Group 6: Physical & Geometric Parameters ---
478 simCtx->Flux_in = 1.0; simCtx->angle = 0.0;
479 simCtx->max_angle = -54. * 3.1415926 / 180.;
480 simCtx->CMx_c=0.0; simCtx->CMy_c=0.0; simCtx->CMz_c=0.0;
481 simCtx->wall_roughness_height = 1e-16;
482 simCtx->schmidt_number = 1.0; simCtx->Turbulent_schmidt_number = 0.7;
483 simCtx->iem_constant = 2.0;
484
485 // --- Group 7: Grid, Domain, and Boundary Condition Settings ---
486 simCtx->block_number = 1; simCtx->inletprofile = 1;
487 simCtx->i_periodic = 0; simCtx->j_periodic = 0; simCtx->k_periodic = 0;
488 simCtx->pseudo_periodic = 0;
489 strcpy(simCtx->grid_file, "config/grid.run");
490 simCtx->generate_grid = PETSC_FALSE;
491 simCtx->da_procs_x = PETSC_DECIDE;
492 simCtx->da_procs_y = PETSC_DECIDE;
493 simCtx->da_procs_z = PETSC_DECIDE;
494 simCtx->num_bcs_files = 1;
495 ierr = PetscMalloc1(1, &simCtx->bcs_files); CHKERRQ(ierr);
496 ierr = PetscStrallocpy("config/bcs.run", &simCtx->bcs_files[0]); CHKERRQ(ierr);
497 simCtx->FluxInSum = 0.0; simCtx->FluxOutSum = 0.0; simCtx->Fluxsum = 0.0;
498 simCtx->drivingForceMagnitude = 0.0, simCtx->forceScalingFactor = 1.8;
499 simCtx->drivingForceStep = -1;
500 simCtx->drivenFluxMeasured = 0.0; simCtx->drivenFluxArea = 0.0;
501 simCtx->targetVolumetricFlux = 0.0;
502 simCtx->drivenFluxTargetLatched = PETSC_FALSE;
503 simCtx->bulkVelocityCorrection = 0.0;
504 simCtx->boundaryVelocityCorrection = 0.0;
505 simCtx->AreaInSum = 0.0; simCtx->AreaOutSum = 0.0;
506 simCtx->ccc = 0;
507 simCtx->ratio = 0.0;
508
509
510 // --- Group 8: Turbulence Modeling (LES) ---
511 simCtx->les = NO_LES_MODEL;
512 simCtx->wallfunction = 0; simCtx->les_gradient_model = 0;
513 ierr = LESConfigSetDefaults(&simCtx->les_config); CHKERRQ(ierr);
514
515 // --- Group 9: Particle / DMSwarm Data & Settings ---
516 simCtx->np = 0;
517 simCtx->particleRandomSeed = 12345;
518 simCtx->dm_swarm = NULL; simCtx->bboxlist = NULL;
521 strcpy(simCtx->particleRestartMode,"load");
522 simCtx->particlesLostLastStep = 0;
523 simCtx->particlesLostCumulative = 0;
524 simCtx->particlesLostScalarLastStep = 0.0;
525 simCtx->particlesMigratedLastStep = 0;
526 simCtx->occupiedCellCount = 0;
527 simCtx->particleLoadImbalance = 0.0;
528 simCtx->migrationPassesLastStep = 0;
529 simCtx->searchMetrics.searchAttempts = 0;
532 simCtx->searchMetrics.searchLostCount = 0;
534 simCtx->searchMetrics.reSearchCount = 0;
537 simCtx->searchMetrics.tieBreakCount = 0;
543 simCtx->BrownianMotionRNG = NULL;
544 simCtx->C_IEM = 2.0;
545
546 // --- Group 10: Immersed Boundary & FSI Data Object Pointers ---
547 simCtx->ibm = NULL; simCtx->ibmv = NULL; simCtx->fsi = NULL;
548
549 // --- Group 11: Logging and Custom Configuration ---
550 strcpy(simCtx->allowedFile, "config/whitelist.run");
551 simCtx->useCfg = PETSC_FALSE;
552 simCtx->allowedFuncs = NULL;
553 simCtx->nAllowed = 0;
554 simCtx->LoggingFrequency = 10;
555 simCtx->poissonSourceImbalance = 0.0;
556 simCtx->MaxDiv = 0.0;
557 simCtx->MaxDivFlatArg = 0; simCtx->MaxDivx = 0; simCtx->MaxDivy = 0; simCtx->MaxDivz = 0;
558 strcpy(simCtx->profilingSelectedFuncsFile, "config/profile.run");
559 simCtx->useProfilingSelectedFuncsCfg = PETSC_FALSE;
560 simCtx->profilingSelectedFuncs = NULL;
561 simCtx->nProfilingSelectedFuncs = 0;
562 strcpy(simCtx->profilingTimestepMode, "selected");
563 strcpy(simCtx->profilingTimestepFile, "Profiling_Timestep_Summary.csv");
564 simCtx->profilingFinalSummary = PETSC_TRUE;
565 simCtx->walltimeGuardEnabled = PETSC_FALSE;
566 simCtx->walltimeGuardActive = PETSC_FALSE;
567 simCtx->walltimeGuardWarmupSteps = 10;
568 simCtx->walltimeGuardMultiplier = 2.0;
569 simCtx->walltimeGuardMinSeconds = 60.0;
570 simCtx->walltimeGuardEstimatorAlpha = 0.35;
572 simCtx->walltimeGuardLimitSeconds = 0.0;
573 simCtx->walltimeGuardCompletedSteps = 0;
576 simCtx->walltimeGuardHasEWMA = PETSC_FALSE;
577 simCtx->walltimeGuardEWMASeconds = 0.0;
578 simCtx->walltimeGuardLatestStepSeconds = 0.0;
579 simCtx->runtimeMemoryLogEnabled = PETSC_TRUE;
580 strcpy(simCtx->runtimeMemoryLogFile, "Runtime_Memory.log");
581 simCtx->runtimeMemoryLogStarted = PETSC_FALSE;
582 simCtx->runtimeMemoryLogHasPrevious = PETSC_FALSE;
584 // --- Group 11: Post-Processing Information ---
585 strcpy(simCtx->PostprocessingControlFile, "config/post.run");
586 ierr = PetscNew(&simCtx->pps); CHKERRQ(ierr);
587
588 // === 2. Get MPI Info and Handle Config File =============================
589 // -- Group 1: Parallelism & MPI Information
590 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &simCtx->rank); CHKERRQ(ierr);
591 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &simCtx->size); CHKERRQ(ierr);
592
593 // First, check if the -control_file argument was provided by the user/script.
594 ierr = PetscOptionsGetString(NULL, NULL, "-control_file", control_filename, sizeof(control_filename), &control_flg); CHKERRQ(ierr);
595
596 // If the flag is NOT present or the filename is empty, abort with a helpful error.
597 if (!control_flg || strlen(control_filename) == 0) {
598 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
599 "\n\n*** MANDATORY ARGUMENT MISSING ***\n"
600 "The -control_file argument was not provided.\n"
601 "This program must be launched with a configuration file.\n"
602 "Example: mpiexec -n 4 ./simulator -control_file /path/to/your/config.control\n"
603 "This is typically handled automatically by the 'picurv' script.\n");
604 }
605
606 // At this point, we have a valid filename. Attempt to load it.
607 LOG(GLOBAL, LOG_INFO, "Loading mandatory configuration from: %s\n", control_filename);
608 ierr = PetscOptionsInsertFile(PETSC_COMM_WORLD, NULL, control_filename, PETSC_FALSE);
609 if (ierr == PETSC_ERR_FILE_OPEN) {
610 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_FILE_OPEN, "The specified control file was not found or could not be opened: %s", control_filename);
611 }
612 CHKERRQ(ierr);
613
614 {
615 PetscBool legacy_averaging = PETSC_FALSE;
616 ierr = PetscOptionsHasName(NULL, NULL, "-averaging", &legacy_averaging); CHKERRQ(ierr);
617 PetscCheck(!legacy_averaging, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
618 "Legacy -averaging was removed. Use instantaneous output and offline "
619 "postprocessing until the replacement field-statistics pipeline is available.");
620 }
621
622 // === 3. A Configure Logging System ========================================
623 // This logic determines the logging configuration and STORES it in simCtx for
624 // later reference and cleanup.
625 ierr = PetscOptionsGetString(NULL, NULL, "-whitelist_config_file", simCtx->allowedFile, PETSC_MAX_PATH_LEN, &simCtx->useCfg); CHKERRQ(ierr);
626
627 if (simCtx->useCfg) {
628 ierr = LoadAllowedFunctionsFromFile(simCtx->allowedFile, &simCtx->allowedFuncs, &simCtx->nAllowed);
629 if (ierr) {
630 // Use direct PetscPrintf as logging system isn't fully active yet.
631 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Failed to load allowed functions from '%s'. Falling back to default list.\n", __func__, simCtx->allowedFile);
632 simCtx->useCfg = PETSC_FALSE; // Mark as failed.
633 ierr = 0; // Clear the error to allow fallback.
634 } else if (simCtx->nAllowed == 0) {
635 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
636 "Whitelist config file '%s' is empty. Omit -whitelist_config_file to use the default allow-list, or list at least one function.",
637 simCtx->allowedFile);
638 }
639 }
640 if (!simCtx->useCfg) {
641 // Fallback to default logging functions if no file was used or if loading failed.
642 simCtx->nAllowed = 2;
643 ierr = PetscMalloc1(simCtx->nAllowed, &simCtx->allowedFuncs); CHKERRQ(ierr);
644 ierr = PetscStrallocpy("main", &simCtx->allowedFuncs[0]); CHKERRQ(ierr);
645 ierr = PetscStrallocpy("CreateSimulationContext", &simCtx->allowedFuncs[1]); CHKERRQ(ierr);
646 }
647
648 // Activate the configuration by passing it to the logging module's setup function.
649 set_allowed_functions((const char**)simCtx->allowedFuncs, (size_t)simCtx->nAllowed);
650
651 // Now that the logger is configured, we can use it.
652 LOG_ALLOW_SYNC(LOCAL, LOG_INFO, "Context created. Initializing on rank %d of %d.\n", simCtx->rank, simCtx->size);
653 print_log_level(); // This will now correctly reflect the LOG_LEVEL environment variable.
654
655 // === 3.B Configure Profiling System ========================================
656 ierr = PetscOptionsGetString(NULL, NULL, "-profiling_timestep_mode", simCtx->profilingTimestepMode, sizeof(simCtx->profilingTimestepMode), NULL); CHKERRQ(ierr);
657 ierr = PetscOptionsGetString(NULL, NULL, "-profiling_timestep_file", simCtx->profilingTimestepFile, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
658 ierr = PetscOptionsGetBool(NULL, NULL, "-profiling_final_summary", &simCtx->profilingFinalSummary, NULL); CHKERRQ(ierr);
659 if (strcmp(simCtx->profilingTimestepMode, "off") != 0 &&
660 strcmp(simCtx->profilingTimestepMode, "selected") != 0 &&
661 strcmp(simCtx->profilingTimestepMode, "all") != 0) {
662 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Unknown profiling timestep mode '%s'. Falling back to 'selected'.\n", __func__, simCtx->profilingTimestepMode);
663 strcpy(simCtx->profilingTimestepMode, "selected");
664 }
665
666 if (strcmp(simCtx->profilingTimestepMode, "selected") == 0) {
667 ierr = PetscOptionsGetString(NULL, NULL, "-profile_config_file", simCtx->profilingSelectedFuncsFile, PETSC_MAX_PATH_LEN, &simCtx->useProfilingSelectedFuncsCfg); CHKERRQ(ierr);
668 if (simCtx->useProfilingSelectedFuncsCfg) {
670 if (ierr) {
671 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Failed to load selected profiling functions from '%s'. Falling back to default list.\n", __func__, simCtx->profilingSelectedFuncsFile);
672 simCtx->useProfilingSelectedFuncsCfg = PETSC_FALSE;
673 ierr = 0;
674 }
675 }
676 if (!simCtx->useProfilingSelectedFuncsCfg) {
677 // Fallback to a hardcoded default list if no file was provided or loading failed.
678 simCtx->nProfilingSelectedFuncs = 4;
679 ierr = PetscMalloc1(simCtx->nProfilingSelectedFuncs, &simCtx->profilingSelectedFuncs); CHKERRQ(ierr);
680 ierr = PetscStrallocpy("FlowSolver", &simCtx->profilingSelectedFuncs[0]); CHKERRQ(ierr);
681 ierr = PetscStrallocpy("AdvanceSimulation", &simCtx->profilingSelectedFuncs[1]); CHKERRQ(ierr);
682 ierr = PetscStrallocpy("LocateAllParticlesInGrid", &simCtx->profilingSelectedFuncs[2]); CHKERRQ(ierr);
683 ierr = PetscStrallocpy("InterpolateAllFieldsToSwarm", &simCtx->profilingSelectedFuncs[3]); CHKERRQ(ierr);
684 }
685 }
686
687 // Initialize the profiling system with the current updated simulation context.
688 ierr = ProfilingInitialize(simCtx); CHKERRQ(ierr);
689
690 // === 4. Parse All Command Line Options ==================================
691 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing command-line options...\n");
692
693 // --- Group 2
694 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 2: Simulation Control,Time and I/O.\n");
695 // Read the physical time to start from.
696 // The default is already 0.0, so this will only be non-zero if the user provides it.
697 ierr = PetscOptionsGetInt(NULL, NULL, "-start_step", &simCtx->StartStep, NULL); CHKERRQ(ierr);
698 ierr = PetscOptionsGetInt(NULL,NULL, "-totalsteps", &simCtx->StepsToRun, NULL); CHKERRQ(ierr);
699 ierr = PetscOptionsGetBool(NULL, NULL, "-only_setup", &simCtx->OnlySetup, NULL); CHKERRQ(ierr);
700 ierr = PetscOptionsGetBool(NULL, NULL, "-continue_mode", &simCtx->continueMode, NULL); CHKERRQ(ierr);
701 /* Resuming in the same run directory continues accumulated statistics by
702 * default; branching with --restart-from must opt in, because the branch may
703 * follow a different physical trajectory than the samples already collected. */
704 simCtx->fieldStatisticsContinue = simCtx->continueMode;
705 ierr = PetscOptionsGetBool(NULL, NULL, "-field_statistics_continue",
706 &simCtx->fieldStatisticsContinue, NULL); CHKERRQ(ierr);
707 ierr = PetscOptionsGetReal(NULL, NULL, "-dt", &simCtx->dt, NULL); CHKERRQ(ierr);
708 ierr = PetscOptionsGetInt(NULL, NULL, "-tio", &simCtx->tiout, NULL); CHKERRQ(ierr);
709 ierr = PetscOptionsGetInt(NULL, NULL, "-particle_console_output_freq", &simCtx->particleConsoleOutputFreq, &particle_console_output_freq_flg); CHKERRQ(ierr);
710 if (!particle_console_output_freq_flg) {
711 simCtx->particleConsoleOutputFreq = simCtx->tiout;
712 }
713 ierr = PetscOptionsGetString(NULL,NULL,"-euler_field_source",simCtx->eulerianSource,sizeof(simCtx->eulerianSource),NULL);CHKERRQ(ierr);
714 ierr = PetscOptionsGetString(NULL,NULL,"-output_dir",simCtx->output_dir,sizeof(simCtx->output_dir),NULL);CHKERRQ(ierr);
715 ierr = PetscOptionsGetString(NULL,NULL,"-restart_dir",simCtx->restart_dir,sizeof(simCtx->restart_dir),NULL);CHKERRQ(ierr);
716 ierr = PetscOptionsGetString(NULL,NULL,"-log_dir",simCtx->log_dir,sizeof(simCtx->log_dir),NULL);CHKERRQ(ierr);
717 ierr = PetscOptionsGetString(NULL,NULL,"-analysis_dir",simCtx->analysis_dir,sizeof(simCtx->analysis_dir),NULL);CHKERRQ(ierr);
718 ierr = PetscOptionsGetBool(NULL, NULL, "-walltime_guard_enabled", &simCtx->walltimeGuardEnabled, NULL); CHKERRQ(ierr);
719 ierr = PetscOptionsGetInt(NULL, NULL, "-walltime_guard_warmup_steps", &simCtx->walltimeGuardWarmupSteps, NULL); CHKERRQ(ierr);
720 ierr = PetscOptionsGetReal(NULL, NULL, "-walltime_guard_multiplier", &simCtx->walltimeGuardMultiplier, NULL); CHKERRQ(ierr);
721 ierr = PetscOptionsGetBool(NULL, NULL, "-runtime_memory_log_enabled", &simCtx->runtimeMemoryLogEnabled, NULL); CHKERRQ(ierr);
722 ierr = PetscOptionsGetString(NULL, NULL, "-runtime_memory_log_file", simCtx->runtimeMemoryLogFile, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
723 ierr = PetscOptionsGetReal(NULL, NULL, "-walltime_guard_min_seconds", &simCtx->walltimeGuardMinSeconds, NULL); CHKERRQ(ierr);
724 ierr = PetscOptionsGetReal(NULL, NULL, "-walltime_guard_estimator_alpha", &simCtx->walltimeGuardEstimatorAlpha, NULL); CHKERRQ(ierr);
725
726 if (simCtx->walltimeGuardWarmupSteps <= 0) {
727 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_warmup_steps: %d. Must be > 0.", simCtx->walltimeGuardWarmupSteps);
728 }
729 if (simCtx->walltimeGuardMultiplier <= 0.0 || simCtx->walltimeGuardMultiplier > 5.0) {
730 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_multiplier: %.6f. Must be in (0, 5].", (double)simCtx->walltimeGuardMultiplier);
731 }
732 if (simCtx->walltimeGuardMinSeconds <= 0.0) {
733 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_min_seconds: %.6f. Must be > 0.", (double)simCtx->walltimeGuardMinSeconds);
734 }
735 if (simCtx->walltimeGuardEstimatorAlpha <= 0.0 || simCtx->walltimeGuardEstimatorAlpha > 1.0) {
736 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -walltime_guard_estimator_alpha: %.6f. Must be in (0, 1].", (double)simCtx->walltimeGuardEstimatorAlpha);
737 }
738
739 if(strcmp(simCtx->eulerianSource,"solve")!= 0 && strcmp(simCtx->eulerianSource,"load") != 0 && strcmp(simCtx->eulerianSource,"analytical")!=0){
740 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);
741 }
742 if (simCtx->walltimeGuardEnabled) {
743 const char *job_start_env = getenv("PICURV_JOB_START_EPOCH");
744 const char *limit_env = getenv("PICURV_WALLTIME_LIMIT_SECONDS");
745 PetscBool job_start_ok = RuntimeWalltimeGuardParsePositiveSeconds(job_start_env, &simCtx->walltimeGuardJobStartEpochSeconds);
746 PetscBool limit_ok = RuntimeWalltimeGuardParsePositiveSeconds(limit_env, &simCtx->walltimeGuardLimitSeconds);
747
748 if (!job_start_ok || !limit_ok) {
749 simCtx->walltimeGuardActive = PETSC_FALSE;
751 simCtx->walltimeGuardLimitSeconds = 0.0;
752 LOG_ALLOW(
753 GLOBAL,
755 "Runtime walltime guard enabled but %s/%s are missing or invalid. Falling back to external shutdown signals only.\n",
756 "PICURV_JOB_START_EPOCH",
757 "PICURV_WALLTIME_LIMIT_SECONDS"
758 );
759 } else {
760 simCtx->walltimeGuardActive = PETSC_TRUE;
761 }
762 }
763
764 // --- Group 3
765 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 3: High-Level Physics & Model Selection Flags\n");
766 ierr = PetscOptionsGetInt(NULL, NULL, "-imm", &simCtx->immersed, NULL); CHKERRQ(ierr);
767 ierr = PetscOptionsGetInt(NULL, NULL, "-fsi", &simCtx->movefsi, NULL); CHKERRQ(ierr);
768 ierr = PetscOptionsGetInt(NULL, NULL, "-rfsi", &simCtx->rotatefsi, NULL); CHKERRQ(ierr);
769 ierr = PetscOptionsGetInt(NULL, NULL, "-inv", &simCtx->invicid, NULL); CHKERRQ(ierr);
770 ierr = PetscOptionsGetInt(NULL, NULL, "-TwoD", &simCtx->TwoD, NULL); CHKERRQ(ierr);
771 ierr = PetscOptionsGetInt(NULL, NULL, "-mframe", &simCtx->moveframe, NULL); CHKERRQ(ierr);
772 ierr = PetscOptionsGetInt(NULL, NULL, "-rframe", &simCtx->rotateframe, NULL); CHKERRQ(ierr);
773 ierr = PetscOptionsGetString(NULL,NULL,"-analytical_type",simCtx->AnalyticalSolutionType,sizeof(simCtx->AnalyticalSolutionType),NULL);CHKERRQ(ierr);
774
775 /* Immersed boundaries, moving bodies and moving reference frames are planned, not
776 implemented. No body geometry is ever loaded, and the IBM interpolation the
777 momentum solvers would call is commented out and defined nowhere, so -imm only
778 reconfigures the Poisson solve around a body that is not there. The moving-frame
779 convection branch in ComputeRHS is commented out as well, so -mframe/-rframe would
780 drop the convective term. Each would run a different problem without saying so;
781 the conductor refuses the YAML switches, and this refuses the same flags arriving
782 through a PETSc passthrough. */
783 PetscCheck(!simCtx->immersed && !simCtx->movefsi && !simCtx->rotatefsi, PETSC_COMM_WORLD, PETSC_ERR_SUP,
784 "Immersed boundaries and moving bodies (-imm, -fsi, -rfsi) are planned, not implemented.");
785 PetscCheck(!simCtx->moveframe && !simCtx->rotateframe, PETSC_COMM_WORLD, PETSC_ERR_SUP,
786 "Moving and rotating reference frames (-mframe, -rframe) are planned, not implemented: "
787 "their convection branch is absent, so the convective term would be dropped.");
788
789 // --- Group 4
790 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 4: Immersed-Body Flux Corrections and Driven-Flow Controls\n");
791 ierr = PetscOptionsGetInt(NULL, NULL, "-mhv", &simCtx->MHV, NULL); CHKERRQ(ierr);
792 ierr = PetscOptionsGetInt(NULL, NULL, "-lv", &simCtx->LV, NULL); CHKERRQ(ierr);
793 /* The heart-valve volume-flux corrections balance flux across an immersed body, which
794 cannot exist while immersed boundaries are unimplemented (see the Group 3 check). */
795 PetscCheck(!simCtx->MHV && !simCtx->LV, PETSC_COMM_WORLD, PETSC_ERR_SUP,
796 "The -mhv/-lv immersed-body flux corrections need immersed boundaries, which are planned, not implemented.");
797 ierr = PetscOptionsGetReal(NULL,NULL,"-driven_flow_initial_force",&simCtx->drivingForceMagnitude,NULL);CHKERRQ(ierr);
798 ierr = PetscOptionsGetReal(NULL,NULL,"-driven_flow_scaling_factor",&simCtx->forceScalingFactor,NULL);CHKERRQ(ierr);
799 // --- Group 5
800 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 5: Solver & Numerics Parameters \n");
801 char mom_solver_type_char[PETSC_MAX_PATH_LEN];
802 char solution_convergence_mode_char[PETSC_MAX_PATH_LEN];
803 PetscBool mom_solver_type_flg = PETSC_FALSE;
804 PetscBool solution_convergence_mode_flg = PETSC_FALSE;
805 ierr = PetscOptionsGetString(NULL, NULL, "-mom_solver_type", mom_solver_type_char, sizeof(mom_solver_type_char), &mom_solver_type_flg); CHKERRQ(ierr);
806 ierr = PetscOptionsGetInt(NULL, NULL, "-mom_max_pseudo_steps", &simCtx->mom_max_pseudo_steps, NULL); CHKERRQ(ierr);
807 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_atol", &simCtx->mom_atol, NULL); CHKERRQ(ierr);
808 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_rtol", &simCtx->mom_rtol, NULL); CHKERRQ(ierr);
809 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_resid_atol", &simCtx->mom_resid_atol, NULL); CHKERRQ(ierr);
810 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_resid_rtol", &simCtx->mom_resid_rtol, NULL); CHKERRQ(ierr);
811 ierr = PetscOptionsGetReal(NULL, NULL, "-imp_stol", &simCtx->imp_stol, NULL); CHKERRQ(ierr);
812 ierr = PetscOptionsGetInt(NULL, NULL, "-central", &simCtx->central, NULL); CHKERRQ(ierr);
813 ierr = PetscOptionsGetString(NULL, NULL, "-solution_convergence_mode",
814 solution_convergence_mode_char, sizeof(solution_convergence_mode_char),
815 &solution_convergence_mode_flg); CHKERRQ(ierr);
816 ierr = PetscOptionsGetBool(NULL, NULL, "-solution_convergence_enabled", &simCtx->solutionConvergenceEnabled, NULL); CHKERRQ(ierr);
817 ierr = PetscOptionsGetInt(NULL, NULL, "-solution_convergence_period_steps", &simCtx->solutionConvergencePeriodSteps, NULL); CHKERRQ(ierr);
818 ierr = PetscOptionsGetInt(NULL, NULL, "-solution_convergence_window_steps", &simCtx->solutionConvergenceWindowSteps, NULL); CHKERRQ(ierr);
819 /* Field statistics resolve here rather than inline, because a variable-arity
820 * window list needs its own parse site; see statistics_config.c. It must
821 * precede CreateAndInitializeAllVectors, which sizes the per-window
822 * accumulators from the window count resolved here. */
823 ierr = ParseFieldStatisticsConfig(simCtx); CHKERRQ(ierr);
824
825 // Keep parser acceptance aligned with the enum and FlowSolver dispatch.
826 if (mom_solver_type_flg) {
827 if(strcmp(mom_solver_type_char, "DUALTIME_PICARD_JAMESON_RK") == 0 ||
828 strcmp(mom_solver_type_char, "DUALTIME_PICARD_RK4") == 0) {
830 } else if (strcmp(mom_solver_type_char, "EXPLICIT_RK") == 0) {
832 } else if (strcmp(mom_solver_type_char, "newton_krylov") == 0) {
834 } else {
835 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);
836 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -mom_solver_type: '%s'.", mom_solver_type_char);
837 }
838 }
839
840 if (solution_convergence_mode_flg) {
841 if (strcmp(solution_convergence_mode_char, "STEADY_DETERMINISTIC") == 0) {
843 } else if (strcmp(solution_convergence_mode_char, "PERIODIC_DETERMINISTIC") == 0) {
845 } else if (strcmp(solution_convergence_mode_char, "STATISTICAL_STEADY") == 0) {
847 } else if (strcmp(solution_convergence_mode_char, "TRANSIENT") == 0) {
849 } else {
850 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
851 "Invalid value for -solution_convergence_mode: '%s'.", solution_convergence_mode_char);
852 }
853 }
854
856 simCtx->solutionConvergencePeriodSteps <= 0) {
857 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
858 "solution convergence mode PERIODIC_DETERMINISTIC requires -solution_convergence_period_steps > 0.");
859 }
861 simCtx->solutionConvergenceWindowSteps <= 0) {
862 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
863 "solution convergence mode STATISTICAL_STEADY requires -solution_convergence_window_steps > 0.");
864 }
865
866 // --- Multigrid Options ---
867 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_level", &simCtx->mglevels, NULL); CHKERRQ(ierr);
868 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_pre_it", &simCtx->mg_preItr, NULL); CHKERRQ(ierr);
869 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_post_it", &simCtx->mg_poItr, NULL); CHKERRQ(ierr);
870
871 // --- Other Solver Options ---
872 ierr = PetscOptionsGetInt(NULL, NULL, "-poisson", &simCtx->poisson, NULL); CHKERRQ(ierr);
873 ierr = PetscOptionsGetReal(NULL, NULL, "-ren", &simCtx->ren, NULL); CHKERRQ(ierr);
874 ierr = PetscOptionsGetReal(NULL, NULL, "-pseudo_cfl", &simCtx->pseudo_cfl, NULL); CHKERRQ(ierr);
875 ierr = PetscOptionsGetReal(NULL, NULL, "-max_pseudo_cfl", &simCtx->max_pseudo_cfl, NULL); CHKERRQ(ierr);
876 ierr = PetscOptionsGetReal(NULL, NULL, "-min_pseudo_cfl", &simCtx->min_pseudo_cfl, NULL); CHKERRQ(ierr);
877 ierr = PetscOptionsGetReal(NULL, NULL, "-pseudo_cfl_reduction_factor", &simCtx->pseudo_cfl_reduction_factor, NULL); CHKERRQ(ierr);
878 ierr = PetscOptionsGetReal(NULL, NULL, "-pseudo_cfl_growth_factor", &simCtx->pseudo_cfl_growth_factor, NULL); CHKERRQ(ierr);
879 // Read the deprecated RK4 spelling first so the canonical Jameson option wins if both are present.
880 ierr = PetscOptionsGetReal(NULL,NULL, "-mom_dt_rk4_residual_norm_noise_allowance_factor",&simCtx->mom_dt_jameson_residual_norm_noise_allowance_factor,NULL);CHKERRQ(ierr);
881 ierr = PetscOptionsGetReal(NULL,NULL, "-mom_dt_jameson_residual_norm_noise_allowance_factor",&simCtx->mom_dt_jameson_residual_norm_noise_allowance_factor,NULL);CHKERRQ(ierr);
882 ierr = PetscOptionsGetBool(NULL, NULL, "-no_pseudo_cfl_backtrack", &simCtx->no_pseudo_cfl_backtrack, NULL); CHKERRQ(ierr);
883 ierr = PetscOptionsGetReal(NULL, NULL, "-mom_ratio_ema_alpha", &simCtx->mom_ratio_ema_alpha, NULL); CHKERRQ(ierr);
884 if (simCtx->min_pseudo_cfl <= 0.0 ||
885 simCtx->pseudo_cfl < simCtx->min_pseudo_cfl ||
886 simCtx->pseudo_cfl > simCtx->max_pseudo_cfl) {
887 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
888 "Pseudo-CFL controls require 0 < minimum <= initial <= maximum.");
889 }
890 if (simCtx->pseudo_cfl_growth_factor < 1.0 ||
891 simCtx->pseudo_cfl_reduction_factor <= 0.0 ||
892 simCtx->pseudo_cfl_reduction_factor >= 1.0 ||
894 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
895 "Pseudo-CFL controls require growth_factor >= 1, 0 < reduction_factor < 1, and noise allowance >= 1.");
896 }
897 if (simCtx->mom_ratio_ema_alpha < 0.0 || simCtx->mom_ratio_ema_alpha > 1.0) {
898 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
899 "-mom_ratio_ema_alpha must be in [0, 1].");
900 }
901 ierr = PetscOptionsHasName(NULL, NULL, "-ps_ksp_pic_monitor_true_residual", &simCtx->ps_ksp_pic_monitor_true_residual); CHKERRQ(ierr);
902 ierr = PetscOptionsGetBool(NULL, NULL, "-mom_nk_pic_monitor", &simCtx->mom_nk_monitor_history, NULL); CHKERRQ(ierr);
903 {
904 PetscInt ic_mode = (PetscInt)simCtx->initialConditionMode;
905 PetscInt ic_field = (PetscInt)simCtx->initialConditionField;
906 ierr = PetscOptionsGetInt(NULL, NULL, "-finit", &ic_mode, NULL); CHKERRQ(ierr);
907 ierr = PetscOptionsGetInt(NULL, NULL, "-ic_field", &ic_field, NULL); CHKERRQ(ierr);
910 }
911 ierr = PetscOptionsGetString(NULL, NULL, "-ic_dir", simCtx->initialConditionDirectory,
912 sizeof(simCtx->initialConditionDirectory), NULL); CHKERRQ(ierr);
914 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
915 "Invalid value for -finit. Expected an initial-condition mode in [0,4], got %d.",
916 simCtx->initialConditionMode);
917 }
919 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
920 "Invalid value for -ic_field. Expected 0 (Ucat) or 1 (Ucont), got %d.",
921 simCtx->initialConditionField);
922 }
923 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_x", &simCtx->InitialConstantContra.x, NULL); CHKERRQ(ierr);
924 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_y", &simCtx->InitialConstantContra.y, NULL); CHKERRQ(ierr);
925 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_z", &simCtx->InitialConstantContra.z, NULL); CHKERRQ(ierr);
926 {
927 PetscInt fd_int = (PetscInt)FLOW_DIR_UNSET;
928 PetscBool fd_set = PETSC_FALSE;
929 ierr = PetscOptionsGetInt(NULL, NULL, "-flow_direction", &fd_int, &fd_set); CHKERRQ(ierr);
930 if (fd_set) simCtx->flowDirection = (FlowDirection)fd_int;
931 }
932 ierr = PetscOptionsGetReal(NULL, NULL, "-ic_velocity_physical", &simCtx->icVelocityPhysical, NULL); CHKERRQ(ierr);
933 ierr = PetscOptionsGetReal(NULL, NULL, "-analytical_uniform_u", &simCtx->AnalyticalUniformVelocity.x, NULL); CHKERRQ(ierr);
934 ierr = PetscOptionsGetReal(NULL, NULL, "-analytical_uniform_v", &simCtx->AnalyticalUniformVelocity.y, NULL); CHKERRQ(ierr);
935 ierr = PetscOptionsGetReal(NULL, NULL, "-analytical_uniform_w", &simCtx->AnalyticalUniformVelocity.z, NULL); CHKERRQ(ierr);
936 PetscBool verification_scalar_value_set = PETSC_FALSE;
937 PetscBool verification_scalar_phi0_set = PETSC_FALSE;
938 PetscBool verification_scalar_slope_x_set = PETSC_FALSE;
939 PetscBool verification_scalar_amplitude_set = PETSC_FALSE;
940 PetscBool verification_scalar_kx_set = PETSC_FALSE;
941 PetscBool verification_scalar_ky_set = PETSC_FALSE;
942 PetscBool verification_scalar_kz_set = PETSC_FALSE;
943 ierr = PetscOptionsGetString(NULL, NULL, "-verification_diffusivity_mode",
945 sizeof(simCtx->verificationDiffusivity.mode), NULL); CHKERRQ(ierr);
946 ierr = PetscOptionsGetString(NULL, NULL, "-verification_diffusivity_profile",
948 sizeof(simCtx->verificationDiffusivity.profile), NULL); CHKERRQ(ierr);
949 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_diffusivity_gamma0",
950 &simCtx->verificationDiffusivity.gamma0, NULL); CHKERRQ(ierr);
951 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_diffusivity_slope_x",
952 &simCtx->verificationDiffusivity.slope_x, NULL); CHKERRQ(ierr);
953 ierr = PetscOptionsGetString(NULL, NULL, "-verification_scalar_mode",
954 simCtx->verificationScalar.mode,
955 sizeof(simCtx->verificationScalar.mode), NULL); CHKERRQ(ierr);
956 ierr = PetscOptionsGetString(NULL, NULL, "-verification_scalar_profile",
958 sizeof(simCtx->verificationScalar.profile), NULL); CHKERRQ(ierr);
959 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_value",
960 &simCtx->verificationScalar.value, &verification_scalar_value_set); CHKERRQ(ierr);
961 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_phi0",
962 &simCtx->verificationScalar.phi0, &verification_scalar_phi0_set); CHKERRQ(ierr);
963 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_slope_x",
964 &simCtx->verificationScalar.slope_x, &verification_scalar_slope_x_set); CHKERRQ(ierr);
965 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_amplitude",
966 &simCtx->verificationScalar.amplitude, &verification_scalar_amplitude_set); CHKERRQ(ierr);
967 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_kx",
968 &simCtx->verificationScalar.kx, &verification_scalar_kx_set); CHKERRQ(ierr);
969 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_ky",
970 &simCtx->verificationScalar.ky, &verification_scalar_ky_set); CHKERRQ(ierr);
971 ierr = PetscOptionsGetReal(NULL, NULL, "-verification_scalar_kz",
972 &simCtx->verificationScalar.kz, &verification_scalar_kz_set); CHKERRQ(ierr);
974 (PetscBool)(simCtx->verificationDiffusivity.mode[0] != '\0' ||
975 simCtx->verificationDiffusivity.profile[0] != '\0');
977 (PetscBool)(simCtx->verificationScalar.mode[0] != '\0' ||
978 simCtx->verificationScalar.profile[0] != '\0');
979 if (simCtx->verificationDiffusivity.enabled) {
980 if (strcmp(simCtx->eulerianSource, "analytical") != 0) {
981 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
982 "verification diffusivity overrides require -euler_field_source \"analytical\".");
983 }
984 if (strcmp(simCtx->verificationDiffusivity.mode, "analytical") != 0) {
985 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
986 "Unsupported -verification_diffusivity_mode '%s'. Only 'analytical' is supported.",
988 }
989 if (strcmp(simCtx->verificationDiffusivity.profile, "LINEAR_X") != 0) {
990 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
991 "Unsupported -verification_diffusivity_profile '%s'. Only 'LINEAR_X' is supported.",
993 }
994 }
995 if (simCtx->verificationScalar.enabled) {
996 if (strcmp(simCtx->eulerianSource, "analytical") != 0) {
997 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
998 "verification scalar overrides require -euler_field_source \"analytical\".");
999 }
1000 if (strcmp(simCtx->verificationScalar.mode, "analytical") != 0) {
1001 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
1002 "Unsupported -verification_scalar_mode '%s'. Only 'analytical' is supported.",
1003 simCtx->verificationScalar.mode);
1004 }
1005 if (strcmp(simCtx->verificationScalar.profile, "CONSTANT") == 0) {
1006 if (!verification_scalar_value_set) {
1007 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
1008 "verification scalar profile CONSTANT requires -verification_scalar_value.");
1009 }
1010 } else if (strcmp(simCtx->verificationScalar.profile, "LINEAR_X") == 0) {
1011 if (!verification_scalar_phi0_set || !verification_scalar_slope_x_set) {
1012 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
1013 "verification scalar profile LINEAR_X requires -verification_scalar_phi0 and -verification_scalar_slope_x.");
1014 }
1015 } else if (strcmp(simCtx->verificationScalar.profile, "SIN_PRODUCT") == 0) {
1016 if (!verification_scalar_amplitude_set || !verification_scalar_kx_set ||
1017 !verification_scalar_ky_set || !verification_scalar_kz_set) {
1018 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
1019 "verification scalar profile SIN_PRODUCT requires -verification_scalar_amplitude, -verification_scalar_kx, -verification_scalar_ky, and -verification_scalar_kz.");
1020 }
1021 } else {
1022 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
1023 "Unsupported -verification_scalar_profile '%s'. Supported profiles: CONSTANT, LINEAR_X, SIN_PRODUCT.",
1024 simCtx->verificationScalar.profile);
1025 }
1026 }
1027 // NOTE: cdisx,cdisy,cdisz haven't been parsed, add if necessary.
1028
1029 // --- Group 6
1030 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 6: Physical & Geometric Parameters \n");
1031 ierr = PetscOptionsGetReal(NULL,NULL,"-schmidt_number",&simCtx->schmidt_number,NULL);CHKERRQ(ierr);
1032 ierr = PetscOptionsGetReal(NULL,NULL,"-turb_schmidt_number",&simCtx->Turbulent_schmidt_number,NULL);CHKERRQ(ierr);
1033 ierr = PetscOptionsGetReal(NULL,NULL,"-iem_constant",&simCtx->iem_constant,NULL);CHKERRQ(ierr);
1034 /* Zero is valid: it switches micromixing off, so a particle scalar is carried unchanged. */
1035 PetscCheck(simCtx->iem_constant >= 0.0 && !PetscIsInfOrNanReal(simCtx->iem_constant),
1036 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
1037 "-iem_constant must be a non-negative finite number (got %g).", (double)simCtx->iem_constant);
1038 ierr = PetscOptionsGetReal(NULL,NULL,"-wall_roughness",&simCtx->wall_roughness_height,NULL);CHKERRQ(ierr);
1039 // NOTE: angle is not parsed in the original code, it set programmatically. We will follow that.
1040 // NOTE: max_angle is calculated based on other flags (like MHV) in the legacy code.
1041 // We will defer that logic to a later setup stage and not parse them directly.
1042 // The Scaling Information is calculated here
1043 ierr = ParseScalingInformation(simCtx); CHKERRQ(ierr);
1044
1045 // --- Group 7
1046 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 7: Grid, Domain, and Boundary Condition Settings \n");
1047 ierr = PetscOptionsGetInt(NULL, NULL, "-nblk", &simCtx->block_number, NULL); CHKERRQ(ierr); // This is also a modern option
1048 /* Every inter-block exchange (Block_Interface_U) is commented out in the momentum
1049 solvers and the initial condition, so blocks would be solved as isolated domains.
1050 Multi-block coupling is planned, not implemented. */
1051 PetscCheck(simCtx->block_number == 1, PETSC_COMM_WORLD, PETSC_ERR_SUP,
1052 "Multi-block domains are planned, not implemented: blocks are never coupled (got -nblk %" PetscInt_FMT ").",
1053 simCtx->block_number);
1054 ierr = PetscOptionsGetInt(NULL, NULL, "-inlet", &simCtx->inletprofile, NULL); CHKERRQ(ierr);
1055 // NOTE: channelz was not parsed, likely set programmatically. We will omit its parsing call.
1056 ierr = PetscOptionsGetBool(NULL, NULL, "-grid", &simCtx->generate_grid, NULL); CHKERRQ(ierr);
1057 ierr = PetscOptionsGetString(NULL, NULL, "-grid_file", simCtx->grid_file, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
1058 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_x", &simCtx->da_procs_x, NULL); CHKERRQ(ierr);
1059 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_y", &simCtx->da_procs_y, NULL); CHKERRQ(ierr);
1060 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_z", &simCtx->da_procs_z, NULL); CHKERRQ(ierr);
1061 // NOTE: pseudo_periodic was not parsed. We will omit its parsing call.
1062 PetscBool bcs_flg;
1063 char file_list_str[PETSC_MAX_PATH_LEN * 10]; // Buffer for comma-separated list
1064
1065 ierr = PetscOptionsGetString(NULL, NULL, "-bcs_files", file_list_str, sizeof(file_list_str), &bcs_flg); CHKERRQ(ierr);
1066
1067 if (bcs_flg) {
1068 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Found -bcs_files option, overriding default.\n");
1069
1070 // A. Clean up the default memory we allocated in Phase 1.
1071 ierr = PetscFree(simCtx->bcs_files[0]); CHKERRQ(ierr);
1072 ierr = PetscFree(simCtx->bcs_files); CHKERRQ(ierr);
1073 simCtx->num_bcs_files = 0;
1074 simCtx->bcs_files = NULL;
1075
1076 // B. Parse the user-provided comma-separated list.
1077 char *token;
1078 char *str_copy;
1079 ierr = PetscStrallocpy(file_list_str, &str_copy); CHKERRQ(ierr);
1080
1081 // First pass: count the number of files.
1082 token = strtok(str_copy, ",");
1083 while (token) {
1084 simCtx->num_bcs_files++;
1085 token = strtok(NULL, ",");
1086 }
1087 ierr = PetscFree(str_copy); CHKERRQ(ierr);
1088
1089 // Second pass: allocate memory and store the filenames.
1090 ierr = PetscMalloc1(simCtx->num_bcs_files, &simCtx->bcs_files); CHKERRQ(ierr);
1091 ierr = PetscStrallocpy(file_list_str, &str_copy); CHKERRQ(ierr);
1092 token = strtok(str_copy, ",");
1093 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
1094 ierr = PetscStrallocpy(token, &simCtx->bcs_files[i]); CHKERRQ(ierr);
1095 token = strtok(NULL, ",");
1096 }
1097 ierr = PetscFree(str_copy); CHKERRQ(ierr);
1098 }
1099
1100
1101 // --- Group 8
1102 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 8: Turbulence Modeling (LES) \n");
1103 // Seeded from the default already in simCtx: PetscOptionsGetInt leaves the target
1104 // untouched when -les is absent, and an uninitialized value would become the model.
1105 PetscInt temp_les_model = (PetscInt)simCtx->les;
1106 ierr = PetscOptionsGetInt(NULL, NULL, "-les", &temp_les_model, NULL); CHKERRQ(ierr);
1107 PetscCheck(temp_les_model >= NO_LES_MODEL && temp_les_model <= WALE, PETSC_COMM_WORLD,
1108 PETSC_ERR_ARG_OUTOFRANGE,
1109 "-les must be 0 (none), 1 (constant_smagorinsky), 2 (dynamic_smagorinsky), "
1110 "3 (vreman), or 4 (wale); received %" PetscInt_FMT ".", temp_les_model);
1111 simCtx->les = (LESModelType)temp_les_model;
1112 {
1113 /* RANS is planned, not implemented: the k-omega transport update was never
1114 written and its fields were never allocated. The selector and its dead
1115 hooks were removed on 2026-09-22 (see src/guide.md); this refuses the flag
1116 arriving through a PETSc passthrough. */
1117 PetscInt requested_rans = 0;
1118 ierr = PetscOptionsGetInt(NULL, NULL, "-rans", &requested_rans, NULL); CHKERRQ(ierr);
1119 PetscCheck(requested_rans == 0, PETSC_COMM_WORLD, PETSC_ERR_SUP,
1120 "RANS closures (-rans) are planned, not implemented: no transport equation is "
1121 "solved for them. Use an LES closure, or run laminar.");
1122 }
1123 ierr = PetscOptionsGetInt(NULL, NULL, "-wallfunction", &simCtx->wallfunction, NULL); CHKERRQ(ierr);
1124 PetscCheck(simCtx->wallfunction >= WALL_FUNCTION_NONE && simCtx->wallfunction <= WALL_FUNCTION_CABOT,
1125 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
1126 "-wallfunction must be 0 (none), 1 (log_law), 2 (werner), or 3 (cabot); received %" PetscInt_FMT ".",
1127 simCtx->wallfunction);
1128 ierr = PetscOptionsGetInt(NULL, NULL, "-les_gradient_model", &simCtx->les_gradient_model, NULL); CHKERRQ(ierr);
1129 ierr = ParseLESConfiguration(simCtx); CHKERRQ(ierr);
1130
1131 // --- Group 9
1132 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 9: Particle / DMSwarm Data & Settings \n");
1133 ierr = PetscOptionsGetInt(NULL, NULL, "-numParticles", &simCtx->np, NULL); CHKERRQ(ierr);
1134 PetscInt temp_pinit = (PetscInt)PARTICLE_INIT_SURFACE_RANDOM;
1135 ierr = PetscOptionsGetInt(NULL, NULL, "-pinit", &temp_pinit, NULL); CHKERRQ(ierr);
1137 PetscInt temp_interp = (PetscInt)INTERP_TRILINEAR;
1138 ierr = PetscOptionsGetInt(NULL, NULL, "-interpolation_method", &temp_interp, NULL); CHKERRQ(ierr);
1139 simCtx->interpolationMethod = (InterpolationMethod)temp_interp;
1140 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Interpolation method: %s\n",
1141 simCtx->interpolationMethod == INTERP_TRILINEAR ? "Trilinear (direct cell-center)" : "CornerAveraged (legacy)");
1142 ierr = PetscOptionsGetReal(NULL, NULL, "-psrc_x", &simCtx->psrc_x, NULL); CHKERRQ(ierr);
1143 ierr = PetscOptionsGetReal(NULL, NULL, "-psrc_y", &simCtx->psrc_y, NULL); CHKERRQ(ierr);
1144 ierr = PetscOptionsGetReal(NULL, NULL, "-psrc_z", &simCtx->psrc_z, NULL); CHKERRQ(ierr);
1145 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Particle initialization mode: %s. Point source: (%.6f, %.6f, %.6f)\n",
1147 simCtx->psrc_x, simCtx->psrc_y, simCtx->psrc_z);
1148 ierr = PetscOptionsGetString(NULL,NULL,"-particle_restart_mode",simCtx->particleRestartMode,sizeof(simCtx->particleRestartMode),NULL); CHKERRQ(ierr);
1149 // Validation for Particle Restart Mode
1150 if (strcmp(simCtx->particleRestartMode, "load") != 0 && strcmp(simCtx->particleRestartMode, "init") != 0) {
1151 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -particle_restart_mode. Must be 'load' or 'init'. You provided '%s'.", simCtx->particleRestartMode);
1152 }
1153 ierr = PetscOptionsGetInt(NULL, NULL, "-particle_random_seed", &simCtx->particleRandomSeed, NULL); CHKERRQ(ierr);
1154 PetscCheck(simCtx->particleRandomSeed >= 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
1155 "-particle_random_seed must be non-negative (got %" PetscInt_FMT ").", simCtx->particleRandomSeed);
1156 ierr = InitializeBrownianRNG(simCtx); CHKERRQ(ierr);
1157 ierr = ParticleFieldPlanCreate(&simCtx->particleFieldPlan); CHKERRQ(ierr);
1158 PetscCheck(!simCtx->particleFieldPlan || simCtx->np > 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
1159 "Particle field initial values are configured but the run has no particles.");
1160 PetscCheck(!simCtx->particleFieldPlan || !VerificationScalarOverrideActive(simCtx), PETSC_COMM_WORLD,
1161 PETSC_ERR_ARG_WRONG,
1162 "Particle field initial values cannot be combined with the verification scalar source, "
1163 "which prescribes Psi at every step.");
1164 // --- Group 10
1165 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 10: Immersed Boundary & FSI Data Object Pointers \n");
1166
1167 // --- Group 11
1168 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 11: Top-Level Managers & Custom Configuration \n");
1169 ierr = PetscOptionsGetInt(NULL, NULL, "-logfreq", &simCtx->LoggingFrequency, NULL); CHKERRQ(ierr);
1170
1171 if (simCtx->num_bcs_files != simCtx->block_number) {
1172 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);
1173 }
1174
1175 // --- Group 12
1176 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 12: Post-Processing Information.\n");
1177 // This logic determines the Post Processing configuration and STORES it in simCtx for later reference and cleanup.
1178 ierr = PetscOptionsGetString(NULL,NULL,"-postprocessing_config_file",simCtx->PostprocessingControlFile,PETSC_MAX_PATH_LEN,NULL); CHKERRQ(ierr);
1179 /* Parse post settings for both solver and post-processor binaries using the single pre-allocated pps object. */
1180 ierr = ParsePostProcessingSettings(simCtx); CHKERRQ(ierr);
1181
1182 // === 5. Dependent Parameter Calculations ================================
1183 // Some parameters depend on others, so we calculate them here.
1184 simCtx->StartTime = (PetscReal)simCtx->StartStep*simCtx->dt;
1185 simCtx->ti = simCtx->StartTime;
1186 simCtx->step = simCtx->StartStep;
1187
1188 // === 5. Log Summary and Finalize Setup ==================================
1189 LOG_ALLOW(GLOBAL, LOG_DEBUG, "-- Console Output Functions [Total : %d] : --\n", simCtx->nAllowed);
1190 for (PetscInt i = 0; i < simCtx->nAllowed; ++i) {
1191 LOG_ALLOW(GLOBAL, LOG_DEBUG, " [%2d] «%s»\n", i, simCtx->allowedFuncs[i]);
1192 }
1193
1194 LOG_ALLOW(GLOBAL, LOG_INFO, "Configuration complete. Key parameters:\n");
1195 LOG_ALLOW(GLOBAL, LOG_INFO, " - Run mode: %s\n", simCtx->OnlySetup ? "SETUP ONLY" : "Full Simulation");
1196 LOG_ALLOW(GLOBAL, LOG_INFO, " - Time steps: %d (from %d to %d)\n", simCtx->StepsToRun, simCtx->StartStep, simCtx->StartStep + simCtx->StepsToRun);
1197 LOG_ALLOW(GLOBAL, LOG_INFO, " - Time step size (dt): %g\n", simCtx->dt);
1198 if (simCtx->tiout > 0) {
1199 LOG_ALLOW(GLOBAL, LOG_INFO, " - Field/restart output cadence: every %d step(s)\n", simCtx->tiout);
1200 } else {
1201 LOG_ALLOW(GLOBAL, LOG_INFO, " - Field/restart output cadence: DISABLED\n");
1202 }
1203 LOG_ALLOW(GLOBAL, LOG_INFO, " - Immersed Boundary: %s\n", simCtx->immersed ? "ENABLED" : "DISABLED");
1204 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particles: %d\n", simCtx->np);
1205 if (simCtx->np > 0) {
1206 if (simCtx->particleConsoleOutputFreq > 0) {
1207 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle console cadence: every %d step(s)\n", simCtx->particleConsoleOutputFreq);
1208 } else {
1209 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle console cadence: DISABLED\n");
1210 }
1211 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle console row subsampling: every %d particle(s)\n", simCtx->LoggingFrequency);
1212 }
1213 if (simCtx->StartStep > 0 && simCtx->np > 0) {
1214 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle Restart Mode: %s\n", simCtx->particleRestartMode);
1215 }
1216
1217 // --- Initialize PETSc's internal performance logging stage ---
1218 ierr = PetscLogDefaultBegin(); CHKERRQ(ierr); // REDUNDANT but safe.
1219 ierr = PetscMemorySetGetMaximumUsage(); CHKERRQ(ierr);
1220
1221 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Finished CreateSimulationContext successfully on rank %d.\n", simCtx->rank);
1222
1224 PetscFunctionReturn(0);
1225}
PetscErrorCode ParticleFieldPlanCreate(ParticleFieldPlan **plan)
Read a plan from the options database.
PetscErrorCode ParsePostProcessingSettings(SimCtx *simCtx)
Initializes post-processing settings from a config file and command-line overrides.
Definition io.c:3240
PetscErrorCode ParseScalingInformation(SimCtx *simCtx)
Parses physical scaling parameters from command-line options.
Definition io.c:3425
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
Definition logging.c:155
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:253
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
Definition logging.c:119
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:894
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:84
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
Definition logging.c:598
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:2023
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:885
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Returns the canonical log token for a particle-initialization mode.
Definition logging.c:724
static PetscErrorCode ParseLESConfiguration(SimCtx *simCtx)
Reads every LES closure parameter from the generated control file.
Definition setup.c:259
PetscErrorCode InitializeBrownianRNG(SimCtx *simCtx)
Internal helper implementation: InitializeBrownianRNG().
Definition setup.c:3940
PetscErrorCode LESConfigSetDefaults(LESConfig *config)
Implementation of LESConfigSetDefaults().
Definition setup.c:206
PetscBool RuntimeWalltimeGuardParsePositiveSeconds(const char *text, PetscReal *seconds_out)
Implementation of RuntimeWalltimeGuardParsePositiveSeconds().
Definition setup.c:67
PetscErrorCode ParseFieldStatisticsConfig(SimCtx *simCtx)
Resolves field-statistics configuration from the control file.
LESModelType
Identifies the subgrid-scale closure evaluated during a timestep.
Definition variables.h:548
@ NO_LES_MODEL
Definition variables.h:549
@ WALE
Definition variables.h:553
PetscReal icVelocityPhysical
Definition variables.h:921
PetscInt MHV
Definition variables.h:896
PetscBool mom_nk_monitor_history
Definition variables.h:914
PetscInt fieldStatisticsWindowCount
Definition variables.h:932
PetscInt movefsi
Definition variables.h:891
PetscBool continueMode
Definition variables.h:876
PetscInt moveframe
Definition variables.h:892
PetscInt TwoD
Definition variables.h:892
PetscInt pseudo_periodic
Definition variables.h:953
PetscBool profilingFinalSummary
Definition variables.h:1036
PetscReal schmidt_number
Definition variables.h:948
PetscMPIInt rank
Definition variables.h:862
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:1035
PetscInt LV
Heart-valve flux corrections for immersed bodies; refused at setup.
Definition variables.h:896
PetscReal angle
Definition variables.h:943
PetscReal Turbulent_schmidt_number
Definition variables.h:948
PetscInt64 searchLocatedCount
Definition variables.h:267
PetscInt statisticsConsoleOutputFreq
Definition variables.h:934
PetscInt block_number
Definition variables.h:952
PetscReal mom_rtol
Definition variables.h:901
PetscInt64 searchLostCount
Definition variables.h:268
PetscInt da_procs_z
Definition variables.h:956
PetscReal targetVolumetricFlux
Definition variables.h:967
PetscBool walltimeGuardActive
Definition variables.h:1038
PetscReal mom_last_lambda_max
Definition variables.h:913
PetscReal walltimeGuardWarmupTotalSeconds
Definition variables.h:1046
LESConfig les_config
Parameters of the LES closure selected by les.
Definition variables.h:987
PetscReal forceScalingFactor
Definition variables.h:961
PetscReal pseudo_cfl_reduction_factor
Definition variables.h:907
InitialConditionMode initialConditionMode
Definition variables.h:916
ParticleInitializationType
Enumerator to identify the particle initialization strategy.
Definition variables.h:709
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:710
PetscReal StartTime
Definition variables.h:873
PetscReal * solutionConvergenceMeanSpeedHistory
Definition variables.h:928
PetscReal FluxOutSum
Definition variables.h:959
PetscBool walltimeGuardHasEWMA
Definition variables.h:1048
PetscReal CMy_c
Definition variables.h:944
FlowDirection flowDirection
Definition variables.h:920
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:1051
char ** bcs_files
Definition variables.h:958
PetscReal boundaryVelocityCorrection
Definition variables.h:974
PetscReal max_angle
Definition variables.h:943
PetscReal min_pseudo_cfl
Definition variables.h:908
PetscInt64 boundaryClampCount
Definition variables.h:274
PetscInt particlesLostLastStep
Definition variables.h:997
PetscInt tiout
Definition variables.h:871
PetscReal walltimeGuardMinSeconds
Definition variables.h:1041
char allowedFile[PETSC_MAX_PATH_LEN]
Definition variables.h:1016
PetscInt da_procs_y
Definition variables.h:956
PetscInt64 traversalStepsSum
Definition variables.h:269
PetscBool mom_last_converged
Definition variables.h:912
PetscReal psrc_x
Definition variables.h:945
PetscReal ren
Definition variables.h:906
PetscReal iem_constant
IEM mixing constant C_IEM in Omega = C_IEM Gamma / Delta^2 (default 2.0).
Definition variables.h:949
PetscInt solutionConvergenceSamplesRecorded
Definition variables.h:927
PetscReal poissonSourceImbalance
Definition variables.h:1026
PetscBool drivenFluxTargetLatched
Definition variables.h:972
IBMVNodes * ibmv
Definition variables.h:1011
PetscInt64 searchPopulation
Definition variables.h:266
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:881
PetscBool solutionConvergenceEnabled
Definition variables.h:923
PetscReal * solutionConvergenceMeanKEHistory
Definition variables.h:929
PetscReal walltimeGuardLatestStepSeconds
Definition variables.h:1050
PetscReal dt
Definition variables.h:874
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:1052
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
Definition variables.h:1053
PetscInt occupiedCellCount
Definition variables.h:1003
PetscInt StepsToRun
Definition variables.h:870
char profilingTimestepMode[32]
Definition variables.h:1034
PetscInt k_periodic
Definition variables.h:953
PetscInt inletprofile
Definition variables.h:952
PetscReal bulkVelocityCorrection
Definition variables.h:973
PetscReal cdisy
Definition variables.h:906
PetscReal mom_atol
Definition variables.h:901
@ WALL_FUNCTION_CABOT
Definition variables.h:569
@ WALL_FUNCTION_NONE
Definition variables.h:566
PetscInt currentSettlementPass
Definition variables.h:278
PetscInt np
Definition variables.h:990
PetscBool fieldStatisticsEnabled
Definition variables.h:931
PetscBool no_pseudo_cfl_backtrack
Definition variables.h:910
PetscReal C_IEM
Definition variables.h:1007
PetscInt ccc
Definition variables.h:980
PetscReal ratio
Definition variables.h:981
PetscInt StartStep
Definition variables.h:869
PetscBool OnlySetup
Definition variables.h:875
PetscInt rotatefsi
Refused at setup: immersed boundaries and moving bodies are not implemented.
Definition variables.h:891
@ MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK
Definition variables.h:694
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:693
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:695
PetscInt solutionConvergencePeriodSteps
Definition variables.h:925
PetscReal cdisz
Definition variables.h:906
PetscScalar x
Definition variables.h:122
PetscInt64 reSearchCount
Definition variables.h:270
char * current_io_directory
Definition variables.h:885
PetscReal MaxDiv
Definition variables.h:1027
char grid_file[PETSC_MAX_PATH_LEN]
Definition variables.h:955
PetscInt invicid
Definition variables.h:892
char ** allowedFuncs
Definition variables.h:1018
PetscInt64 bboxGuessFallbackCount
Definition variables.h:276
InterpolationMethod interpolationMethod
Definition variables.h:995
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
Definition variables.h:945
PetscInt mg_poItr
Definition variables.h:902
VerificationScalarConfig verificationScalar
Definition variables.h:940
PetscReal max_pseudo_cfl
Definition variables.h:908
PetscInt MaxDivx
Definition variables.h:1028
PetscInt poisson
Definition variables.h:903
char profilingSelectedFuncsFile[PETSC_MAX_PATH_LEN]
Definition variables.h:1030
PetscInt MaxDivy
Definition variables.h:1028
char analysis_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:883
char particleRestartMode[16]
Definition variables.h:996
PetscInt64 bboxGuessSuccessCount
Definition variables.h:275
PetscInt MaxDivz
Definition variables.h:1028
BoundingBox * bboxlist
Definition variables.h:993
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:933
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:882
PetscInt MaxDivFlatArg
Definition variables.h:1028
PetscReal FluxInSum
Definition variables.h:959
PetscInt walltimeGuardCompletedSteps
Definition variables.h:1045
PetscInt64 maxParticlePassDepth
Definition variables.h:277
PetscInt les_gradient_model
Add the Clark gradient (tensor-diffusivity) term to the viscous flux.
Definition variables.h:986
PetscReal CMz_c
Definition variables.h:944
PetscInt64 maxTraversalSteps
Definition variables.h:271
PetscBool generate_grid
Definition variables.h:954
Cmpnts AnalyticalUniformVelocity
Definition variables.h:922
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:879
PetscReal imp_stol
Definition variables.h:901
PetscInt nAllowed
Definition variables.h:1019
PetscBool walltimeGuardEnabled
Definition variables.h:1037
PetscBool checkpointGeometryHashReady
Definition variables.h:887
PetscReal wall_roughness_height
Definition variables.h:947
PetscBool useProfilingSelectedFuncsCfg
Definition variables.h:1031
PetscInt walltimeGuardWarmupSteps
Definition variables.h:1039
ParticleInitializationType ParticleInitialization
Definition variables.h:994
PetscReal mom_dt_jameson_residual_norm_noise_allowance_factor
Definition variables.h:909
PetscScalar z
Definition variables.h:122
InterpolationMethod
Selects the grid-to-particle interpolation method.
Definition variables.h:722
@ INTERP_TRILINEAR
Definition variables.h:723
PetscInt wallfunction
Enable wall functions on WALL faces.
Definition variables.h:985
PetscInt drivingForceStep
Definition variables.h:966
PetscReal Flux_in
Definition variables.h:943
PetscReal drivenFluxMeasured
Definition variables.h:978
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
Definition variables.h:1054
char ** profilingSelectedFuncs
Definition variables.h:1032
PetscReal cdisx
Definition variables.h:906
PetscInt mglevels
Definition variables.h:902
PetscInt num_bcs_files
Definition variables.h:957
DM dm_swarm
Definition variables.h:992
PetscBool useCfg
Definition variables.h:1017
PetscReal psrc_y
Definition variables.h:945
PetscInt solutionConvergenceWindowSteps
Definition variables.h:926
PetscInt central
Definition variables.h:904
PetscReal Fluxsum
Definition variables.h:959
FlowDirection
Primary flow direction for streamwise IC and Poiseuille modes.
Definition variables.h:298
@ FLOW_DIR_UNSET
Definition variables.h:305
PetscReal pseudo_cfl_growth_factor
Definition variables.h:907
PetscInt particlesLostCumulative
Definition variables.h:998
PetscInt nProfilingSelectedFuncs
Definition variables.h:1033
PetscInt particlesMigratedLastStep
Definition variables.h:1002
PetscInt particleRandomSeed
Base seed for every particle RNG stream (-particle_random_seed).
Definition variables.h:991
char initialConditionDirectory[PETSC_MAX_PATH_LEN]
Definition variables.h:918
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:893
PetscInt da_procs_x
Definition variables.h:956
PetscReal walltimeGuardWarmupAverageSeconds
Definition variables.h:1047
InitialConditionMode
Selects the algorithm used to populate a fresh Eulerian velocity field.
Definition variables.h:177
@ IC_MODE_FILE
Definition variables.h:182
@ IC_MODE_ZERO
Definition variables.h:178
PetscInt particleConsoleOutputFreq
Definition variables.h:872
Cmpnts InitialConstantContra
Definition variables.h:919
SearchMetricsState searchMetrics
Definition variables.h:1005
PetscInt i_periodic
Definition variables.h:953
PetscReal mom_resid_rtol
Definition variables.h:901
char checkpointGeometrySHA256[65]
Definition variables.h:886
PetscReal runtimeMemoryLogPreviousProcessMB
Previous local process memory sample in MB.
Definition variables.h:1055
PetscInt step
Definition variables.h:867
PetscReal walltimeGuardEWMASeconds
Definition variables.h:1049
PetscReal AreaOutSum
Definition variables.h:979
PetscInt mom_max_pseudo_steps
Definition variables.h:900
PetscRandom BrownianMotionRNG
Definition variables.h:1006
PetscReal drivenFluxArea
Definition variables.h:978
PostProcessParams * pps
Definition variables.h:1058
PetscInt migrationPassesLastStep
Definition variables.h:1001
PetscScalar y
Definition variables.h:122
InitialConditionField
Selects the authoritative velocity representation in a staged file IC.
Definition variables.h:186
@ IC_FIELD_UCONT
Definition variables.h:188
@ IC_FIELD_UCAT
Definition variables.h:187
PetscMPIInt size
Definition variables.h:863
char _io_context_buffer[PETSC_MAX_PATH_LEN]
Definition variables.h:884
PetscReal walltimeGuardLimitSeconds
Definition variables.h:1044
PetscBool ps_ksp_pic_monitor_true_residual
Definition variables.h:915
PetscReal walltimeGuardEstimatorAlpha
Definition variables.h:1042
PetscInt les
Active LES closure; an LESModelType value.
Definition variables.h:984
@ SOLUTION_CONVERGENCE_TRANSIENT
Definition variables.h:705
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:703
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:704
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:702
PetscInt mg_preItr
Definition variables.h:902
PetscReal mom_ratio_ema_alpha
Definition variables.h:911
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:924
PetscViewer logviewer
Definition variables.h:877
PetscReal particlesLostScalarLastStep
Sum of Psi over the particles removed this step.
Definition variables.h:999
PetscInt64 searchAttempts
Definition variables.h:265
InitialConditionField initialConditionField
Definition variables.h:917
PetscInt64 tieBreakCount
Definition variables.h:273
PetscReal mom_resid_atol
Definition variables.h:901
PetscBool restartHistoryAvailable
Definition variables.h:888
PetscReal ti
Definition variables.h:868
PetscReal walltimeGuardMultiplier
Definition variables.h:1040
PetscInt rotateframe
moveframe/rotateframe are refused at setup.
Definition variables.h:892
IBMNodes * ibm
Definition variables.h:1010
PetscReal AreaInSum
Definition variables.h:979
MomentumSolverType mom_solver_type
Definition variables.h:899
PetscInt immersed
Definition variables.h:891
PetscInt64 maxTraversalFailCount
Definition variables.h:272
char PostprocessingControlFile[PETSC_MAX_PATH_LEN]
Definition variables.h:1057
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:880
VerificationDiffusivityConfig verificationDiffusivity
Definition variables.h:939
PetscReal walltimeGuardJobStartEpochSeconds
Definition variables.h:1043
PetscReal pseudo_cfl
Definition variables.h:906
PetscInt LoggingFrequency
Definition variables.h:1020
PetscReal CMx_c
Definition variables.h:944
PetscReal drivingForceMagnitude
Definition variables.h:961
PetscReal particleLoadImbalance
Definition variables.h:1004
struct ParticleFieldPlan * particleFieldPlan
Configured initial particle-field values, or NULL.
Definition variables.h:1000
PetscBool fieldStatisticsContinue
Definition variables.h:938
PetscInt j_periodic
Definition variables.h:953
FSInfo * fsi
Definition variables.h:1012
The master context for the entire simulation.
Definition variables.h:859
PetscBool VerificationScalarOverrideActive(const SimCtx *simCtx)
Reports whether a verification-only scalar override is active.
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 67 of file setup.c.

68{
69 char *endptr = NULL;
70 double parsed_value;
71
72 if (seconds_out) *seconds_out = 0.0;
73 if (!text || text[0] == '\0') return PETSC_FALSE;
74
75 errno = 0;
76 parsed_value = strtod(text, &endptr);
77 if (endptr == text || errno == ERANGE || !isfinite(parsed_value) || parsed_value <= 0.0) {
78 return PETSC_FALSE;
79 }
80
81 while (*endptr != '\0' && isspace((unsigned char)*endptr)) {
82 endptr++;
83 }
84 if (*endptr != '\0') return PETSC_FALSE;
85
86 if (seconds_out) *seconds_out = (PetscReal)parsed_value;
87 return PETSC_TRUE;
88}
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 1685 of file setup.c.

1686{
1687 PetscErrorCode ierr;
1688 PetscMPIInt rank;
1689 PetscBool exists;
1690
1691 PetscFunctionBeginUser;
1692 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1693
1694 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Setting up simulation environment ---\n");
1695
1696 /* =====================================================================
1697 * Phase 1: Check for all required and optional INPUT files.
1698 * ===================================================================== */
1699 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 1: Verifying input files...\n");
1700
1701 // --- Mandatory Inputs ---
1702 if (!simCtx->generate_grid) {
1703 ierr = VerifyPathExistence(simCtx->grid_file, PETSC_FALSE, PETSC_FALSE, "Grid file", &exists); CHKERRQ(ierr);
1704 }
1705 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
1706 char desc[128];
1707 ierr = PetscSNPrintf(desc, sizeof(desc), "BCS file #%d", i + 1); CHKERRQ(ierr);
1708 ierr = VerifyPathExistence(simCtx->bcs_files[i], PETSC_FALSE, PETSC_FALSE, desc, &exists); CHKERRQ(ierr);
1709 }
1710
1711 // --- Optional Inputs (these produce warnings if missing) ---
1712 if (simCtx->useCfg) {
1713 ierr = VerifyPathExistence(simCtx->allowedFile, PETSC_FALSE, PETSC_TRUE, "Whitelist config file", &exists); CHKERRQ(ierr);
1714 }
1715 if (simCtx->useProfilingSelectedFuncsCfg) {
1716 ierr = VerifyPathExistence(simCtx->profilingSelectedFuncsFile, PETSC_FALSE, PETSC_TRUE, "Profiling config file", &exists); CHKERRQ(ierr);
1717 }
1718 if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
1719 ierr = VerifyPathExistence(simCtx->PostprocessingControlFile, PETSC_FALSE, PETSC_TRUE, "Post-processing control file", &exists); CHKERRQ(ierr);
1720 }
1721
1722
1723 /* =====================================================================
1724 * Phase 2: Validate directories specific to the execution mode.
1725 * ===================================================================== */
1726 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 2: Verifying execution mode directories...\n");
1727 // The data source directory must exist if we intend to load any data from it.
1728 // This is true if:
1729 // 1. We are restarting from a previous time step (StartStep > 0), which implies
1730 // loading Eulerian fields and/or particle fields.
1731 // 2. We are starting from t=0 but are explicitly told to load the initial
1732 // Eulerian fields from a file (eulerianSource == "load").
1733 if (simCtx->StartStep > 0 || strcmp(simCtx->eulerianSource,"load")== 0){ // If this is a restart run
1734 ierr = VerifyPathExistence(simCtx->restart_dir, PETSC_TRUE, PETSC_FALSE, "Restart source directory", &exists); CHKERRQ(ierr);
1735 }
1736 if (simCtx->StartStep == 0 && strcmp(simCtx->eulerianSource, "solve") == 0 &&
1738 ierr = VerifyPathExistence(simCtx->initialConditionDirectory, PETSC_TRUE, PETSC_FALSE,
1739 "Initial-condition source directory", &exists); CHKERRQ(ierr);
1740 }
1741 if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
1742 ierr = VerifyPathExistence(simCtx->pps->source_dir, PETSC_TRUE, PETSC_FALSE, "Post-processing source directory", &exists); CHKERRQ(ierr);
1743 }
1744
1745 /* =====================================================================
1746 * Phase 3: Create and prepare all OUTPUT directories.
1747 * ===================================================================== */
1748 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 3: Preparing output directories...\n");
1749
1750 if (rank == 0){
1751 if(simCtx->exec_mode == EXEC_MODE_SOLVER){
1752 // --- Prepare Log Directory ---
1753 if (!simCtx->continueMode) {
1754 // Only wipe logs on fresh runs; continue mode appends to existing logs.
1755 // Final guard: this delete is recursive and irreversible, so re-check
1756 // containment here rather than trusting that the launcher validated it.
1757 {
1758 PetscBool unsafe_authorized = PETSC_FALSE;
1759 const char *refusal = NULL;
1760 ierr = PetscOptionsGetBool(NULL, NULL, "-allow_unsafe_log_dir",
1761 &unsafe_authorized, NULL); CHKERRQ(ierr);
1762 if (!LogDirectoryIsSafeToWipe(simCtx->log_dir, simCtx->output_dir,
1763 unsafe_authorized, &refusal)) {
1764 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
1765 "Refusing to delete log directory '%s': it %s. Configure run "
1766 "directories through monitor.io.directories.",
1767 simCtx->log_dir, refusal);
1768 }
1769 if (unsafe_authorized) {
1771 "Deleting log directory '%s' outside the working directory, "
1772 "authorized by -allow_unsafe_log_dir.\n", simCtx->log_dir);
1773 }
1774 }
1775 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating/cleaning log directory: %s\n", simCtx->log_dir);
1776 ierr = PetscRMTree(simCtx->log_dir); // Wipes the directory and its contents
1777 if (ierr) { /* Ignore file-not-found error, but fail on others */
1778 PetscError(PETSC_COMM_SELF, __LINE__, __FUNCT__, __FILE__, ierr, PETSC_ERROR_INITIAL, "Could not remove existing log directory '%s'. Check permissions.", simCtx->log_dir);
1779 }
1780 ierr = PetscMkdir(simCtx->log_dir); CHKERRQ(ierr);
1781 } else {
1782 // In continue mode, ensure log directory exists but don't wipe it.
1783 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Continue mode: preserving existing log directory: %s\n", simCtx->log_dir);
1784 ierr = PetscMkdir(simCtx->log_dir); CHKERRQ(ierr);
1785 }
1786
1787 // --- Prepare Output Directory ---
1788 // The checkpoint coordinator creates its fixed internal hierarchy
1789 // transactionally when a checkpoint is due.
1790 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying main output directory: %s\n", simCtx->output_dir);
1791 ierr = PetscTestDirectory(simCtx->output_dir, 'r', &exists); CHKERRQ(ierr);
1792 if (!exists) {
1793 LOG_ALLOW(GLOBAL, LOG_INFO, "Output directory not found. Creating: %s\n", simCtx->output_dir);
1794 ierr = PetscMkdir(simCtx->output_dir); CHKERRQ(ierr);
1795 }
1796 // The analysis home is nested (output/analysis/metrics by default), so it
1797 // needs the recursive create the postprocessor branch already uses; PetscMkdir
1798 // fails on a path whose parents do not exist yet.
1799 ierr = PetscMkdirRecursive(simCtx->analysis_dir); CHKERRQ(ierr);
1800 } else if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1801 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Preparing post-processing output directories ...\n");
1802
1803 PostProcessParams *pps = simCtx->pps;
1804 char path_buffer[PETSC_MAX_PATH_LEN];
1805
1806 const char *last_slash_euler = strrchr(pps->output_prefix, '/');
1807 if(last_slash_euler){
1808 size_t dir_len = last_slash_euler - pps->output_prefix;
1809 if(dir_len > 0){
1810 if(dir_len >= sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing output prefix path is too long.");
1811 strncpy(path_buffer, pps->output_prefix, dir_len);
1812 path_buffer[dir_len] = '\0';
1813
1814 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1815 if (!exists){
1816 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Eulerian output directory: %s\n", path_buffer);
1817 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
1818 }
1819 }
1820 }
1821
1822 // Particle output directory
1823 if(pps->outputParticles){
1824 const char *last_slash_particle = strrchr(pps->particle_output_prefix, '/');
1825 if(last_slash_particle){
1826 size_t dir_len = last_slash_particle - pps->particle_output_prefix;
1827 if(dir_len > 0){
1828 if(dir_len > sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing particle output prefix path is too long.");
1829 strncpy(path_buffer, pps->particle_output_prefix, dir_len);
1830 path_buffer[dir_len] = '\0';
1831
1832 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1833
1834 if (!exists){
1835 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Particle output directory: %s\n", path_buffer);
1836 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
1837 }
1838 }
1839 }
1840 }
1841
1842 // Statistics output directory
1843 if(pps->statistics_pipeline[0] != '\0'){
1844 const char *last_slash_stats = strrchr(pps->statistics_output_prefix, '/');
1845 if(last_slash_stats){
1846 size_t dir_len = last_slash_stats - pps->statistics_output_prefix;
1847 if(dir_len > 0){
1848 if(dir_len >= sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing statistics output prefix path is too long.");
1849 strncpy(path_buffer, pps->statistics_output_prefix, dir_len);
1850 path_buffer[dir_len] = '\0';
1851
1852 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
1853 if (!exists){
1854 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Statistics output directory: %s\n", path_buffer);
1855 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
1856 }
1857 }
1858 }
1859 }
1860 }
1861 }
1862
1863 // Synchronize all processes before proceeding
1864 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRMPI(ierr);
1865
1866 /* PETSc opens a -info file during PetscInitialize, before the fresh-run wipe above
1867 removes the log directory it usually lives in. Every later record would then go
1868 to an unlinked file and the run would end with no info log at all, so each rank
1869 reopens its file once the directory exists again. Records from initialization
1870 itself are the only ones lost. */
1871 if (simCtx->exec_mode == EXEC_MODE_SOLVER && !simCtx->continueMode) {
1872 char *info_name = NULL;
1873 FILE *info_file = NULL;
1874 ierr = PetscInfoGetFile(&info_name, &info_file); CHKERRQ(ierr);
1875 if (info_name && info_name[0] != '\0') {
1876 char reopen_name[PETSC_MAX_PATH_LEN];
1877 ierr = PetscStrncpy(reopen_name, info_name, sizeof(reopen_name)); CHKERRQ(ierr);
1878 if (info_file && info_file != PETSC_STDOUT) {
1879 ierr = PetscFClose(PETSC_COMM_SELF, info_file); CHKERRQ(ierr);
1880 }
1881 ierr = PetscInfoSetFile(reopen_name, "w"); CHKERRQ(ierr);
1882 }
1883 /* PetscInfoGetFile hands back its own copy of the name. */
1884 ierr = PetscFree(info_name); CHKERRQ(ierr);
1885 }
1886
1887 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Environment setup complete ---\n");
1888
1889 PetscFunctionReturn(0);
1890}
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:1136
static PetscBool LogDirectoryIsSafeToWipe(const char *log_dir, const char *output_dir, PetscBool authorized, const char **reason)
Final safety guard before the runtime deletes its log directory.
Definition setup.c:1669
static PetscErrorCode PetscMkdirRecursive(const char *path)
Create a directory path recursively using PETSc-compatible error handling.
Definition setup.c:1232
#define __FUNCT__
Definition setup.c:199
char statistics_output_prefix[256]
basename for CSV output, e.g.
Definition variables.h:777
char particle_output_prefix[256]
Definition variables.h:772
char output_prefix[256]
Definition variables.h:769
char statistics_pipeline[1024]
e.g.
Definition variables.h:776
char source_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:756
PetscBool outputParticles
Definition variables.h:764
@ EXEC_MODE_SOLVER
Definition variables.h:832
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:833
ExecutionMode exec_mode
Definition variables.h:878
Holds all configuration parameters for a post-processing run.
Definition variables.h:754
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 2001 of file setup.c.

2002{
2003 PetscErrorCode ierr;
2004 PetscFunctionBeginUser;
2005
2007
2008 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Starting Grid and Solvers Setup ---\n");
2009
2010 // Phase 1: Allocate the UserMG and UserCtx hierarchy
2011 ierr = AllocateContextHierarchy(simCtx); CHKERRQ(ierr);
2012
2013 ierr = DefineAllGridDimensions(simCtx); CHKERRQ(ierr);
2014 ierr = InitializeAllGridDMs(simCtx); CHKERRQ(ierr);
2015 ierr = AssignAllGridCoordinates(simCtx); CHKERRQ(ierr);
2016 ierr = CreateAndInitializeAllVectors(simCtx); CHKERRQ(ierr);
2017
2018 // NOTE: CalculateAllGridMetrics is now called inside SetupBoundaryConditions (not here) to ensure:
2019 // 1. Boundary condition configuration data (boundary_faces) is available for periodic BC corrections
2020 // 2. Computed metrics are available for inlet/outlet area calculations
2021 // This resolves the circular dependency between BC setup and metric calculations.
2022
2023 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Grid and Solvers Setup Complete ---\n");
2024
2026 PetscFunctionReturn(0);
2027}
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:276
PetscErrorCode AssignAllGridCoordinates(SimCtx *simCtx)
Orchestrates the assignment of physical coordinates to all DMDA objects.
Definition grid.c:358
PetscErrorCode CreateAndInitializeAllVectors(SimCtx *simCtx)
Internal helper implementation: CreateAndInitializeAllVectors().
Definition setup.c:2036
static PetscErrorCode AllocateContextHierarchy(SimCtx *simCtx)
Allocate the user-context objects required by every multigrid level.
Definition setup.c:1897
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 2036 of file setup.c.

2037{
2038 PetscErrorCode ierr;
2039 UserMG *usermg = &simCtx->usermg;
2040 MGCtx *mgctx = usermg->mgctx;
2041 PetscInt nblk = simCtx->block_number;
2042
2043 PetscFunctionBeginUser;
2044
2046
2047 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating and initializing all simulation vectors...\n");
2048
2049 for (PetscInt level = usermg->mglevels-1; level >=0; level--) {
2050 for (PetscInt bi = 0; bi < nblk; bi++) {
2051 UserCtx *user = &mgctx[level].user[bi];
2052
2053 if(!user->da || !user->fda) {
2054 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "DMs not properly initialized in UserCtx before vector creation.");
2055 }
2056
2057 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Rank %d: Creating vectors for level %d, block %d\n", simCtx->rank, level, bi);
2058
2059 // --- Group A: Primary Flow Fields (Global and Local) ---
2060 // These are the core solution variables.
2061 ierr = DMCreateGlobalVector(user->fda, &user->Ucont); CHKERRQ(ierr); ierr = VecSet(user->Ucont, 0.0); CHKERRQ(ierr);
2062 ierr = DMCreateGlobalVector(user->fda, &user->Ucat); CHKERRQ(ierr); ierr = VecSet(user->Ucat, 0.0); CHKERRQ(ierr);
2063 ierr = DMCreateGlobalVector(user->da, &user->P); CHKERRQ(ierr); ierr = VecSet(user->P, 0.0); CHKERRQ(ierr);
2064 ierr = DMCreateGlobalVector(user->da, &user->Nvert); CHKERRQ(ierr); ierr = VecSet(user->Nvert, 0.0); CHKERRQ(ierr);
2065
2066 ierr = DMCreateLocalVector(user->fda, &user->lUcont); CHKERRQ(ierr); ierr = VecSet(user->lUcont, 0.0); CHKERRQ(ierr);
2067 ierr = DMCreateLocalVector(user->fda, &user->lUcat); CHKERRQ(ierr); ierr = VecSet(user->lUcat, 0.0); CHKERRQ(ierr);
2068 ierr = DMCreateLocalVector(user->da, &user->lP); CHKERRQ(ierr); ierr = VecSet(user->lP, 0.0); CHKERRQ(ierr);
2069 ierr = DMCreateLocalVector(user->da, &user->lNvert); CHKERRQ(ierr); ierr = VecSet(user->lNvert, 0.0); CHKERRQ(ierr);
2070
2071 // -- Group A2: Derived Flow Fields (Global and Local) ---
2072 ierr = VecDuplicate(user->P,&user->Diffusivity); CHKERRQ(ierr); ierr = VecSet(user->Diffusivity, 0.0); CHKERRQ(ierr);
2073 ierr = VecDuplicate(user->lP,&user->lDiffusivity); CHKERRQ(ierr); ierr = VecSet(user->lDiffusivity, 0.0); CHKERRQ(ierr);
2074 ierr = VecDuplicate(user->Ucat,&user->DiffusivityGradient); CHKERRQ(ierr); ierr = VecSet(user->DiffusivityGradient, 0.0); CHKERRQ(ierr);
2075 ierr = VecDuplicate(user->lUcat,&user->lDiffusivityGradient); CHKERRQ(ierr); ierr = VecSet(user->lDiffusivityGradient, 0.0); CHKERRQ(ierr);
2076
2077 // -- Group B: Solver Work Vectors (Global and Local) ---
2078 ierr = VecDuplicate(user->P, &user->Phi); CHKERRQ(ierr); ierr = VecSet(user->Phi, 0.0); CHKERRQ(ierr);
2079 ierr = VecDuplicate(user->lP, &user->lPhi); CHKERRQ(ierr); ierr = VecSet(user->lPhi, 0.0); CHKERRQ(ierr);
2080
2081 // --- Group C: Time-Stepping & Workspace Fields (Finest Level Only) ---
2082 if (level == usermg->mglevels - 1) {
2083 ierr = VecDuplicate(user->Ucont, &user->Ucont_o); CHKERRQ(ierr); ierr = VecSet(user->Ucont_o, 0.0); CHKERRQ(ierr);
2084 ierr = VecDuplicate(user->Ucont, &user->Ucont_rm1); CHKERRQ(ierr); ierr = VecSet(user->Ucont_rm1, 0.0); CHKERRQ(ierr);
2085 ierr = VecDuplicate(user->Ucat, &user->Ucat_o); CHKERRQ(ierr); ierr = VecSet(user->Ucat_o, 0.0); CHKERRQ(ierr);
2086 ierr = VecDuplicate(user->P, &user->P_o); CHKERRQ(ierr); ierr = VecSet(user->P_o, 0.0); CHKERRQ(ierr);
2087 ierr = VecDuplicate(user->lUcont, &user->lUcont_o); CHKERRQ(ierr); ierr = VecSet(user->lUcont_o, 0.0); CHKERRQ(ierr);
2088 ierr = VecDuplicate(user->lUcont, &user->lUcont_rm1); CHKERRQ(ierr); ierr = VecSet(user->lUcont_rm1, 0.0); CHKERRQ(ierr);
2089 ierr = DMCreateLocalVector(user->da, &user->lNvert_o); CHKERRQ(ierr); ierr = VecSet(user->lNvert_o, 0.0); CHKERRQ(ierr);
2090 ierr = VecDuplicate(user->Nvert, &user->Nvert_o); CHKERRQ(ierr); ierr = VecSet(user->Nvert_o, 0.0); CHKERRQ(ierr);
2091 }
2092
2093 // --- Group D: Grid Metrics (Face-Centered) ---
2094 ierr = DMCreateGlobalVector(user->fda, &user->Csi); CHKERRQ(ierr); ierr = VecSet(user->Csi, 0.0); CHKERRQ(ierr);
2095 ierr = VecDuplicate(user->Csi, &user->Eta); CHKERRQ(ierr); ierr = VecSet(user->Eta, 0.0); CHKERRQ(ierr);
2096 ierr = VecDuplicate(user->Csi, &user->Zet); CHKERRQ(ierr); ierr = VecSet(user->Zet, 0.0); CHKERRQ(ierr);
2097 ierr = DMCreateGlobalVector(user->da, &user->Aj); CHKERRQ(ierr); ierr = VecSet(user->Aj, 0.0); CHKERRQ(ierr);
2098
2099 ierr = DMCreateLocalVector(user->fda, &user->lCsi); CHKERRQ(ierr); ierr = VecSet(user->lCsi, 0.0); CHKERRQ(ierr);
2100 ierr = VecDuplicate(user->lCsi, &user->lEta); CHKERRQ(ierr); ierr = VecSet(user->lEta, 0.0); CHKERRQ(ierr);
2101 ierr = VecDuplicate(user->lCsi, &user->lZet); CHKERRQ(ierr); ierr = VecSet(user->lZet, 0.0); CHKERRQ(ierr);
2102 ierr = DMCreateLocalVector(user->da, &user->lAj); CHKERRQ(ierr); ierr = VecSet(user->lAj, 0.0); CHKERRQ(ierr);
2103
2104
2105 // --- Group E: Grid Metrics (Face-Centered) ---
2106 // Vector metrics are duplicated from Csi (DOF=3, fda-based)
2107 ierr = VecDuplicate(user->Csi, &user->ICsi); CHKERRQ(ierr); ierr = VecSet(user->ICsi, 0.0); CHKERRQ(ierr);
2108 ierr = VecDuplicate(user->Csi, &user->IEta); CHKERRQ(ierr); ierr = VecSet(user->IEta, 0.0); CHKERRQ(ierr);
2109 ierr = VecDuplicate(user->Csi, &user->IZet); CHKERRQ(ierr); ierr = VecSet(user->IZet, 0.0); CHKERRQ(ierr);
2110 ierr = VecDuplicate(user->Csi, &user->JCsi); CHKERRQ(ierr); ierr = VecSet(user->JCsi, 0.0); CHKERRQ(ierr);
2111 ierr = VecDuplicate(user->Csi, &user->JEta); CHKERRQ(ierr); ierr = VecSet(user->JEta, 0.0); CHKERRQ(ierr);
2112 ierr = VecDuplicate(user->Csi, &user->JZet); CHKERRQ(ierr); ierr = VecSet(user->JZet, 0.0); CHKERRQ(ierr);
2113 ierr = VecDuplicate(user->Csi, &user->KCsi); CHKERRQ(ierr); ierr = VecSet(user->KCsi, 0.0); CHKERRQ(ierr);
2114 ierr = VecDuplicate(user->Csi, &user->KEta); CHKERRQ(ierr); ierr = VecSet(user->KEta, 0.0); CHKERRQ(ierr);
2115 ierr = VecDuplicate(user->Csi, &user->KZet); CHKERRQ(ierr); ierr = VecSet(user->KZet, 0.0); CHKERRQ(ierr);
2116 // Scalar metrics are duplicated from Aj (DOF=1, da-based)
2117 ierr = VecDuplicate(user->Aj, &user->IAj); CHKERRQ(ierr); ierr = VecSet(user->IAj, 0.0); CHKERRQ(ierr);
2118 ierr = VecDuplicate(user->Aj, &user->JAj); CHKERRQ(ierr); ierr = VecSet(user->JAj, 0.0); CHKERRQ(ierr);
2119 ierr = VecDuplicate(user->Aj, &user->KAj); CHKERRQ(ierr); ierr = VecSet(user->KAj, 0.0); CHKERRQ(ierr);
2120
2121 ierr = VecDuplicate(user->lCsi, &user->lICsi); CHKERRQ(ierr); ierr = VecSet(user->lICsi, 0.0); CHKERRQ(ierr);
2122 ierr = VecDuplicate(user->lCsi, &user->lIEta); CHKERRQ(ierr); ierr = VecSet(user->lIEta, 0.0); CHKERRQ(ierr);
2123 ierr = VecDuplicate(user->lCsi, &user->lIZet); CHKERRQ(ierr); ierr = VecSet(user->lIZet, 0.0); CHKERRQ(ierr);
2124 ierr = VecDuplicate(user->lCsi, &user->lJCsi); CHKERRQ(ierr); ierr = VecSet(user->lJCsi, 0.0); CHKERRQ(ierr);
2125 ierr = VecDuplicate(user->lCsi, &user->lJEta); CHKERRQ(ierr); ierr = VecSet(user->lJEta, 0.0); CHKERRQ(ierr);
2126 ierr = VecDuplicate(user->lCsi, &user->lJZet); CHKERRQ(ierr); ierr = VecSet(user->lJZet, 0.0); CHKERRQ(ierr);
2127 ierr = VecDuplicate(user->lCsi, &user->lKCsi); CHKERRQ(ierr); ierr = VecSet(user->lKCsi, 0.0); CHKERRQ(ierr);
2128 ierr = VecDuplicate(user->lCsi, &user->lKEta); CHKERRQ(ierr); ierr = VecSet(user->lKEta, 0.0); CHKERRQ(ierr);
2129 ierr = VecDuplicate(user->lCsi, &user->lKZet); CHKERRQ(ierr); ierr = VecSet(user->lKZet, 0.0); CHKERRQ(ierr);
2130
2131 ierr = VecDuplicate(user->lAj, &user->lIAj); CHKERRQ(ierr); ierr = VecSet(user->lIAj, 0.0); CHKERRQ(ierr);
2132 ierr = VecDuplicate(user->lAj, &user->lJAj); CHKERRQ(ierr); ierr = VecSet(user->lJAj, 0.0); CHKERRQ(ierr);
2133 ierr = VecDuplicate(user->lAj, &user->lKAj); CHKERRQ(ierr); ierr = VecSet(user->lKAj, 0.0); CHKERRQ(ierr);
2134
2135 // --- Group F: Cell/Face Center Coordinates and Grid Spacing ---
2136 ierr = DMCreateGlobalVector(user->fda, &user->Cent); CHKERRQ(ierr); ierr = VecSet(user->Cent, 0.0); CHKERRQ(ierr);
2137 ierr = DMCreateLocalVector(user->fda, &user->lCent); CHKERRQ(ierr); ierr = VecSet(user->lCent, 0.0); CHKERRQ(ierr);
2138
2139 ierr = VecDuplicate(user->Cent, &user->GridSpace); CHKERRQ(ierr); ierr = VecSet(user->GridSpace, 0.0); CHKERRQ(ierr);
2140 ierr = VecDuplicate(user->lCent, &user->lGridSpace); CHKERRQ(ierr); ierr = VecSet(user->lGridSpace, 0.0); CHKERRQ(ierr);
2141
2142 ierr = VecDuplicate(user->Cent, &user->Centx); CHKERRQ(ierr); ierr = VecSet(user->Centx, 0.0); CHKERRQ(ierr);
2143 ierr = VecDuplicate(user->Cent, &user->Centy); CHKERRQ(ierr); ierr = VecSet(user->Centy, 0.0); CHKERRQ(ierr);
2144 ierr = VecDuplicate(user->Cent, &user->Centz); CHKERRQ(ierr); ierr = VecSet(user->Centz, 0.0); CHKERRQ(ierr);
2145 ierr = VecDuplicate(user->lCent, &user->lCentx); CHKERRQ(ierr); ierr = VecSet(user->lCentx, 0.0); CHKERRQ(ierr);
2146 ierr = VecDuplicate(user->lCent, &user->lCenty); CHKERRQ(ierr); ierr = VecSet(user->lCenty, 0.0); CHKERRQ(ierr);
2147 ierr = VecDuplicate(user->lCent, &user->lCentz); CHKERRQ(ierr); ierr = VecSet(user->lCentz, 0.0); CHKERRQ(ierr);
2148
2149 if(level == usermg->mglevels -1){
2150 // --- Group G: Turbulence Models (Finest Level Only) ---
2151 if (simCtx->les) {
2152 ierr = DMCreateGlobalVector(user->da, &user->Nu_t); CHKERRQ(ierr); ierr = VecSet(user->Nu_t, 0.0); CHKERRQ(ierr);
2153 ierr = DMCreateLocalVector(user->da, &user->lNu_t); CHKERRQ(ierr); ierr = VecSet(user->lNu_t, 0.0); CHKERRQ(ierr);
2154 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Turbulence viscosity (Nu_t) vectors created for the LES model.\n");
2155 // Only the dynamic model carries a coefficient field. The constant model
2156 // reads its coefficient straight from configuration, so allocating,
2157 // synchronizing, and checkpointing a field of one repeated number would
2158 // buy nothing.
2159 if(simCtx->les == DYNAMIC_SMAGORINSKY){
2160 ierr = DMCreateGlobalVector(user->da,&user->CS); CHKERRQ(ierr); ierr = VecSet(user->CS,0.0); CHKERRQ(ierr);
2161 ierr = DMCreateLocalVector(user->da,&user->lCs); CHKERRQ(ierr); ierr = VecSet(user->lCs,0.0); CHKERRQ(ierr);
2162 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Dynamic Smagorinsky coefficient (CS) vectors created.\n");
2163 }
2164
2165 // Add K_Omega etc. here as needed
2166
2167 // Note: Add any other vectors from the legacy MG_Initial here as needed.
2168 // For example: Rhs, Forcing, turbulence Vecs (K_Omega, Nu_t)...
2169
2170 }
2171
2172 /* A wall model is configured independently of LES and RANS - `wall_function`
2173 is their sibling in the schema, not their child - so its storage cannot sit
2174 inside their block. It did, which left `ApplyWallFunction` dereferencing a
2175 null vector on any case that enabled a wall model without one of them. */
2176 if (simCtx->wallfunction) {
2177 /* Scalar per cell, so it lives on `da`. It was previously created from
2178 `fda`, whose dof is 3, while every reader opens it through `da` - a
2179 pairing PETSc rejects outright. */
2180 ierr = DMCreateGlobalVector(user->da, &user->Friction_Velocity); CHKERRQ(ierr);
2181 ierr = VecSet(user->Friction_Velocity, 0.0); CHKERRQ(ierr);
2182 ierr = DMCreateLocalVector(user->da, &user->lFriction_Velocity); CHKERRQ(ierr);
2183 ierr = VecSet(user->lFriction_Velocity, 0.0); CHKERRQ(ierr);
2184 ierr = DMCreateGlobalVector(user->da, &user->Nu_Wall); CHKERRQ(ierr);
2185 ierr = VecSet(user->Nu_Wall, 0.0); CHKERRQ(ierr);
2186 ierr = DMCreateLocalVector(user->da, &user->lNu_Wall); CHKERRQ(ierr);
2187 ierr = VecSet(user->lNu_Wall, 0.0); CHKERRQ(ierr);
2188 }
2189 // --- Group H: Particle Methods
2190 if(simCtx->np>0){
2191 ierr = DMCreateGlobalVector(user->da,&user->ParticleCount); CHKERRQ(ierr); ierr = VecSet(user->ParticleCount,0.0); CHKERRQ(ierr);
2192 ierr = DMCreateLocalVector(user->da,&user->lParticleCount); CHKERRQ(ierr); ierr = VecSet(user->lParticleCount,0.0); CHKERRQ(ierr);
2193 // Scalar field to hold particle scalar property (e.g., temperature, concentration)
2194 ierr = DMCreateGlobalVector(user->da,&user->Psi); CHKERRQ(ierr); ierr = VecSet(user->Psi,0.0); CHKERRQ(ierr);
2195 ierr = DMCreateLocalVector(user->da,&user->lPsi); CHKERRQ(ierr); ierr = VecSet(user->lPsi,0.0); CHKERRQ(ierr);
2196 LOG_ALLOW(GLOBAL,LOG_DEBUG,"ParticleCount & Scalar(Psi) created for %d particles.\n",simCtx->np);
2197 }
2198 }
2199 // --- Group I: Boundary Condition vectors ---
2200 ierr = DMCreateGlobalVector(user->fda, &user->Bcs.Ubcs); CHKERRQ(ierr);
2201 ierr = VecSet(user->Bcs.Ubcs, 0.0); CHKERRQ(ierr);
2202 ierr = DMCreateGlobalVector(user->fda, &user->Bcs.Uch); CHKERRQ(ierr);
2203 ierr = VecSet(user->Bcs.Uch, 0.0); CHKERRQ(ierr);
2204
2205 // --- Group L: Field-Statistics Accumulators (Finest Level Only) ---
2206 // Config-counted, like the convergence-state reference fields: the window
2207 // count is resolved before this factory runs, and each accumulator is
2208 // duplicated from a vector created above so it inherits DM and layout.
2209 if (level == usermg->mglevels - 1 && FieldStatisticsIsActive(simCtx)) {
2210 ierr = PetscCalloc1((size_t)simCtx->fieldStatisticsWindowCount,
2211 &user->fieldStatisticsStorage); CHKERRQ(ierr);
2212 for (PetscInt w = 0; w < simCtx->fieldStatisticsWindowCount; ++w) {
2213 ierr = PicurvWindowStorageCreate(user,
2215 &user->fieldStatisticsStorage[w]); CHKERRQ(ierr);
2216 }
2218 "Allocated accumulators for %d statistics window(s).\n",
2220 }
2221
2222 // --- Group K: Corner-Staging Workspace (Finest Level Only) ---
2223 // One pair per block size. Previously these were created lazily inside
2224 // the interpolation routine and rebuilt whenever the block size changed;
2225 // allocating both here removes that churn and the cached-size check.
2226 if (level == usermg->mglevels - 1) {
2227 ierr = DMCreateGlobalVector(user->da, &user->CellScalarAtCorner); CHKERRQ(ierr);
2228 ierr = VecSet(user->CellScalarAtCorner, 0.0); CHKERRQ(ierr);
2229 ierr = DMCreateLocalVector(user->da, &user->lCellScalarAtCorner); CHKERRQ(ierr);
2230 ierr = VecSet(user->lCellScalarAtCorner, 0.0); CHKERRQ(ierr);
2231 ierr = DMCreateGlobalVector(user->fda, &user->CellVectorAtCorner); CHKERRQ(ierr);
2232 ierr = VecSet(user->CellVectorAtCorner, 0.0); CHKERRQ(ierr);
2233 ierr = DMCreateLocalVector(user->fda, &user->lCellVectorAtCorner); CHKERRQ(ierr);
2234 ierr = VecSet(user->lCellVectorAtCorner, 0.0); CHKERRQ(ierr);
2235 }
2236
2237 /* --- Group N: Statistics Output Staging (Finest Level Only) ---
2238 * The same kind of object as the corner workspace: a named buffer the
2239 * shared kernels can address, rather than simulation state. It exists only
2240 * to carry derived statistics to the nodal and VTK paths, so a run without
2241 * statistics allocates none of it. */
2242 if (level == usermg->mglevels - 1 && FieldStatisticsIsActive(simCtx)) {
2243 ierr = DMCreateGlobalVector(user->da, &user->PostScalar); CHKERRQ(ierr);
2244 ierr = VecSet(user->PostScalar, 0.0); CHKERRQ(ierr);
2245 ierr = DMCreateLocalVector(user->da, &user->lPostScalar); CHKERRQ(ierr);
2246 ierr = VecSet(user->lPostScalar, 0.0); CHKERRQ(ierr);
2247 ierr = DMCreateGlobalVector(user->da, &user->PostScalarNodal); CHKERRQ(ierr);
2248 ierr = VecSet(user->PostScalarNodal, 0.0); CHKERRQ(ierr);
2249 ierr = DMCreateGlobalVector(user->fda, &user->PostVector); CHKERRQ(ierr);
2250 ierr = VecSet(user->PostVector, 0.0); CHKERRQ(ierr);
2251 ierr = DMCreateLocalVector(user->fda, &user->lPostVector); CHKERRQ(ierr);
2252 ierr = VecSet(user->lPostVector, 0.0); CHKERRQ(ierr);
2253 ierr = DMCreateGlobalVector(user->fda, &user->PostVectorNodal); CHKERRQ(ierr);
2254 ierr = VecSet(user->PostVectorNodal, 0.0); CHKERRQ(ierr);
2255 }
2256
2257 if(level == usermg->mglevels - 1){
2258 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
2259 LOG_ALLOW(LOCAL, LOG_DEBUG, "Post-processor mode detected. Allocating derived field vectors.\n");
2260
2261 ierr = VecDuplicate(user->P, &user->P_nodal); CHKERRQ(ierr);
2262 ierr = VecSet(user->P_nodal, 0.0); CHKERRQ(ierr);
2263
2264 ierr = VecDuplicate(user->Ucat, &user->Ucat_nodal); CHKERRQ(ierr);
2265 ierr = VecSet(user->Ucat_nodal, 0.0); CHKERRQ(ierr);
2266
2267 ierr = VecDuplicate(user->P, &user->Qcrit); CHKERRQ(ierr);
2268 ierr = VecSet(user->Qcrit, 0.0); CHKERRQ(ierr);
2269 ierr = DMCreateLocalVector(user->da, &user->lQcrit); CHKERRQ(ierr);
2270 ierr = VecSet(user->lQcrit, 0.0); CHKERRQ(ierr);
2271 ierr = VecDuplicate(user->P, &user->Qcrit_nodal); CHKERRQ(ierr);
2272 ierr = VecSet(user->Qcrit_nodal, 0.0); CHKERRQ(ierr);
2273
2274 LOG_ALLOW(LOCAL, LOG_DEBUG, "Derived field vectors P_nodal, Ucat_nodal, and Qcrit created.\n");
2275
2276 if(simCtx->np>0){
2277 ierr = VecDuplicate(user->Psi, &user->Psi_nodal); CHKERRQ(ierr);
2278 ierr = VecSet(user->Psi_nodal, 0.0); CHKERRQ(ierr);
2279
2280 LOG_ALLOW(LOCAL, LOG_DEBUG, "Derived field vector Psi_nodal created for particle scalar property.\n");
2281
2282 }
2283 }else{
2284 user->P_nodal = NULL;
2285 user->Ucat_nodal = NULL;
2286 user->Qcrit = NULL;
2287 user->lQcrit = NULL;
2288 user->Qcrit_nodal = NULL;
2289 user->Psi_nodal = NULL;
2290 }
2291 }
2292
2293 }
2294}
2295
2296 /* Config-counted vectors belong to this factory too. The convergence state
2297 * allocates a Vec array whose length comes from configuration, so it is
2298 * invoked here rather than by the caller, keeping every vector this run
2299 * owns created in one place. It depends only on option-parsed configuration
2300 * and on the vectors created above. */
2301 ierr = InitializeSolutionConvergenceState(simCtx); CHKERRQ(ierr);
2302
2303 LOG_ALLOW(GLOBAL, LOG_INFO, "All simulation vectors created and initialized.\n");
2304
2306 PetscFunctionReturn(0);
2307}
PetscErrorCode InitializeSolutionConvergenceState(SimCtx *simCtx)
Implementation of InitializeSolutionConvergenceState().
Definition setup.c:96
PetscErrorCode PicurvWindowStorageCreate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage)
Allocates the accumulator state one window owns on one block.
PicurvWindowDefinition definition
PetscBool FieldStatisticsIsActive(const struct SimCtx *simCtx)
Reports whether this run has live field-statistics state.
@ DYNAMIC_SMAGORINSKY
Definition variables.h:551
Vec lFriction_Velocity
Definition variables.h:1106
Vec lDiffusivityGradient
Definition variables.h:1117
Vec Qcrit_nodal
Q-criterion averaged to grid nodes; the field a .vts can place correctly.
Definition variables.h:1179
Vec lPostScalar
Definition variables.h:1133
Vec lCent
Definition variables.h:1148
Vec GridSpace
Definition variables.h:1148
Vec P_nodal
Definition variables.h:1176
UserCtx * user
Definition variables.h:729
Vec lNu_Wall
Definition variables.h:1110
Vec lIEta
Definition variables.h:1151
Vec lIZet
Definition variables.h:1151
Vec lNvert
Definition variables.h:1113
Vec Centz
Definition variables.h:1149
UserMG usermg
Definition variables.h:1015
Vec lUcont_rm1
Definition variables.h:1121
Vec Nu_Wall
Definition variables.h:1110
Vec lKEta
Definition variables.h:1153
Vec Ucat_nodal
Definition variables.h:1177
Vec PostScalarNodal
Definition variables.h:1133
Vec DiffusivityGradient
Definition variables.h:1117
Vec lJCsi
Definition variables.h:1152
Vec Ucont
Definition variables.h:1113
Vec PostScalar
Definition variables.h:1133
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
Definition variables.h:149
Vec Qcrit
Definition variables.h:1178
Vec CellScalarAtCorner
Definition variables.h:1126
Vec Centx
Definition variables.h:1149
Vec lParticleCount
Definition variables.h:1171
Vec lUcont_o
Definition variables.h:1120
Vec CellVectorAtCorner
Definition variables.h:1127
Vec Ucat_o
Definition variables.h:1120
Vec lKZet
Definition variables.h:1153
Vec lNu_t
Definition variables.h:1156
Vec lCellScalarAtCorner
Definition variables.h:1126
Vec lJEta
Definition variables.h:1152
Vec lGridSpace
Definition variables.h:1148
Vec lKCsi
Definition variables.h:1153
Vec ParticleCount
Definition variables.h:1171
Vec Ucont_o
Definition variables.h:1120
Vec lCenty
Definition variables.h:1150
Vec PostVectorNodal
Definition variables.h:1134
PetscInt mglevels
Definition variables.h:736
Vec Friction_Velocity
Definition variables.h:1106
Vec lJZet
Definition variables.h:1152
Vec Nvert_o
Definition variables.h:1120
Vec lCellVectorAtCorner
Definition variables.h:1127
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:1136
Vec Psi_nodal
Definition variables.h:1180
Vec lPostVector
Definition variables.h:1134
Vec lCentx
Definition variables.h:1150
Vec Ucont_rm1
Definition variables.h:1121
Vec lUcont
Definition variables.h:1113
Vec Diffusivity
Definition variables.h:1116
Vec lICsi
Definition variables.h:1151
Vec lUcat
Definition variables.h:1113
Vec PostVector
Definition variables.h:1134
Vec lQcrit
Cell-centred Q-criterion and its ghosted copy for nodal averaging.
Definition variables.h:1178
Vec Nvert
Definition variables.h:1113
MGCtx * mgctx
Definition variables.h:739
Vec lDiffusivity
Definition variables.h:1116
Vec lNvert_o
Definition variables.h:1120
Vec Centy
Definition variables.h:1149
Vec lCentz
Definition variables.h:1150
Vec Uch
Characteristic velocity for boundary conditions.
Definition variables.h:150
Context for Multigrid operations.
Definition variables.h:728
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074
User-level context for managing the entire multigrid hierarchy.
Definition variables.h:735
Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdateLocalGhosts()

PetscErrorCode UpdateLocalGhosts ( UserCtx *  user,
FieldId  field_id 
)

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

This function resolves the correct global vector, local vector, and DM from the authoritative field catalog 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.
field_idTyped identity of the catalogued field to update.
Returns
PetscErrorCode 0 on success, non-zero on failure.
Note
This function assumes the global vector associated with field_id 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.

Resolves the typed field view, performs the existing PETSc scatter, and applies the established periodic normal-face repair when needed.

Definition at line 2489 of file setup.c.

2490{
2491 PetscErrorCode ierr;
2492 PetscMPIInt rank;
2493 FieldView field_view;
2494 const char *field_name;
2495 Vec globalVec;
2496 Vec localVec;
2497 DM dm;
2498 PetscInt dof;
2499 char face_direction = '\0';
2500 PetscBool component_staggered = PETSC_FALSE;
2501
2502 PetscFunctionBeginUser; // Use User version for application code
2504 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2505 ierr = FieldGetView(user, field_id, &field_view); CHKERRQ(ierr);
2506 PetscCheck((field_view.descriptor->capabilities & FIELD_CAPABILITY_GHOST_UPDATE) != 0u,
2507 PETSC_COMM_SELF, PETSC_ERR_SUP,
2508 "Field '%s' does not support ghost updates.",
2509 field_view.descriptor->canonical_name);
2510 field_name = field_view.descriptor->canonical_name;
2511 globalVec = field_view.global_vec;
2512 localVec = field_view.local_vec;
2513 dm = field_view.dm;
2514 dof = field_view.descriptor->dof;
2515
2516 switch (field_view.descriptor->sync_class) {
2517 case FIELD_SYNC_I_FACE:
2518 face_direction = 'i';
2519 break;
2520 case FIELD_SYNC_J_FACE:
2521 face_direction = 'j';
2522 break;
2523 case FIELD_SYNC_K_FACE:
2524 face_direction = 'k';
2525 break;
2527 component_staggered = PETSC_TRUE;
2528 break;
2530 break;
2531 default:
2532 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB,
2533 "Field '%s' has an invalid ghost synchronization class.", field_name);
2534 }
2535
2536 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Starting ghost update for field '%s'.\n", rank, field_name);
2537
2538 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Identified components for '%s': DM=%p, GlobalVec=%p, LocalVec=%p.\n",
2539 rank, field_name, (void*)dm, (void*)globalVec, (void*)localVec);
2540
2541 // --- 3. Optional Debugging: Norm Before Update ---
2542 // Use your logging convention check
2543 // if (get_log_level() >= LOG_LEVEL_DEBUG && is_function_allowed("UpdateLocalGhosts")) { // Example check
2544 if(get_log_level() == LOG_DEBUG && is_function_allowed(__func__)){
2545 PetscReal norm_global_before;
2546 ierr = VecNorm(globalVec, NORM_INFINITY, &norm_global_before); CHKERRQ(ierr);
2547 LOG_ALLOW(GLOBAL, LOG_INFO,"Max norm '%s' (Global) BEFORE Ghost Update: %g\n", field_name, norm_global_before);
2548 // Optional: Norm of local vector before update (might contain old ghost values)
2549 // PetscReal norm_local_before;
2550 // ierr = VecNorm(localVec, NORM_INFINITY, &norm_local_before); CHKERRQ(ierr);
2551 // LOG_ALLOW(GLOBAL, LOG_DEBUG,"Max norm '%s' (Local) BEFORE Ghost Update: %g\n", field_name, norm_local_before);
2552 }
2553
2554 // --- 4. Perform the Global-to-Local Transfer (Ghost Update) ---
2555 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Calling DMGlobalToLocalBegin/End for '%s'.\n", rank, field_name);
2556 ierr = DMGlobalToLocalBegin(dm, globalVec, INSERT_VALUES, localVec); CHKERRQ(ierr);
2557 ierr = DMGlobalToLocalEnd(dm, globalVec, INSERT_VALUES, localVec); CHKERRQ(ierr);
2558 ierr = RepairPeriodicNormalFaceGhosts(user, dm, localVec, dof, face_direction,
2559 component_staggered); CHKERRQ(ierr);
2560 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Completed DMGlobalToLocalBegin/End for '%s'.\n", rank, field_name);
2561
2562 // --- 5. Optional Debugging: Norm After Update ---
2563 // Use your logging convention check
2564 // if (get_log_level() >= LOG_LEVEL_DEBUG && is_function_allowed("UpdateLocalGhosts")) { // Example check
2565 if(get_log_level() == LOG_DEBUG && is_function_allowed(__func__)){ // Using your specific check
2566 PetscReal norm_local_after;
2567 ierr = VecNorm(localVec, NORM_INFINITY, &norm_local_after); CHKERRQ(ierr);
2568 LOG_ALLOW(GLOBAL, LOG_INFO,"Max norm '%s' (Local) AFTER Ghost Update: %g\n", field_name, norm_local_after);
2569
2570 // --- 6. Optional Debugging: Specific Point Checks (Example for Ucat on Rank 0/1) ---
2571 // (Keep this conditional if it's only for specific debug scenarios)
2572 if (field_id == FIELD_ID_UCAT) { // Only do detailed checks for Ucat for now
2573 PetscMPIInt rank_test;
2574 MPI_Comm_rank(PETSC_COMM_WORLD, &rank_test);
2575
2576 // Get Local Info needed for indexing checks
2577 DMDALocalInfo info_check;
2578 ierr = DMDAGetLocalInfo(dm, &info_check); CHKERRQ(ierr); // Use the correct dm
2579
2580 // Buffer for array pointer
2581 Cmpnts ***lUcat_arr_test = NULL;
2582 PetscErrorCode ierr_test = 0;
2583
2584 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Testing '%s' access immediately after ghost update...\n", rank_test, field_name);
2585 ierr_test = DMDAVecGetArrayDOFRead(dm, localVec, &lUcat_arr_test); // Use correct dm and localVec
2586
2587 if (ierr_test) {
2588 LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR %d getting '%s' array after ghost update!\n", rank_test, ierr_test, field_name);
2589 } else if (!lUcat_arr_test) {
2590 LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR NULL pointer getting '%s' array after ghost update!\n", rank_test, field_name);
2591 }
2592 else {
2593 // Check owned interior point (e.g., first interior point)
2594 PetscInt k_int = info_check.zs + (info_check.zm > 1 ? 1 : 0); // Global k index (at least zs+1 if possible)
2595 PetscInt j_int = info_check.ys + (info_check.ym > 1 ? 1 : 0); // Global j index
2596 PetscInt i_int = info_check.xs + (info_check.xm > 1 ? 1 : 0); // Global i index
2597 // Ensure indices are within global bounds if domain is very small
2598 //if (k_int >= info_check.mz-1) k_int = info_check.mz-2; if (k_int < 1) k_int = 1;
2599 //if (j_int >= info_check.my-1) j_int = info_check.my-2; if (j_int < 1) j_int = 1;
2600 // if (i_int >= info_check.mx-1) i_int = info_check.mx-2; if (i_int < 1) i_int = 1;
2601 // clamp k_int to [1 .. mz-2]
2602 if (k_int >= info_check.mz - 1) {
2603 k_int = info_check.mz - 2;
2604 }
2605 if (k_int < 1) {
2606 k_int = 1;
2607 }
2608
2609 // clamp j_int to [1 .. my-2]
2610 if (j_int >= info_check.my - 1) {
2611 j_int = info_check.my - 2;
2612 }
2613 if (j_int < 1) {
2614 j_int = 1;
2615 }
2616
2617 // clamp i_int to [1 .. mx-2]
2618 if (i_int >= info_check.mx - 1) {
2619 i_int = info_check.mx - 2;
2620 }
2621 if (i_int < 1) {
2622 i_int = 1;
2623 }
2624
2625 // Only attempt read if indices are actually owned (relevant for multi-rank)
2626 if (k_int >= info_check.zs && k_int < info_check.zs + info_check.zm &&
2627 j_int >= info_check.ys && j_int < info_check.ys + info_check.ym &&
2628 i_int >= info_check.xs && i_int < info_check.xs + info_check.xm)
2629 {
2630 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);
2631 Cmpnts test_val_owned_interior = lUcat_arr_test[k_int][j_int][i_int];
2632 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading owned interior: x=%g\n", rank_test, test_val_owned_interior.x);
2633 } else {
2634 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);
2635 }
2636
2637
2638 // Check owned boundary point (e.g., first owned point)
2639 PetscInt k_bnd = info_check.zs; // Global k index
2640 PetscInt j_bnd = info_check.ys; // Global j index
2641 PetscInt i_bnd = info_check.xs; // Global i index
2642 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);
2643 Cmpnts test_val_owned_boundary = lUcat_arr_test[k_bnd][j_bnd][i_bnd];
2644 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading owned boundary: x=%g\n", rank_test, test_val_owned_boundary.x);
2645
2646
2647 // Check ghost point (e.g., one layer below in k, if applicable)
2648 if (info_check.zs > 0) { // Only if there's a rank below
2649 PetscInt k_ghost = info_check.zs - 1;
2650 PetscInt j_ghost = info_check.ys; // Use start of owned y, simple example
2651 PetscInt i_ghost = info_check.xs; // Use start of owned x, simple example
2652 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Attempting test read GHOST [%d][%d][%d] (Global)\n", rank_test, k_ghost, j_ghost, i_ghost);
2653 Cmpnts test_val_ghost = lUcat_arr_test[k_ghost][j_ghost][i_ghost];
2654 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading ghost: x=%g\n", rank_test, test_val_ghost.x);
2655 } else {
2656 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Skipping ghost test read (zs=0).\n", rank_test);
2657 }
2658
2659 // Restore the array
2660 ierr_test = DMDAVecRestoreArrayDOFRead(dm, localVec, &lUcat_arr_test);
2661 if(ierr_test){ LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR %d restoring '%s' array after test read!\n", rank_test, ierr_test, field_name); }
2662 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Finished testing '%s' access.\n", rank_test, field_name);
2663 }
2664 } // end if Ucat
2665 } // end debug logging check
2666
2667 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Completed ghost update for field '%s'.\n", rank, field_name);
2669 PetscFunctionReturn(0);
2670}
@ FIELD_CAPABILITY_GHOST_UPDATE
@ FIELD_SYNC_STANDARD
@ FIELD_SYNC_K_FACE
@ FIELD_SYNC_J_FACE
@ FIELD_SYNC_COMPONENT_STAGGERED
@ FIELD_SYNC_I_FACE
unsigned int capabilities
const FieldDescriptor * descriptor
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Resolve the existing DM and global/local vectors for one field.
const char * canonical_name
FieldSyncClass sync_class
@ FIELD_ID_UCAT
Non-owning runtime objects resolved for one field and UserCtx.
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:186
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:87
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:2319
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 2678 of file setup.c.

2679{
2680 PetscErrorCode ierr;
2681 PetscFunctionBeginUser;
2682
2684
2685 LOG_ALLOW(GLOBAL,LOG_INFO, "--- Setting up Boundary Conditions ---\n");
2686 // --- Phase 1: Parse and initialize BC configuration for all blocks ---
2687 LOG_ALLOW(GLOBAL,LOG_INFO,"Parsing BC configuration files and initializing boundary condition data structures.\n");
2688 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels-1].user;
2689 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
2690 LOG_ALLOW(GLOBAL,LOG_DEBUG, " -> Processing Block %d:\n", bi);
2691
2692 // --- Generate the filename for the current block ---
2693 const char *current_bc_filename = simCtx->bcs_files[bi];
2694 LOG_ALLOW(GLOBAL,LOG_DEBUG," -> Processing Block %d using config file '%s'\n", bi, current_bc_filename);
2695 // This will populate user_finest[bi].boundary_faces
2696
2697 //ierr = ParseAllBoundaryConditions(&user_finest[bi],current_bc_filename); CHKERRQ(ierr);
2698
2699 ierr = BoundarySystem_Initialize(&user_finest[bi], current_bc_filename); CHKERRQ(ierr);
2700 }
2701
2702 // Propogate BC Configuration to coarser levels.
2703 ierr = PropagateBoundaryConfigToCoarserLevels(simCtx); CHKERRQ(ierr);
2704
2705 // Validate the geometric contract before any metric consumes periodic geometry.
2706 for (PetscInt level = simCtx->usermg.mglevels - 1; level >= 0; level--) {
2707 UserCtx *level_users = simCtx->usermg.mgctx[level].user;
2708 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
2709 ierr = ValidatePeriodicGeometry(&level_users[bi]); CHKERRQ(ierr);
2710 }
2711 }
2712
2713 // --- Calculate Grid Metrics (requires BC configuration) ---
2714 // NOTE: This MUST be called here (after BC initialization but before inlet/outlet calculations) because:
2715 // 1. Periodic BC corrections in metric calculations need boundary_faces data to be populated
2716 // 2. Inlet/Outlet area calculations (below) require computed metrics (Csi, Eta, Zet) to be available
2717 // Previously this was in SetupGridAndSolvers, but that caused metrics to be computed without BC info.
2718 LOG_ALLOW(GLOBAL,LOG_INFO,"Computing grid metrics with boundary condition information.\n");
2719 ierr = CalculateAllGridMetrics(simCtx); CHKERRQ(ierr);
2720
2721 // --- Phase 2: Calculate inlet/outlet properties (requires computed metrics) ---
2722 LOG_ALLOW(GLOBAL,LOG_INFO,"Calculating inlet and outlet face properties.\n");
2723 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
2724 // Call the function to calculate the center of the inlet face & the inlet area, which may be used to calculate Boundary values.
2725 ierr = CalculateInletProperties(&user_finest[bi]); CHKERRQ(ierr);
2726
2727 // Call the function to calculate the center of the outlet face & the outlet area, which may be used to calculate Boundary values.
2728 ierr = CalculateOutletProperties(&user_finest[bi]); CHKERRQ(ierr);
2729 }
2730
2731 LOG_ALLOW(GLOBAL,LOG_INFO, "--- Boundary Conditions setup complete ---\n");
2732
2733
2735 PetscFunctionReturn(0);
2736}
PetscErrorCode BoundarySystem_Initialize(UserCtx *user, const char *bcs_filename)
Initializes the entire boundary system.
Definition Boundaries.c:876
PetscErrorCode PropagateBoundaryConfigToCoarserLevels(SimCtx *simCtx)
Propagates boundary condition configuration from finest to all coarser multigrid levels.
Definition Boundaries.c:973
PetscErrorCode CalculateAllGridMetrics(SimCtx *simCtx)
Orchestrates the calculation of all grid metrics.
Definition Metric.c:1993
PetscErrorCode CalculateOutletProperties(UserCtx *user)
Calculates the center and area of the primary OUTLET face.
Definition grid.c:1164
PetscErrorCode ValidatePeriodicGeometry(UserCtx *user)
Validates that configured geometric periodic seams match by translation.
Definition grid.c:421
PetscErrorCode CalculateInletProperties(UserCtx *user)
Calculates the center and area of the primary INLET face.
Definition grid.c:1111
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 96 of file setup.c.

97{
98 UserCtx *user = NULL;
99 PetscInt history_capacity = 0;
100
101 PetscFunctionBeginUser;
102 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL.");
103 if (simCtx->exec_mode != EXEC_MODE_SOLVER) PetscFunctionReturn(0);
104 if (!simCtx->solutionConvergenceEnabled) PetscFunctionReturn(0);
105 if (!simCtx->usermg.mgctx) {
106 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
107 "Multigrid hierarchy must exist before initializing solution convergence storage.");
108 }
109
110 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
111 if (!user) {
112 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
113 "Finest-level UserCtx must exist before initializing solution convergence storage.");
114 }
115
117
119 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
120 PetscCall(PetscCalloc1((size_t)simCtx->solutionConvergencePeriodSteps,
121 &user[bi].solutionConvergencePeriodicUcatRef));
122 PetscCall(PetscCalloc1((size_t)simCtx->solutionConvergencePeriodSteps,
123 &user[bi].solutionConvergencePeriodicPRef));
124 for (PetscInt phase = 0; phase < simCtx->solutionConvergencePeriodSteps; ++phase) {
125 PetscCall(VecDuplicate(user[bi].Ucat, &user[bi].solutionConvergencePeriodicUcatRef[phase]));
126 PetscCall(VecSet(user[bi].solutionConvergencePeriodicUcatRef[phase], 0.0));
127 PetscCall(VecDuplicate(user[bi].P, &user[bi].solutionConvergencePeriodicPRef[phase]));
128 PetscCall(VecSet(user[bi].solutionConvergencePeriodicPRef[phase], 0.0));
129 }
130 }
131 }
132
134 history_capacity = 2 * simCtx->solutionConvergenceWindowSteps;
135 PetscCall(PetscCalloc1((size_t)history_capacity, &simCtx->solutionConvergenceMeanSpeedHistory));
136 PetscCall(PetscCalloc1((size_t)history_capacity, &simCtx->solutionConvergenceMeanKEHistory));
137 }
138
139 PetscFunctionReturn(0);
140}
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 148 of file setup.c.

149{
150 UserCtx *user = NULL;
151
152 PetscFunctionBeginUser;
153 if (!simCtx) PetscFunctionReturn(0);
154 if (simCtx->fieldStatisticsWindows) {
155 PetscCall(PetscFree(simCtx->fieldStatisticsWindows));
156 simCtx->fieldStatisticsWindows = NULL;
157 simCtx->fieldStatisticsWindowCount = 0;
158 }
159 if (!simCtx->usermg.mgctx) PetscFunctionReturn(0);
160
161 user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
162 if (user) {
163 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
164 if (user[bi].solutionConvergencePeriodicUcatRef) {
165 for (PetscInt phase = 0; phase < simCtx->solutionConvergencePeriodSteps; ++phase) {
166 if (user[bi].solutionConvergencePeriodicUcatRef[phase]) {
167 PetscCall(VecDestroy(&user[bi].solutionConvergencePeriodicUcatRef[phase]));
168 }
169 }
170 PetscCall(PetscFree(user[bi].solutionConvergencePeriodicUcatRef));
172 }
173 if (user[bi].solutionConvergencePeriodicPRef) {
174 for (PetscInt phase = 0; phase < simCtx->solutionConvergencePeriodSteps; ++phase) {
175 if (user[bi].solutionConvergencePeriodicPRef[phase]) {
176 PetscCall(VecDestroy(&user[bi].solutionConvergencePeriodicPRef[phase]));
177 }
178 }
179 PetscCall(PetscFree(user[bi].solutionConvergencePeriodicPRef));
180 user[bi].solutionConvergencePeriodicPRef = NULL;
181 }
182 }
183 }
184
186 PetscCall(PetscFree(simCtx->solutionConvergenceMeanSpeedHistory));
188 }
190 PetscCall(PetscFree(simCtx->solutionConvergenceMeanKEHistory));
192 }
194
195 PetscFunctionReturn(0);
196}
Vec * solutionConvergencePeriodicPRef
Definition variables.h:1123
Vec * solutionConvergencePeriodicUcatRef
Definition variables.h:1122
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 2742 of file setup.c.

2743{
2744 PetscErrorCode ierr;
2745 PetscReal ***data;
2746 PetscReal *dataContiguous;
2747 PetscInt k, j;
2748
2749 PetscFunctionBegin;
2750 /* Step 1: Allocate memory for an array of nz layer pointers (zero-initialized) */
2751 ierr = PetscCalloc1(nz, &data); CHKERRQ(ierr);
2752
2753 /* Step 2: Allocate memory for all row pointers (nz * ny pointers) */
2754 ierr = PetscCalloc1(nz * ny, &data[0]); CHKERRQ(ierr);
2755 for (k = 1; k < nz; k++) {
2756 data[k] = data[0] + k * ny;
2757 }
2758
2759 /* Step 3: Allocate one contiguous block for all data elements (nz*ny*nx) */
2760 ierr = PetscCalloc1(nz * ny * nx, &dataContiguous); CHKERRQ(ierr);
2761
2762 /* Build the 3D pointer structure: each row pointer gets the correct segment of data */
2763 for (k = 0; k < nz; k++) {
2764 for (j = 0; j < ny; j++) {
2765 data[k][j] = dataContiguous + (k * ny + j) * nx;
2766 /* Memory is already zeroed by PetscCalloc1, so no manual initialization is needed */
2767 }
2768 }
2769 *array = data;
2770 PetscFunctionReturn(0);
2771}

◆ 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 2777 of file setup.c.

2778{
2779 PetscErrorCode ierr;
2780 (void)nz;
2781 (void)ny;
2782
2783 PetscFunctionBegin;
2784 if (!array || !array[0] || !array[0][0] ) { // Added more robust check
2785 LOG_ALLOW(GLOBAL, LOG_WARNING, "Deallocate3DArrayScalar called with potentially unallocated or NULL array.\n");
2786 if (array) {
2787 if (array[0]) { // Check if row pointers might exist
2788 // Cannot safely access array[0][0] if array[0] might be invalid/freed
2789 // Standard deallocation below assumes valid pointers.
2790 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free row pointers if they exist
2791 }
2792 ierr = PetscFree(array); CHKERRQ(ierr); // Free layer pointers if they exist
2793 }
2794 PetscFunctionReturn(0);
2795 }
2796
2797 // --- Standard Deallocation (assuming valid allocation) ---
2798
2799 /* 1. Free the contiguous block of PetscReal values.
2800 The starting address was stored in array[0][0]. */
2801 ierr = PetscFree(array[0][0]); CHKERRQ(ierr); // Free the ACTUAL DATA
2802
2803 /* 2. Free the contiguous block of row pointers.
2804 The starting address was stored in array[0]. */
2805 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free the ROW POINTERS
2806
2807 /* 3. Free the layer pointer array.
2808 The starting address is 'array' itself. */
2809 ierr = PetscFree(array); CHKERRQ(ierr); // Free the LAYER POINTERS
2810
2811 PetscFunctionReturn(0);
2812}

◆ 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 2820 of file setup.c.

2821{
2822 PetscErrorCode ierr;
2823 Cmpnts ***data;
2824 Cmpnts *dataContiguous;
2825 PetscInt k, j;
2826 PetscMPIInt rank;
2827
2828 PetscFunctionBegin;
2829
2830 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
2831
2832 /* Step 1: Allocate memory for nz layer pointers (zeroed) */
2833 ierr = PetscCalloc1(nz, &data); CHKERRQ(ierr);
2834
2835 LOG_ALLOW(LOCAL,LOG_DEBUG," [Rank %d] memory allocated for outermost layer (%d k-layer pointers).\n",rank,nz);
2836
2837 /* Step 2: Allocate memory for all row pointers (nz * ny pointers) */
2838 ierr = PetscCalloc1(nz * ny, &data[0]); CHKERRQ(ierr);
2839 for (k = 1; k < nz; k++) {
2840 data[k] = data[0] + k * ny;
2841 }
2842
2843 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d] memory allocated for %dx%d row pointers.\n",rank,nz,ny);
2844
2845 /* Step 3: Allocate one contiguous block for nz*ny*nx Cmpnts structures (zeroed) */
2846 ierr = PetscCalloc1(nz * ny * nx, &dataContiguous); CHKERRQ(ierr);
2847
2848 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[Rank %d] memory allocated for contigous block of %dx%dx%d Cmpnts structures).\n",rank,nz,ny,nx);
2849
2850 /* Build the 3D pointer structure for vector data */
2851 for (k = 0; k < nz; k++) {
2852 for (j = 0; j < ny; j++) {
2853 data[k][j] = dataContiguous + (k * ny + j) * nx;
2854 /* The PetscCalloc1 call has already initialized each Cmpnts to zero. */
2855 }
2856 }
2857
2858 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[Rank %d] 3D pointer structure for vector data created. \n",rank);
2859
2860 *array = data;
2861 PetscFunctionReturn(0);
2862}

◆ 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 2870 of file setup.c.

2871{
2872 PetscErrorCode ierr;
2873 (void)nz;
2874 (void)ny;
2875
2876 PetscFunctionBegin;
2877 // If array is NULL or hasn't been allocated properly, just return.
2878 if (!array || !array[0] || !array[0][0] ) {
2879 LOG_ALLOW(GLOBAL, LOG_WARNING, "Deallocate3DArrayVector called with potentially unallocated or NULL array.\n");
2880 // Attempt to free what might exist, but be cautious
2881 if (array) {
2882 if (array[0]) { // Check if row pointers were allocated
2883 // We don't have a direct pointer to the contiguous data block
2884 // saved separately in this allocation scheme. The allocation relies
2885 // on array[0][0] pointing to it. If array[0] was freed first,
2886 // accessing array[0][0] is unsafe.
2887 // The allocation scheme where the contiguous data block is not
2888 // stored separately makes safe deallocation tricky if freeing
2889 // happens out of order or if parts are NULL.
2890
2891 // A SAFER ALLOCATION/DEALLOCATION would store the data pointer separately.
2892 // Given the current allocation scheme, the order MUST be:
2893 // 1. Free the data block (pointed to by array[0][0])
2894 // 2. Free the row pointer block (pointed to by array[0])
2895 // 3. Free the layer pointer block (pointed to by array)
2896
2897 // Let's assume the allocation was successful and pointers are valid.
2898 // Get pointer to the contiguous data block *before* freeing row pointers
2899 Cmpnts *dataContiguous = array[0][0];
2900 ierr = PetscFree(dataContiguous); CHKERRQ(ierr); // Free data block
2901
2902 // Now free the row pointers block
2903 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free row pointers
2904
2905 }
2906 // Finally, free the array of layer pointers
2907 ierr = PetscFree(array); CHKERRQ(ierr);
2908 }
2909 PetscFunctionReturn(0); // Return gracefully if input was NULL initially
2910 }
2911
2912
2913 // --- Standard Deallocation (assuming valid allocation) ---
2914
2915 /* 1. Free the contiguous block of Cmpnts structures.
2916 The starting address was stored in array[0][0] by Allocate3DArrayVector. */
2917 ierr = PetscFree(array[0][0]); CHKERRQ(ierr); // Free the ACTUAL DATA
2918
2919 /* 2. Free the contiguous block of row pointers.
2920 The starting address was stored in array[0]. */
2921 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free the ROW POINTERS
2922
2923 /* 3. Free the layer pointer array.
2924 The starting address is 'array' itself. */
2925 ierr = PetscFree(array); CHKERRQ(ierr); // Free the LAYER POINTERS
2926
2927 PetscFunctionReturn(0);
2928}

◆ 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 2936 of file setup.c.

2940{
2941 PetscErrorCode ierr = 0; // Standard PETSc error code, not explicitly set here but good practice.
2942 PetscInt xs_node_global_rank; // Global index of the first node owned by this rank in the specified dimension.
2943 PetscInt num_nodes_owned_rank; // Number of nodes owned by this rank in this dimension (local count, excluding ghosts).
2944 PetscInt GlobalNodesInDim_from_info; // Total number of DA points in this dimension, from DMDALocalInfo.
2945
2946 PetscFunctionBeginUser;
2947
2948 // --- 1. Input Validation ---
2949 if (!info_nodes || !xs_cell_global_out || !xm_cell_local_out) {
2950 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null pointer passed to GetOwnedCellRange.");
2951 }
2952
2953 // --- 2. Extract Node Ownership and Global Dimension Information from DMDALocalInfo ---
2954 if (dim == 0) { // I-direction
2955 xs_node_global_rank = info_nodes->xs;
2956 num_nodes_owned_rank = info_nodes->xm;
2957 GlobalNodesInDim_from_info = info_nodes->mx;
2958 } else if (dim == 1) { // J-direction
2959 xs_node_global_rank = info_nodes->ys;
2960 num_nodes_owned_rank = info_nodes->ym;
2961 GlobalNodesInDim_from_info = info_nodes->my;
2962 } else if (dim == 2) { // K-direction
2963 xs_node_global_rank = info_nodes->zs;
2964 num_nodes_owned_rank = info_nodes->zm;
2965 GlobalNodesInDim_from_info = info_nodes->mz;
2966 } else {
2967 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d in GetOwnedCellRange. Must be 0, 1, or 2.", dim);
2968 }
2969
2970 // --- 3. Correct for User-Defined Ghost Node ---
2971 // Per the function's contract (@warning), the DA size includes an extra, non-physical
2972 // node. We subtract 1 to get the true number of physical nodes for cell calculations.
2973 const PetscInt physical_nodes_in_dim = GlobalNodesInDim_from_info - 1;
2974
2975 // --- 4. Handle Edge Cases for Physical Domain Size ---
2976 // If the physical domain has 0 or 1 node, no cells can be formed.
2977 if (physical_nodes_in_dim <= 1) {
2978 *xs_cell_global_out = xs_node_global_rank; // Still report the rank's starting node
2979 *xm_cell_local_out = 0; // But 0 cells
2980 PetscFunctionReturn(0);
2981 }
2982
2983 // --- 5. Determine Cell Ownership Based on Corrected Node Ownership ---
2984 // The first cell this rank *could* define has its origin at the first node this rank owns.
2985 *xs_cell_global_out = xs_node_global_rank;
2986
2987 // If the rank owns no nodes in this dimension, it can't form any cell origins.
2988 if (num_nodes_owned_rank == 0) {
2989 *xm_cell_local_out = 0;
2990 } else {
2991 // --- BUG FIX APPLIED HERE ---
2992 // The previous logic incorrectly assumed a cell's end node (N_{k+1}) must be on the
2993 // same rank as its origin node (N_k). The correct logic is to find the intersection
2994 // between the nodes this rank owns and the nodes that are valid origins globally.
2995
2996 // The first node owned by the rank is its first potential origin.
2997 PetscInt first_owned_origin = xs_node_global_rank;
2998
2999 // The absolute last node owned by this rank. Any node up to and including this one
3000 // is a potential cell origin from this rank's perspective.
3001 PetscInt last_node_owned_by_rank = xs_node_global_rank + num_nodes_owned_rank - 1;
3002
3003 // The absolute last node in the entire PHYSICAL domain that can serve as a cell origin.
3004 // If there are `N` physical nodes (0 to N-1), this index is `N-2`.
3005 PetscInt last_possible_origin_global_idx = physical_nodes_in_dim - 2;
3006
3007 // The actual last origin this rank can provide is the *minimum* of what it owns
3008 // and what is globally possible. This correctly handles both ranks in the middle of
3009 // the domain and the very last rank.
3010 PetscInt actual_last_origin_this_rank_can_form = PetscMin(last_node_owned_by_rank, last_possible_origin_global_idx);
3011
3012 // If the first potential origin this rank owns is already beyond the actual last
3013 // origin it can form, then this rank forms no valid cell origins. This happens if
3014 // the rank only owns the very last physical node.
3015 if (first_owned_origin > actual_last_origin_this_rank_can_form) {
3016 *xm_cell_local_out = 0;
3017 } else {
3018 // The number of cells is the count of valid origins this rank owns.
3019 // (Count = Last Index - First Index + 1)
3020 *xm_cell_local_out = actual_last_origin_this_rank_can_form - first_owned_origin + 1;
3021 }
3022 }
3023
3024 PetscFunctionReturn(ierr);
3025}
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 3033 of file setup.c.

3034{
3035 PetscErrorCode ierr;
3036 PetscMPIInt rank;
3037 PetscMPIInt size; // MPI communicator size
3038 const PetscMPIInt *neighbor_ranks_ptr; // Pointer to raw neighbor data from PETSc
3039
3040 PetscFunctionBeginUser;
3042 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3043 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr); // Get MPI size for validation
3044
3045 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Computing DMDA neighbor ranks.\n", rank);
3046
3047 if (!user || !user->da) {
3048 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx or user->da is NULL in ComputeAndStoreNeighborRanks.");
3049 }
3050
3051 // Get the neighbor information from the DMDA
3052 // neighbor_ranks_ptr will point to an internal PETSc array of 27 ranks.
3053 ierr = DMDAGetNeighbors(user->da, &neighbor_ranks_ptr); CHKERRQ(ierr);
3054
3055 // Log the raw values from DMDAGetNeighbors for boundary-relevant directions for debugging
3056 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",
3057 rank,
3058 neighbor_ranks_ptr[12], neighbor_ranks_ptr[14],
3059 neighbor_ranks_ptr[10], neighbor_ranks_ptr[16],
3060 neighbor_ranks_ptr[4], neighbor_ranks_ptr[22],
3061 (int)MPI_PROC_NULL);
3062
3063 // PETSc standard indices for 3D face neighbors from the 27-point stencil:
3064 // Index = k_offset*9 + j_offset*3 + i_offset (where offsets -1,0,1 map to 0,1,2)
3065 // Center: (i_off=1, j_off=1, k_off=1) => 1*9 + 1*3 + 1 = 13
3066 // X-min: (i_off=0, j_off=1, k_off=1) => 1*9 + 1*3 + 0 = 12
3067 // X-plus: (i_off=2, j_off=1, k_off=1) => 1*9 + 1*3 + 2 = 14
3068 // Y-min: (i_off=1, j_off=0, k_off=1) => 1*9 + 0*3 + 1 = 10
3069 // Y-plus: (i_off=1, j_off=2, k_off=1) => 1*9 + 2*3 + 1 = 16
3070 // Z-min: (i_off=1, j_off=1, k_off=0) => 0*9 + 1*3 + 1 = 4
3071 // Z-plus: (i_off=1, j_off=1, k_off=2) => 2*9 + 1*3 + 1 = 22
3072
3073 if (neighbor_ranks_ptr[13] != rank) {
3074 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",
3075 rank, neighbor_ranks_ptr[13], rank);
3076 // This warning is important. If the center isn't the current rank, the offsets are likely wrong.
3077 // However, PETSc should ensure this unless the DM is too small for a 3x3x3 stencil.
3078 }
3079
3080 // Assign and sanitize each neighbor rank
3081 PetscMPIInt temp_neighbor;
3082
3083 temp_neighbor = neighbor_ranks_ptr[12]; // xm
3084 if (temp_neighbor < 0 || temp_neighbor >= size) {
3085 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);
3086 user->neighbors.rank_xm = MPI_PROC_NULL;
3087 } else {
3088 user->neighbors.rank_xm = temp_neighbor;
3089 }
3090
3091 temp_neighbor = neighbor_ranks_ptr[14]; // xp
3092 if (temp_neighbor < 0 || temp_neighbor >= size) {
3093 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);
3094 user->neighbors.rank_xp = MPI_PROC_NULL;
3095 } else {
3096 user->neighbors.rank_xp = temp_neighbor;
3097 }
3098
3099 temp_neighbor = neighbor_ranks_ptr[10]; // ym
3100 if (temp_neighbor < 0 || temp_neighbor >= size) {
3101 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);
3102 user->neighbors.rank_ym = MPI_PROC_NULL;
3103 } else {
3104 user->neighbors.rank_ym = temp_neighbor;
3105 }
3106
3107 temp_neighbor = neighbor_ranks_ptr[16]; // yp
3108 if (temp_neighbor < 0 || temp_neighbor >= size) {
3109 // The log for index 16 was "zm" in your output, should be yp
3110 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);
3111 user->neighbors.rank_yp = MPI_PROC_NULL;
3112 } else {
3113 user->neighbors.rank_yp = temp_neighbor;
3114 }
3115
3116 temp_neighbor = neighbor_ranks_ptr[4]; // zm
3117 if (temp_neighbor < 0 || temp_neighbor >= size) {
3118 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);
3119 user->neighbors.rank_zm = MPI_PROC_NULL;
3120 } else {
3121 user->neighbors.rank_zm = temp_neighbor;
3122 }
3123
3124 temp_neighbor = neighbor_ranks_ptr[22]; // zp
3125 if (temp_neighbor < 0 || temp_neighbor >= size) {
3126 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);
3127 user->neighbors.rank_zp = MPI_PROC_NULL;
3128 } else {
3129 user->neighbors.rank_zp = temp_neighbor;
3130 }
3131
3132 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,
3133 user->neighbors.rank_xm, user->neighbors.rank_xp,
3134 user->neighbors.rank_ym, user->neighbors.rank_yp,
3135 user->neighbors.rank_zm, user->neighbors.rank_zp);
3136 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); // Ensure logs are flushed
3137
3138 // Note: neighbor_ranks_ptr memory is managed by PETSc, do not free it.
3140 PetscFunctionReturn(0);
3141}
PetscMPIInt rank_zm
Definition variables.h:225
PetscMPIInt rank_yp
Definition variables.h:224
PetscMPIInt rank_ym
Definition variables.h:224
PetscMPIInt rank_xp
Definition variables.h:223
RankNeighbors neighbors
Definition variables.h:1091
PetscMPIInt rank_xm
Definition variables.h:223
PetscMPIInt rank_zp
Definition variables.h:225
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 3149 of file setup.c.

3150{
3151 PetscErrorCode ierr;
3152 PetscMPIInt size, rank;
3153 PetscInt px = PETSC_DECIDE, py = PETSC_DECIDE, pz = PETSC_DECIDE;
3154 PetscBool px_set = PETSC_FALSE, py_set = PETSC_FALSE, pz_set = PETSC_FALSE;
3155 SimCtx *simCtx = user->simCtx;
3156
3157 // Set no.of processors in direction 1
3158 if(simCtx->da_procs_x) {
3159 px_set = PETSC_TRUE;
3160 px = simCtx->da_procs_x;
3161 }
3162 // Set no.of processors in direction 2
3163 if(simCtx->da_procs_y) {
3164 py_set = PETSC_TRUE;
3165 py = simCtx->da_procs_y;
3166 }
3167 // Set no.of processors in direction 1
3168 if(simCtx->da_procs_z) {
3169 pz_set = PETSC_TRUE;
3170 pz = simCtx->da_procs_z;
3171 }
3172
3173 PetscFunctionBeginUser;
3175 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size); CHKERRQ(ierr);
3176 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank); CHKERRQ(ierr);
3177 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Configuring DMDA processor layout for %d total processes.\n", rank, size);
3178
3179 // --- Validate User Input (Optional but Recommended) ---
3180 // Check if specified processor counts multiply to the total MPI size
3181 if (px_set && py_set && pz_set) {
3182 if (px * py * pz != size) {
3183 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP,
3184 "Specified processor layout %d x %d x %d = %d does not match MPI size %d",
3185 px, py, pz, px * py * pz, size);
3186 }
3187 LOG_ALLOW(GLOBAL, LOG_INFO, "Using specified processor layout: %d x %d x %d\n", px, py, pz);
3188 } else if (px_set || py_set || pz_set) {
3189 // If only some are set, PETSC_DECIDE will be used for others
3190 LOG_ALLOW(GLOBAL, LOG_INFO, "Using partially specified processor layout: %d x %d x %d (PETSC_DECIDE for unspecified)\n", px, py, pz);
3191 } else {
3192 LOG_ALLOW(GLOBAL, LOG_INFO, "Using fully automatic processor layout (PETSC_DECIDE x PETSC_DECIDE x PETSC_DECIDE)\n");
3193 }
3194 // Additional checks: Ensure px, py, pz are positive if set
3195 if ((px_set && px <= 0) || (py_set && py <= 0) || (pz_set && pz <= 0)) {
3196 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Specified processor counts must be positive.");
3197 }
3198
3199
3200 // --- Apply the layout to the DMDA ---
3201 ierr = DMDASetNumProcs(dm, px, py, pz); CHKERRQ(ierr);
3202 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Rank %d: DMDASetNumProcs called with px=%d, py=%d, pz=%d.\n", rank, px, py, pz);
3203
3204 // --- Store the values in UserCtx (Optional) ---
3205 // Note: If PETSC_DECIDE was used, PETSc calculates the actual values during DMSetUp.
3206 // We store the *requested* values here. To get the *actual* values used,
3207 // you would need to call DMDAGetInfo after DMSetUp.
3208 /*
3209 if (user) {
3210 user->procs_x = px;
3211 user->procs_y = py;
3212 user->procs_z = pz;
3213 }
3214 */
3216 PetscFunctionReturn(0);
3217}
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:1077

◆ 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 3227 of file setup.c.

3228{
3229 PetscErrorCode ierr;
3230 PetscInt nblk = simCtx->block_number;
3231 PetscInt size = simCtx->size;
3232 BoundingBox *final_bboxlist = NULL;
3233
3234 PetscFunctionBeginUser;
3236
3237 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting full rank communication setup for %d block(s).\n", nblk);
3238
3239 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
3240
3241 // --- Step 1: Compute neighbor ranks (unchanged) ---
3242 for (int bi = 0; bi < nblk; bi++) {
3243 ierr = ComputeAndStoreNeighborRanks(&user_finest[bi]); CHKERRQ(ierr);
3244 }
3245 LOG_ALLOW(GLOBAL, LOG_INFO, "Neighbor ranks computed and stored for all blocks.\n");
3246
3247 // --- Step 2: Allocate the final, unified list on ALL ranks ---
3248 // Every rank will build this list in parallel.
3249 ierr = PetscMalloc1(size * nblk, &final_bboxlist); CHKERRQ(ierr);
3250
3251 // --- Step 3: Loop through each block, gather then broadcast its bbox list ---
3252 for (int bi = 0; bi < nblk; bi++) {
3253 // This is a temporary pointer for the current block's list.
3254 BoundingBox *block_bboxlist = NULL;
3255
3256 LOG_ALLOW(GLOBAL, LOG_INFO, "Processing bounding boxes for block %d...\n", bi);
3257
3258 // A) GATHER: On rank 0, block_bboxlist is allocated and filled. On others, it's NULL.
3259 ierr = GatherAllBoundingBoxes(&user_finest[bi], &block_bboxlist); CHKERRQ(ierr);
3260 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Gather complete for block %d.\n", bi);
3261
3262 // B) BROADCAST: On non-root ranks, block_bboxlist is allocated. Then, the data
3263 // from rank 0 is broadcast to all ranks. After this call, ALL ranks have
3264 // an identical, complete copy of the bounding boxes for the current block.
3265 ierr = BroadcastAllBoundingBoxes(&user_finest[bi], &block_bboxlist); CHKERRQ(ierr);
3266 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Broadcast complete for block %d.\n", bi);
3267
3268 // C) ASSEMBLE: Every rank now copies the data for this block into the
3269 // correct segment of its final, unified list.
3270 for (int r = 0; r < size; r++) {
3271 // The layout is [r0b0, r1b0, ..., r(size-1)b0, r0b1, r1b1, ...]
3272 final_bboxlist[bi * size + r] = block_bboxlist[r];
3273 }
3274 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Assembly into final list complete for block %d.\n", bi);
3275
3276 // D) CLEANUP: Free the temporary list for this block on ALL ranks before the next iteration.
3277 // Your helper functions use malloc, so we must use free.
3278 free(block_bboxlist);
3279 }
3280
3281 // --- Step 4: Assign the final pointer and run the last setup step ---
3282 simCtx->bboxlist = final_bboxlist;
3283 LOG_ALLOW(GLOBAL, LOG_INFO, "Final unified bboxlist created on all ranks and stored in SimCtx.\n");
3284
3285 ierr = SetupDomainCellDecompositionMap(&user_finest[0]); CHKERRQ(ierr);
3286 LOG_ALLOW(GLOBAL, LOG_INFO, "Domain Cell Composition set and broadcasted.\n");
3287
3288 LOG_ALLOW(GLOBAL, LOG_INFO, "SetupDomainRankInfo: Completed successfully.\n");
3289
3291 PetscFunctionReturn(0);
3292}
PetscErrorCode BroadcastAllBoundingBoxes(UserCtx *user, BoundingBox **bboxlist)
Broadcasts the bounding box information collected on rank 0 to all other ranks.
Definition grid.c:1061
PetscErrorCode GatherAllBoundingBoxes(UserCtx *user, BoundingBox **allBBoxes)
Gathers local bounding boxes from all MPI processes to rank 0.
Definition grid.c:999
PetscErrorCode ComputeAndStoreNeighborRanks(UserCtx *user)
Internal helper implementation: ComputeAndStoreNeighborRanks().
Definition setup.c:3033
PetscErrorCode SetupDomainCellDecompositionMap(UserCtx *user)
Internal helper implementation: SetupDomainCellDecompositionMap().
Definition setup.c:3551
Defines a 3D axis-aligned bounding box.
Definition variables.h:197
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, {FIELD_ID_UCAT}) and then call UpdateLocalGhosts(user, FIELD_ID_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 3300 of file setup.c.

3301{
3302 PetscErrorCode ierr;
3303 DMDALocalInfo info;
3304 Cmpnts ***lcsi_arr, ***leta_arr, ***lzet_arr; // Local metric arrays
3305 Cmpnts ***lucont_arr; // Local contravariant velocity array
3306 Cmpnts ***gucat_arr; // Global Cartesian velocity array
3307 PetscReal ***lnvert_arr; // Local Nvert array
3308 PetscReal ***laj_arr; // Local Jacobian Determinant inverse array
3309
3310 PetscFunctionBeginUser;
3312 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Starting Contravariant-to-Cartesian velocity transformation.\n");
3313
3314 // --- 1. Get DMDA Info and Check for Valid Inputs ---
3315 // All inputs (lUcont, lCsi, etc.) and outputs (Ucat) are on DMs from the UserCtx.
3316 // We get local info from fda, which governs the layout of most arrays here.
3317 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
3318 if (!user->lUcont || !user->lCsi || !user->lEta || !user->lZet || !user->lNvert || !user->Ucat) {
3319 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Contra2Cart requires lUcont, lCsi/Eta/Zet, lNvert, and Ucat to be non-NULL.");
3320 }
3321
3322
3323 // --- 2. Get Read-Only Array Access to Local Input Vectors (with ghosts) ---
3324 ierr = DMDAVecGetArrayRead(user->fda, user->lUcont, &lucont_arr); CHKERRQ(ierr);
3325 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &lcsi_arr); CHKERRQ(ierr);
3326 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &leta_arr); CHKERRQ(ierr);
3327 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &lzet_arr); CHKERRQ(ierr);
3328 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, &lnvert_arr); CHKERRQ(ierr);
3329 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &laj_arr); CHKERRQ(ierr);
3330
3331 // --- 3. Get Write-Only Array Access to the Global Output Vector ---
3332 // We compute for local owned cells and write into the global vector.
3333 // PETSc handles mapping the global indices to the correct local memory locations.
3334 ierr = DMDAVecGetArray(user->fda, user->Ucat, &gucat_arr); CHKERRQ(ierr);
3335
3336
3337 // --- 4. Define Loop Bounds for INTERIOR Cells ---
3338 // We use adjusted bounds to avoid calculating Ucat on the physical domain boundaries,
3339 // as these are typically set explicitly by boundary condition functions.
3340 // The stencils use indices like i-1, j-1, k-1, so we must start loops at least at index 1.
3341 PetscInt i_start = (info.xs == 0) ? info.xs + 1 : info.xs;
3342 PetscInt i_end = (info.xs + info.xm == info.mx) ? info.xs + info.xm - 1 : info.xs + info.xm;
3343
3344 PetscInt j_start = (info.ys == 0) ? info.ys + 1 : info.ys;
3345 PetscInt j_end = (info.ys + info.ym == info.my) ? info.ys + info.ym - 1 : info.ys + info.ym;
3346
3347 PetscInt k_start = (info.zs == 0) ? info.zs + 1 : info.zs;
3348 PetscInt k_end = (info.zs + info.zm == info.mz) ? info.zs + info.zm - 1 : info.zs + info.zm;
3349
3350 // --- 5. Main Computation Loop ---
3351 // Loops over the GLOBAL indices of interior cells owned by this rank.
3352 for (PetscInt k_cell = k_start; k_cell < k_end; ++k_cell) {
3353 for (PetscInt j_cell = j_start; j_cell < j_end; ++j_cell) {
3354 for (PetscInt i_cell = i_start; i_cell < i_end; ++i_cell) {
3355
3356 // Check if the cell is a fluid cell (not solid/blanked)
3357 // if (lnvert_arr[k_cell][j_cell][i_cell] > 0.1) continue; // Skip solid/blanked cells
3358
3359 // Transformation matrix [mat] is the metric tensor at the cell center,
3360 // estimated by averaging metrics from adjacent faces.
3361 PetscReal mat[3][3];
3362
3363 // PetscReal aj_center = laj_arr[k_cell+1][j_cell+1][i_cell+1];
3364
3365 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;
3366 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;
3367 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;
3368
3369 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;
3370 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;
3371 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;
3372
3373 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;
3374 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;
3375 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;
3376
3377 // Contravariant velocity vector `q` at the cell center,
3378 // estimated by averaging face-based contravariant velocities.
3379 PetscReal q[3];
3380 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
3381 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
3382 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
3383
3384 // Solve the 3x3 system `mat * ucat = q` using Cramer's rule.
3385 PetscReal det = mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
3386 mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
3387 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]);
3388
3389 if (PetscAbsReal(det) < 1.0e-18) {
3390 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);
3391 }
3392
3393 PetscReal det_inv = 1.0 / det;
3394
3395 PetscReal det0 = q[0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
3396 q[1] * (mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) +
3397 q[2] * (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]);
3398
3399 PetscReal det1 = -q[0] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
3400 q[1] * (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) -
3401 q[2] * (mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]);
3402
3403 PetscReal det2 = q[0] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) -
3404 q[1] * (mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) +
3405 q[2] * (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]);
3406
3407 // Store computed Cartesian velocity in the GLOBAL Ucat array at the
3408 // array index corresponding to the cell's origin node.
3409 gucat_arr[k_cell][j_cell][i_cell].x = det0 * det_inv;
3410 gucat_arr[k_cell][j_cell][i_cell].y = det1 * det_inv;
3411 gucat_arr[k_cell][j_cell][i_cell].z = det2 * det_inv;
3412 }
3413 }
3414 }
3415
3416 // --- 6. Restore Array Access ---
3417 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcont, &lucont_arr); CHKERRQ(ierr);
3418 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &lcsi_arr); CHKERRQ(ierr);
3419 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &leta_arr); CHKERRQ(ierr);
3420 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &lzet_arr); CHKERRQ(ierr);
3421 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, &lnvert_arr); CHKERRQ(ierr);
3422 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &laj_arr); CHKERRQ(ierr);
3423 ierr = DMDAVecRestoreArray(user->fda, user->Ucat, &gucat_arr); CHKERRQ(ierr);
3424
3425 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed Contravariant-to-Cartesian velocity transformation. \n");
3427 PetscFunctionReturn(0);
3428}
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 3435 of file setup.c.

3436{
3437 PetscErrorCode ierr;
3438 DMDALocalInfo info;
3439 const Cmpnts ***ucat_arr, ***csi_arr, ***eta_arr, ***zet_arr;
3440 Cmpnts ***ucont_arr;
3441
3442 PetscFunctionBeginUser;
3444
3445 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
3446 ierr = DMDAVecGetArrayRead(user->fda, user->lUcat, &ucat_arr); CHKERRQ(ierr);
3447 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
3448 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
3449 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
3450 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
3451
3452 const PetscInt i_start = PetscMax(info.xs, 1);
3453 const PetscInt j_start = PetscMax(info.ys, 1);
3454 const PetscInt k_start = PetscMax(info.zs, 1);
3455 const PetscInt i_end = PetscMin(info.xs + info.xm, info.mx - 1);
3456 const PetscInt j_end = PetscMin(info.ys + info.ym, info.my - 1);
3457 const PetscInt k_end = PetscMin(info.zs + info.zm, info.mz - 1);
3458
3459 for (PetscInt k = k_start; k < k_end; k++) {
3460 for (PetscInt j = j_start; j < j_end; j++) {
3461 for (PetscInt i = i_start; i < i_end; i++) {
3462 const Cmpnts u_xi = {
3463 0.5 * (ucat_arr[k][j][i].x + ucat_arr[k][j][i + 1].x),
3464 0.5 * (ucat_arr[k][j][i].y + ucat_arr[k][j][i + 1].y),
3465 0.5 * (ucat_arr[k][j][i].z + ucat_arr[k][j][i + 1].z)
3466 };
3467 const Cmpnts u_eta = {
3468 0.5 * (ucat_arr[k][j][i].x + ucat_arr[k][j + 1][i].x),
3469 0.5 * (ucat_arr[k][j][i].y + ucat_arr[k][j + 1][i].y),
3470 0.5 * (ucat_arr[k][j][i].z + ucat_arr[k][j + 1][i].z)
3471 };
3472 const Cmpnts u_zeta = {
3473 0.5 * (ucat_arr[k][j][i].x + ucat_arr[k + 1][j][i].x),
3474 0.5 * (ucat_arr[k][j][i].y + ucat_arr[k + 1][j][i].y),
3475 0.5 * (ucat_arr[k][j][i].z + ucat_arr[k + 1][j][i].z)
3476 };
3477 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;
3478 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;
3479 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;
3480 }
3481 }
3482 }
3483
3484 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
3485 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
3486 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
3487 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
3488 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcat, &ucat_arr); CHKERRQ(ierr);
3489
3491 PetscFunctionReturn(0);
3492}
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.

Definition at line 3504 of file setup.c.

3505{
3506 PetscErrorCode ierr;
3507 PetscFunctionBeginUser;
3509
3510 DMDALocalInfo info;
3511 Cmpnts ***ucont_arr;
3512 const Cmpnts ***csi_arr, ***eta_arr, ***zet_arr;
3513
3514 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
3515 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
3516 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
3517 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
3518 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
3519
3520 const PetscInt xs = info.xs, xe = info.xs + info.xm;
3521 const PetscInt ys = info.ys, ye = info.ys + info.ym;
3522 const PetscInt zs = info.zs, ze = info.zs + info.zm;
3523
3524 for (PetscInt k = zs; k < ze; k++) {
3525 for (PetscInt j = ys; j < ye; j++) {
3526 for (PetscInt i = xs; i < xe; i++) {
3527 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;
3528 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;
3529 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;
3530 }
3531 }
3532 }
3533
3534 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
3535 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
3536 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
3537 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont_arr); CHKERRQ(ierr);
3538
3539 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Cart2Contra: set Ucont from Cartesian (%.3f, %.3f, %.3f).\n",
3540 (double)u, (double)v, (double)w);
3542 PetscFunctionReturn(0);
3543}
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 3551 of file setup.c.

3552{
3553 PetscErrorCode ierr;
3554 DMDALocalInfo local_node_info;
3555 RankCellInfo my_cell_info;
3556 PetscMPIInt rank, size;
3557
3558 PetscFunctionBeginUser;
3560
3561 // --- 1. Input Validation and MPI Info ---
3562 if (!user) {
3563 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx pointer is NULL in SetupDomainCellDecompositionMap.");
3564 }
3565 if (!user->da) {
3566 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "user->da is not initialized in SetupDomainCellDecompositionMap.");
3567 }
3568
3569 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3570 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
3571
3572 LOG_ALLOW(GLOBAL, LOG_INFO, "Setting up domain cell decomposition map for %d ranks.\n", size);
3573
3574 // --- 2. Determine Local Cell Ownership ---
3575 // Get the local node ownership information from the primary DMDA.
3576 ierr = DMDAGetLocalInfo(user->da, &local_node_info); CHKERRQ(ierr);
3577
3578 // Use the robust helper function to convert node ownership to cell ownership.
3579 // A cell's index is defined by its origin node.
3580
3581 ierr = GetOwnedCellRange(&local_node_info, 0, &my_cell_info.xs_cell, &my_cell_info.xm_cell); CHKERRQ(ierr);
3582 ierr = GetOwnedCellRange(&local_node_info, 1, &my_cell_info.ys_cell, &my_cell_info.ym_cell); CHKERRQ(ierr);
3583 ierr = GetOwnedCellRange(&local_node_info, 2, &my_cell_info.zs_cell, &my_cell_info.zm_cell); CHKERRQ(ierr);
3584
3585 // Log the calculated local ownership for debugging purposes.
3586 LOG_ALLOW(LOCAL, LOG_DEBUG, "[Rank %d] Owns cells: i[%d, %d), j[%d, %d), k[%d, %d)\n",
3587 rank, my_cell_info.xs_cell, my_cell_info.xs_cell + my_cell_info.xm_cell,
3588 my_cell_info.ys_cell, my_cell_info.ys_cell + my_cell_info.ym_cell,
3589 my_cell_info.zs_cell, my_cell_info.zs_cell + my_cell_info.zm_cell);
3590
3591 // --- 3. Allocate and Distribute the Global Map ---
3592 // Allocate memory for the global map that will hold information from all ranks.
3593 ierr = PetscMalloc1(size, &user->RankCellInfoMap); CHKERRQ(ierr);
3594
3595 // Perform the collective communication to gather the `RankCellInfo` struct from every rank.
3596 // Each rank sends its `my_cell_info` and receives the complete array in `user->RankCellInfoMap`.
3597 // We use MPI_BYTE to ensure portability across different systems and struct padding.
3598 ierr = MPI_Allgather(&my_cell_info, sizeof(RankCellInfo), MPI_BYTE,
3599 user->RankCellInfoMap, sizeof(RankCellInfo), MPI_BYTE,
3600 PETSC_COMM_WORLD); CHKERRQ(ierr);
3601
3602 LOG_ALLOW(GLOBAL, LOG_INFO, "Domain cell decomposition map created and distributed successfully.\n");
3603
3605 PetscFunctionReturn(0);
3606}
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:2936
PetscInt ys_cell
Definition variables.h:230
PetscInt xs_cell
Definition variables.h:230
PetscInt zm_cell
Definition variables.h:231
PetscInt zs_cell
Definition variables.h:230
PetscInt xm_cell
Definition variables.h:231
RankCellInfo * RankCellInfoMap
Definition variables.h:1170
PetscInt ym_cell
Definition variables.h:231
A lean struct to hold the global cell ownership range for a single MPI rank.
Definition variables.h:229
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 3616 of file setup.c.

3617{
3618 PetscInt low = 0, high = n - 1;
3619
3620 PetscFunctionBeginUser;
3622
3623 // --- 1. Input Validation ---
3624 if (!found) {
3625 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Output pointer 'found' is NULL in PetscBinarySearchInt64.");
3626 }
3627 if (n > 0 && !arr) {
3628 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input array 'arr' is NULL for n > 0.");
3629 }
3630
3631 // Initialize output
3632 *found = PETSC_FALSE;
3633
3634 // --- 2. Binary Search Algorithm ---
3635 while (low <= high) {
3636 // Use this form to prevent potential integer overflow on very large arrays
3637 PetscInt mid = low + (high - low) / 2;
3638
3639 if (arr[mid] == key) {
3640 *found = PETSC_TRUE; // Key found!
3641 break; // Exit the loop
3642 }
3643
3644 if (arr[mid] < key) {
3645 low = mid + 1; // Search in the right half
3646 } else {
3647 high = mid - 1; // Search in the left half
3648 }
3649 }
3650
3652 PetscFunctionReturn(0);
3653}
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 3685 of file setup.c.

3686{
3687 DM da = user->da, fda = user->fda;
3688 DMDALocalInfo info = user->info;
3689
3690 PetscInt ti = user->simCtx->step;
3691
3692 PetscInt xs = info.xs, xe = info.xs + info.xm;
3693 PetscInt ys = info.ys, ye = info.ys + info.ym;
3694 PetscInt zs = info.zs, ze = info.zs + info.zm;
3695 PetscInt mx = info.mx, my = info.my, mz = info.mz;
3696
3697 PetscInt lxs, lys, lzs, lxe, lye, lze;
3698 PetscInt i, j, k;
3699
3700 Vec Div;
3701 PetscReal ***div, ***aj, ***nvert,***p;
3702 Cmpnts ***ucont;
3703 PetscReal maxdiv;
3704
3705 lxs = xs; lxe = xe;
3706 lys = ys; lye = ye;
3707 lzs = zs; lze = ze;
3708
3709 if (xs==0) lxs = xs+1;
3710 if (ys==0) lys = ys+1;
3711 if (zs==0) lzs = zs+1;
3712
3713 if (xe==mx) lxe = xe-1;
3714 if (ye==my) lye = ye-1;
3715 if (ze==mz) lze = ze-1;
3716
3717 PetscFunctionBeginUser;
3719
3720 DMDAVecGetArray(fda,user->lUcont, &ucont);
3721 DMDAVecGetArray(da, user->lAj, &aj);
3722 VecDuplicate(user->P, &Div);
3723 DMDAVecGetArray(da, Div, &div);
3724 DMDAVecGetArray(da, user->lNvert, &nvert);
3725 DMDAVecGetArray(da, user->P, &p);
3726 for (k=lzs; k<lze; k++) {
3727 for (j=lys; j<lye; j++){
3728 for (i=lxs; i<lxe; i++) {
3729 if (k==10 && j==10 && i==1){
3730 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]);
3731 }
3732
3733 if (k==10 && j==10 && i==mx-3)
3734 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]);
3735 }
3736 }
3737 }
3738 DMDAVecRestoreArray(da, user->P, &p);
3739
3740
3741 for (k=lzs; k<lze; k++) {
3742 for (j=lys; j<lye; j++) {
3743 for (i=lxs; i<lxe; i++) {
3744 maxdiv = fabs((ucont[k][j][i].x - ucont[k][j][i-1].x +
3745 ucont[k][j][i].y - ucont[k][j-1][i].y +
3746 ucont[k][j][i].z - ucont[k-1][j][i].z)*aj[k][j][i]);
3747 if (nvert[k][j][i] + nvert[k+1][j][i] + nvert[k-1][j][i] +
3748 nvert[k][j+1][i] + nvert[k][j-1][i] +
3749 nvert[k][j][i+1] + nvert[k][j][i-1] > 0.1) maxdiv = 0.;
3750 div[k][j][i] = maxdiv;
3751
3752 }
3753 }
3754 }
3755
3756 if (zs==0) {
3757 k=0;
3758 for (j=ys; j<ye; j++) {
3759 for (i=xs; i<xe; i++) {
3760 div[k][j][i] = 0.;
3761 }
3762 }
3763 }
3764
3765 if (ze == mz) {
3766 k=mz-1;
3767 for (j=ys; j<ye; j++) {
3768 for (i=xs; i<xe; i++) {
3769 div[k][j][i] = 0.;
3770 }
3771 }
3772 }
3773
3774 if (xs==0) {
3775 i=0;
3776 for (k=zs; k<ze; k++) {
3777 for (j=ys; j<ye; j++) {
3778 div[k][j][i] = 0.;
3779 }
3780 }
3781 }
3782
3783 if (xe==mx) {
3784 i=mx-1;
3785 for (k=zs; k<ze; k++) {
3786 for (j=ys; j<ye; j++) {
3787 div[k][j][i] = 0;
3788 }
3789 }
3790 }
3791
3792 if (ys==0) {
3793 j=0;
3794 for (k=zs; k<ze; k++) {
3795 for (i=xs; i<xe; i++) {
3796 div[k][j][i] = 0.;
3797 }
3798 }
3799 }
3800
3801 if (ye==my) {
3802 j=my-1;
3803 for (k=zs; k<ze; k++) {
3804 for (i=xs; i<xe; i++) {
3805 div[k][j][i] = 0.;
3806 }
3807 }
3808 }
3809 DMDAVecRestoreArray(da, Div, &div);
3810 PetscInt MaxFlatIndex;
3811
3812 VecMax(Div, &MaxFlatIndex, &maxdiv);
3813
3814 LOG_ALLOW(GLOBAL,LOG_INFO,"[Step %d]] The Maximum Divergence is %e at flat index %d.\n",ti,maxdiv,MaxFlatIndex);
3815
3816 user->simCtx->MaxDivFlatArg = MaxFlatIndex;
3817 user->simCtx->MaxDiv = maxdiv;
3818
3819 for (k=zs; k<ze; k++) {
3820 for (j=ys; j<ye; j++) {
3821 for (i=xs; i<xe; i++) {
3822 if (Gidx(i,j,k,user) == MaxFlatIndex) {
3823 LOG_ALLOW(GLOBAL,LOG_INFO,"[Step %d] The Maximum Divergence(%e) is at location [%d][%d][%d]. \n", ti, maxdiv,k,j,i);
3824 user->simCtx->MaxDivz = k;
3825 user->simCtx->MaxDivy = j;
3826 user->simCtx->MaxDivx = i;
3827 }
3828 }
3829 }
3830 }
3831
3832
3833 DMDAVecRestoreArray(da, user->lNvert, &nvert);
3834 DMDAVecRestoreArray(fda, user->lUcont, &ucont);
3835 DMDAVecRestoreArray(da, user->lAj, &aj);
3836 VecDestroy(&Div);
3837
3839 PetscFunctionReturn(0);
3840}
static PetscInt Gidx(PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
Convert logical indices into the flattened global index used by setup helpers.
Definition setup.c:3659
DMDALocalInfo info
Definition variables.h:1086
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 3851 of file setup.c.

3851 {
3852 PetscErrorCode ierr; // Error code for PETSc functions
3853 PetscMPIInt rank;
3854 PetscFunctionBeginUser;
3856 MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
3857
3858 // Initialize RNG for x-coordinate
3859 ierr = PetscRandomCreate(PETSC_COMM_SELF, randx); CHKERRQ(ierr);
3860 ierr = PetscRandomSetType((*randx), PETSCRAND48); CHKERRQ(ierr);
3861 ierr = PetscRandomSetInterval(*randx, user->bbox.min_coords.x, user->bbox.max_coords.x); CHKERRQ(ierr);
3862 /* Offsets reproduce the historical fixed seeds (12345, 67890, 54321 plus rank) at the
3863 default base seed, so existing placements are unchanged. */
3864 const unsigned long base_seed = (unsigned long)user->simCtx->particleRandomSeed;
3865 ierr = PetscRandomSetSeed(*randx, base_seed + (unsigned long)rank); CHKERRQ(ierr);
3866 ierr = PetscRandomSeed(*randx); CHKERRQ(ierr);
3867 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for X-axis.\n",rank);
3868
3869 // Initialize RNG for y-coordinate
3870 ierr = PetscRandomCreate(PETSC_COMM_SELF, randy); CHKERRQ(ierr);
3871 ierr = PetscRandomSetType((*randy), PETSCRAND48); CHKERRQ(ierr);
3872 ierr = PetscRandomSetInterval(*randy, user->bbox.min_coords.y, user->bbox.max_coords.y); CHKERRQ(ierr);
3873 ierr = PetscRandomSetSeed(*randy, base_seed + 55545UL + (unsigned long)rank); CHKERRQ(ierr);
3874 ierr = PetscRandomSeed(*randy); CHKERRQ(ierr);
3875 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for Y-axis.\n",rank);
3876
3877 // Initialize RNG for z-coordinate
3878 ierr = PetscRandomCreate(PETSC_COMM_SELF, randz); CHKERRQ(ierr);
3879 ierr = PetscRandomSetType((*randz), PETSCRAND48); CHKERRQ(ierr);
3880 ierr = PetscRandomSetInterval(*randz, user->bbox.min_coords.z, user->bbox.max_coords.z); CHKERRQ(ierr);
3881 ierr = PetscRandomSetSeed(*randz, base_seed + 41976UL + (unsigned long)rank); CHKERRQ(ierr);
3882 ierr = PetscRandomSeed(*randz); CHKERRQ(ierr);
3883 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for Z-axis.\n",rank);
3884
3886 PetscFunctionReturn(0);
3887}
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:199
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:198
BoundingBox bbox
Definition variables.h:1090
Here is the caller graph for this function:

◆ InitializeLogicalSpaceRNGs()

PetscErrorCode InitializeLogicalSpaceRNGs ( PetscInt  base_seed,
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
[in]base_seedBase particle seed (SimCtx::particleRandomSeed); each stream adds a fixed offset and the rank.
[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 3895 of file setup.c.

3895 {
3896 PetscErrorCode ierr;
3897 PetscMPIInt rank;
3898 PetscFunctionBeginUser;
3899
3901
3902 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3903
3904 // --- RNG for i-logical dimension ---
3905 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_i); CHKERRQ(ierr);
3906 ierr = PetscRandomSetType((*rand_logic_i), PETSCRAND48); CHKERRQ(ierr);
3907 ierr = PetscRandomSetInterval(*rand_logic_i, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
3908 /* Offsets reproduce the historical seeds (202401..202403 plus rank) at the default base. */
3909 ierr = PetscRandomSetSeed(*rand_logic_i, (unsigned long)base_seed + 190056UL + (unsigned long)rank); CHKERRQ(ierr);
3910 ierr = PetscRandomSeed(*rand_logic_i); CHKERRQ(ierr);
3911 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for i-logical dimension [0,1).\n",rank);
3912
3913 // --- RNG for j-logical dimension ---
3914 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_j); CHKERRQ(ierr);
3915 ierr = PetscRandomSetType((*rand_logic_j), PETSCRAND48); CHKERRQ(ierr);
3916 ierr = PetscRandomSetInterval(*rand_logic_j, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
3917 ierr = PetscRandomSetSeed(*rand_logic_j, (unsigned long)base_seed + 190057UL + (unsigned long)rank); CHKERRQ(ierr);
3918 ierr = PetscRandomSeed(*rand_logic_j); CHKERRQ(ierr);
3919 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for j-logical dimension [0,1).\n",rank);
3920
3921 // --- RNG for k-logical dimension ---
3922 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_k); CHKERRQ(ierr);
3923 ierr = PetscRandomSetType((*rand_logic_k), PETSCRAND48); CHKERRQ(ierr);
3924 ierr = PetscRandomSetInterval(*rand_logic_k, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
3925 ierr = PetscRandomSetSeed(*rand_logic_k, (unsigned long)base_seed + 190058UL + (unsigned long)rank); CHKERRQ(ierr);
3926 ierr = PetscRandomSeed(*rand_logic_k); CHKERRQ(ierr);
3927 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for k-logical dimension [0,1).\n",rank);
3928
3929
3931 PetscFunctionReturn(0);
3932}
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. Seeded from particleRandomSeed, the rank, and StartStep, so identical inputs on the same rank count reproduce, and a restart draws a fresh sequence.

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 3940 of file setup.c.

3940 {
3941 PetscErrorCode ierr;
3942 PetscMPIInt rank;
3943
3944 PetscFunctionBeginUser;
3946
3947 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3948
3949 // 1. Create the generator (stored in SimCtx, not UserCtx, as it is global physics)
3950 ierr = PetscRandomCreate(PETSC_COMM_WORLD, &simCtx->BrownianMotionRNG); CHKERRQ(ierr);
3951 ierr = PetscRandomSetType(simCtx->BrownianMotionRNG, PETSCRAND48); CHKERRQ(ierr);
3952
3953 // 2. CRITICAL: Set interval to [0, 1).
3954 // This is required for the Gaussian math to work.
3955 ierr = PetscRandomSetInterval(simCtx->BrownianMotionRNG, 0.0, 1.0); CHKERRQ(ierr);
3956
3957 // 3. Seed from the configured base, the rank, and the start step. It was seeded from
3958 // the wall clock, so no two runs of the same inputs agreed. The start step keeps a
3959 // restart from replaying the increments the first segment already drew, which would
3960 // correlate them; the same restart is still reproducible.
3961 unsigned long seed = (unsigned long)simCtx->particleRandomSeed
3962 + (unsigned long)rank * 987654321UL
3963 + (unsigned long)simCtx->StartStep * 1000003UL;
3964 ierr = PetscRandomSetSeed(simCtx->BrownianMotionRNG, seed); CHKERRQ(ierr);
3965 ierr = PetscRandomSeed(simCtx->BrownianMotionRNG); CHKERRQ(ierr);
3966
3967 LOG_ALLOW(LOCAL, LOG_VERBOSE, "[Rank %d] Initialized Brownian Physics RNG.\n", rank);
3968
3970 PetscFunctionReturn(0);
3971}
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
jacobianLocal mapping Jacobian determinant.
csi_metricsPhysical gradient of the xi coordinate.
eta_metricsPhysical gradient of the eta coordinate.
zet_metricsPhysical gradient of the zeta coordinate.
dPhi_dcsiScalar derivative in the xi direction.
dPhi_detaScalar derivative in the eta direction.
dPhi_dzetScalar derivative in the zeta direction.
[out]gradPhiPhysical Cartesian scalar gradient.

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 3983 of file setup.c.

3991{
3992 // Gradient X component
3993 gradPhi->x = jacobian * (dPhi_dcsi * csi_metrics.x + dPhi_deta * eta_metrics.x + dPhi_dzet * zet_metrics.x);
3994
3995 // Gradient Y component
3996 gradPhi->y = jacobian * (dPhi_dcsi * csi_metrics.y + dPhi_deta * eta_metrics.y + dPhi_dzet * zet_metrics.y);
3997
3998 // Gradient Z component
3999 gradPhi->z = jacobian * (dPhi_dcsi * csi_metrics.z + dPhi_deta * eta_metrics.z + dPhi_dzet * zet_metrics.z);
4000}
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
userBlock metric context.
iCell index in the xi direction.
jCell index in the eta direction.
kCell index in the zeta direction.
field_dataGhosted scalar values indexed as [k][j][i].
[out]gradPhysical Cartesian gradient at the requested cell.
Returns
PetscErrorCode 0 on success.

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

Local to this translation unit.

Definition at line 4031 of file setup.c.

4033{
4034 PetscErrorCode ierr;
4035 Cmpnts ***csi, ***eta, ***zet;
4036 PetscReal ***jac;
4037 PetscReal d_csi, d_eta, d_zet;
4038
4039 PetscFunctionBeginUser;
4040
4041 // 1. Get read-only access to metrics
4042 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
4043 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
4044 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
4045 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
4046
4047 // 2. Compute derivatives in computational space (Central Difference)
4048 // Assumes ghosts are available at i+/-1
4049 d_csi = 0.5 * (field_data[k][j][i+1] - field_data[k][j][i-1]);
4050 d_eta = 0.5 * (field_data[k][j+1][i] - field_data[k][j-1][i]);
4051 d_zet = 0.5 * (field_data[k+1][j][i] - field_data[k-1][j][i]);
4052
4053 // 3. Transform to physical space
4055 csi[k][j][i], eta[k][j][i], zet[k][j][i],
4056 d_csi, d_eta, d_zet,
4057 grad);
4058
4059 // 4. Restore arrays
4060 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
4061 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
4062 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
4063 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
4064
4065 PetscFunctionReturn(0);
4066}
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:3983
Here is the call graph for this function:
Here is the caller 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
userBlock metric context.
iCell index in the xi direction.
jCell index in the eta direction.
kCell index in the zeta direction.
field_dataGhosted Cartesian vector values indexed as [k][j][i].
[out]dudxGradient of the x velocity component.
[out]dvdxGradient of the y velocity component.
[out]dwdxGradient of the z velocity component.
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 4074 of file setup.c.

4076{
4077 PetscErrorCode ierr;
4078 Cmpnts ***csi, ***eta, ***zet;
4079 PetscReal ***jac;
4080 PetscFunctionBeginUser;
4081
4082 // 1. Get read-only access to the necessary metric data arrays
4083 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
4084 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
4085 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
4086 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
4087
4088 // 2. Calculate derivatives in computational space using central differencing
4089 Cmpnts deriv_csi, deriv_eta, deriv_zet;
4090 deriv_csi.x = (field_data[k][j][i+1].x - field_data[k][j][i-1].x) * 0.5;
4091 deriv_csi.y = (field_data[k][j][i+1].y - field_data[k][j][i-1].y) * 0.5;
4092 deriv_csi.z = (field_data[k][j][i+1].z - field_data[k][j][i-1].z) * 0.5;
4093
4094 deriv_eta.x = (field_data[k][j+1][i].x - field_data[k][j-1][i].x) * 0.5;
4095 deriv_eta.y = (field_data[k][j+1][i].y - field_data[k][j-1][i].y) * 0.5;
4096 deriv_eta.z = (field_data[k][j+1][i].z - field_data[k][j-1][i].z) * 0.5;
4097
4098 deriv_zet.x = (field_data[k+1][j][i].x - field_data[k-1][j][i].x) * 0.5;
4099 deriv_zet.y = (field_data[k+1][j][i].y - field_data[k-1][j][i].y) * 0.5;
4100 deriv_zet.z = (field_data[k+1][j][i].z - field_data[k-1][j][i].z) * 0.5;
4101
4102 // 3. Transform derivatives to physical space
4103 TransformDerivativesToPhysical(jac[k][j][i], csi[k][j][i], eta[k][j][i], zet[k][j][i],
4104 deriv_csi, deriv_eta, deriv_zet,
4105 dudx, dvdx, dwdx);
4106
4107 // 4. Restore access to the PETSc data arrays
4108 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
4109 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
4110 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
4111 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
4112
4113 PetscFunctionReturn(0);
4114}
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)
Transform contravariant vector derivatives into physical Cartesian derivatives.
Definition setup.c:4007
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LESConfigSetDefaults()

PetscErrorCode LESConfigSetDefaults ( LESConfig *  config)

Installs the shipped defaults for every LES closure parameter.

One definition of the defaults, shared by the control-file ingress and by test fixtures, so the two cannot drift apart. It lives with the rest of the context construction because defaults are ingress, not closure behaviour, and because the postprocessor builds a simulation context without linking the LES module.

Local averaging and clamped limiting are the defaults because they are the only settings valid on arbitrary geometry; cases with homogeneous directions or an interest in backscatter opt into the alternatives.

Parameters
[out]configConfiguration block to populate.
Returns
PetscErrorCode 0 on success, or PETSC_ERR_ARG_NULL for a null argument.

Installs the shipped defaults for every LES closure parameter.

Full API contract is documented with the header declaration in include/setup.h.

See also
LESConfigSetDefaults()

Definition at line 206 of file setup.c.

207{
208 PetscFunctionBeginUser;
209 PetscCheck(config != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
210 "LES configuration destination cannot be NULL.");
211
212 config->dynamic_frequency = 1;
213 config->constant_cs = 0.03;
214 // Vreman (2004) recommends c = 2.5 Cs^2, 0.07 for Cs = 0.17; Nicoud & Ducros (1999)
215 // calibrate C_w near 0.5-0.6 against the same isotropic decay. Both are calibrations
216 // from isotropic turbulence, not universal values.
217 config->vreman_coefficient = 0.07;
218 config->wale_coefficient = 0.5;
221 config->test_filter_width_ratio = 2.0;
222 // Local averaging makes no homogeneity claim, so it is the only default that is
223 // correct on every geometry. Homogeneous and global averaging are opted into.
225 config->averaging_direction[0] = PETSC_FALSE;
226 config->averaging_direction[1] = PETSC_FALSE;
227 config->averaging_direction[2] = PETSC_FALSE;
228 config->clip_mode = LES_CLIP_CLAMP;
229 // Roughly twice the physical Smagorinsky constant: high enough to catch a
230 // diverging coefficient, low enough that it does not shape the distribution.
231 config->max_cs = 0.3;
232 config->min_viscosity_ratio = 0.0;
233 config->yoshizawa_ci = 0.09;
234 config->diagnostics_enabled = PETSC_FALSE;
235 config->diagnostics_cadence = 1;
236
237 PetscFunctionReturn(0);
238}
PetscReal yoshizawa_ci
Yoshizawa constant for the reported SGS kinetic energy.
Definition variables.h:642
PetscInt dynamic_frequency
Recompute the dynamic coefficient every N steps.
Definition variables.h:630
LESFilterWidthModel filter_width_model
How the grid filter width Delta is derived per cell.
Definition variables.h:634
LESTestFilterKernel test_filter_kernel
Discrete test-filter stencil.
Definition variables.h:635
@ LES_CLIP_CLAMP
Definition variables.h:618
@ LES_TEST_FILTER_VOLUME_WEIGHTED_BOX
Definition variables.h:592
PetscReal max_cs
Ceiling on Cs under LES_CLIP_CLAMP.
Definition variables.h:640
LESClipMode clip_mode
Admissible range for the coefficient.
Definition variables.h:639
PetscBool averaging_direction[3]
Averaged-over logical directions (xi, eta, zeta).
Definition variables.h:638
PetscReal wale_coefficient
Model constant C_w for WALE (Nicoud & Ducros 1999).
Definition variables.h:633
PetscInt diagnostics_cadence
Steps between diagnostic rows.
Definition variables.h:644
PetscReal min_viscosity_ratio
Enforce nu + nu_t >= ratio * nu.
Definition variables.h:641
@ LES_AVERAGING_LOCAL
Definition variables.h:605
PetscBool diagnostics_enabled
Append per-step coefficient statistics to the run log directory.
Definition variables.h:643
PetscReal constant_cs
Fixed Cs for CONSTANT_SMAGORINSKY; unused by the dynamic model.
Definition variables.h:631
PetscReal test_filter_width_ratio
Test-to-grid ratio per filtered direction; alpha is its square for the box, ratio^(4/3) for Simpson.
Definition variables.h:636
LESAveragingMode averaging_mode
Averaging set for the Germano contractions.
Definition variables.h:637
PetscReal vreman_coefficient
Model constant c for VREMAN (Vreman 2004: 2.5 Cs^2).
Definition variables.h:632
@ LES_FILTER_WIDTH_CUBE_ROOT_VOLUME
Definition variables.h:580
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 the Vec objects stored in a UserCtx. The vectors are organized into functional groups 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)
  • 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 4128 of file setup.c.

4129{
4130 PetscErrorCode ierr;
4131 PetscFunctionBeginUser;
4132
4133 // --- Group A: Primary Flow Fields (Always allocated at all levels) ---
4134 if (user->Ucont) { ierr = VecDestroy(&user->Ucont); CHKERRQ(ierr); }
4135 if (user->lUcont) { ierr = VecDestroy(&user->lUcont); CHKERRQ(ierr); }
4136 if (user->Ucat) { ierr = VecDestroy(&user->Ucat); CHKERRQ(ierr); }
4137 if (user->lUcat) { ierr = VecDestroy(&user->lUcat); CHKERRQ(ierr); }
4138 if (user->P) { ierr = VecDestroy(&user->P); CHKERRQ(ierr); }
4139 if (user->lP) { ierr = VecDestroy(&user->lP); CHKERRQ(ierr); }
4140 if (user->Nvert) { ierr = VecDestroy(&user->Nvert); CHKERRQ(ierr); }
4141 if (user->lNvert) { ierr = VecDestroy(&user->lNvert); CHKERRQ(ierr); }
4142
4143 // --- Group A2: Derived Flow Fields (Conditional) ---
4144 if(user->Diffusivity) {ierr = VecDestroy(&user->Diffusivity); CHKERRQ(ierr);}
4145 if(user->lDiffusivity){ierr = VecDestroy(&user->lDiffusivity); CHKERRQ(ierr);}
4146 if(user->DiffusivityGradient){ierr = VecDestroy(&user->DiffusivityGradient); CHKERRQ(ierr);}
4147 if(user->lDiffusivityGradient){ierr = VecDestroy(&user->lDiffusivityGradient); CHKERRQ(ierr);}
4148
4149 // --- Group B: Solver Work Vectors (All levels) ---
4150 if (user->Phi) { ierr = VecDestroy(&user->Phi); CHKERRQ(ierr); }
4151 if (user->lPhi) { ierr = VecDestroy(&user->lPhi); CHKERRQ(ierr); }
4152
4153 // --- Group C: Time-Stepping Vectors (Finest level only) ---
4154 if (user->Ucont_o) { ierr = VecDestroy(&user->Ucont_o); CHKERRQ(ierr); }
4155 if (user->Ucont_rm1) { ierr = VecDestroy(&user->Ucont_rm1); CHKERRQ(ierr); }
4156 if (user->Ucat_o) { ierr = VecDestroy(&user->Ucat_o); CHKERRQ(ierr); }
4157 if (user->P_o) { ierr = VecDestroy(&user->P_o); CHKERRQ(ierr); }
4158 if (user->Nvert_o) { ierr = VecDestroy(&user->Nvert_o); CHKERRQ(ierr); }
4159 if (user->lUcont_o) { ierr = VecDestroy(&user->lUcont_o); CHKERRQ(ierr); }
4160 if (user->lUcont_rm1) { ierr = VecDestroy(&user->lUcont_rm1); CHKERRQ(ierr); }
4161 if (user->lNvert_o) { ierr = VecDestroy(&user->lNvert_o); CHKERRQ(ierr); }
4162
4163 // --- Group D: Grid Metrics - Face Centered (All levels) ---
4164 if (user->Csi) { ierr = VecDestroy(&user->Csi); CHKERRQ(ierr); }
4165 if (user->Eta) { ierr = VecDestroy(&user->Eta); CHKERRQ(ierr); }
4166 if (user->Zet) { ierr = VecDestroy(&user->Zet); CHKERRQ(ierr); }
4167 if (user->Aj) { ierr = VecDestroy(&user->Aj); CHKERRQ(ierr); }
4168 if (user->lCsi) { ierr = VecDestroy(&user->lCsi); CHKERRQ(ierr); }
4169 if (user->lEta) { ierr = VecDestroy(&user->lEta); CHKERRQ(ierr); }
4170 if (user->lZet) { ierr = VecDestroy(&user->lZet); CHKERRQ(ierr); }
4171 if (user->lAj) { ierr = VecDestroy(&user->lAj); CHKERRQ(ierr); }
4172
4173 // --- Group E: Grid Metrics - Face Centered (All levels) ---
4174 if (user->ICsi) { ierr = VecDestroy(&user->ICsi); CHKERRQ(ierr); }
4175 if (user->IEta) { ierr = VecDestroy(&user->IEta); CHKERRQ(ierr); }
4176 if (user->IZet) { ierr = VecDestroy(&user->IZet); CHKERRQ(ierr); }
4177 if (user->JCsi) { ierr = VecDestroy(&user->JCsi); CHKERRQ(ierr); }
4178 if (user->JEta) { ierr = VecDestroy(&user->JEta); CHKERRQ(ierr); }
4179 if (user->JZet) { ierr = VecDestroy(&user->JZet); CHKERRQ(ierr); }
4180 if (user->KCsi) { ierr = VecDestroy(&user->KCsi); CHKERRQ(ierr); }
4181 if (user->KEta) { ierr = VecDestroy(&user->KEta); CHKERRQ(ierr); }
4182 if (user->KZet) { ierr = VecDestroy(&user->KZet); CHKERRQ(ierr); }
4183 if (user->IAj) { ierr = VecDestroy(&user->IAj); CHKERRQ(ierr); }
4184 if (user->JAj) { ierr = VecDestroy(&user->JAj); CHKERRQ(ierr); }
4185 if (user->KAj) { ierr = VecDestroy(&user->KAj); CHKERRQ(ierr); }
4186 if (user->lICsi) { ierr = VecDestroy(&user->lICsi); CHKERRQ(ierr); }
4187 if (user->lIEta) { ierr = VecDestroy(&user->lIEta); CHKERRQ(ierr); }
4188 if (user->lIZet) { ierr = VecDestroy(&user->lIZet); CHKERRQ(ierr); }
4189 if (user->lJCsi) { ierr = VecDestroy(&user->lJCsi); CHKERRQ(ierr); }
4190 if (user->lJEta) { ierr = VecDestroy(&user->lJEta); CHKERRQ(ierr); }
4191 if (user->lJZet) { ierr = VecDestroy(&user->lJZet); CHKERRQ(ierr); }
4192 if (user->lKCsi) { ierr = VecDestroy(&user->lKCsi); CHKERRQ(ierr); }
4193 if (user->lKEta) { ierr = VecDestroy(&user->lKEta); CHKERRQ(ierr); }
4194 if (user->lKZet) { ierr = VecDestroy(&user->lKZet); CHKERRQ(ierr); }
4195 if (user->lIAj) { ierr = VecDestroy(&user->lIAj); CHKERRQ(ierr); }
4196 if (user->lJAj) { ierr = VecDestroy(&user->lJAj); CHKERRQ(ierr); }
4197 if (user->lKAj) { ierr = VecDestroy(&user->lKAj); CHKERRQ(ierr); }
4198
4199 // --- Group F: Cell/Face Coordinates and Grid Spacing (All levels) ---
4200 if (user->Cent) { ierr = VecDestroy(&user->Cent); CHKERRQ(ierr); }
4201 if (user->lCent) { ierr = VecDestroy(&user->lCent); CHKERRQ(ierr); }
4202 if (user->GridSpace) { ierr = VecDestroy(&user->GridSpace); CHKERRQ(ierr); }
4203 if (user->lGridSpace) { ierr = VecDestroy(&user->lGridSpace); CHKERRQ(ierr); }
4204 if (user->Centx) { ierr = VecDestroy(&user->Centx); CHKERRQ(ierr); }
4205 if (user->Centy) { ierr = VecDestroy(&user->Centy); CHKERRQ(ierr); }
4206 if (user->Centz) { ierr = VecDestroy(&user->Centz); CHKERRQ(ierr); }
4207 if (user->lCentx) { ierr = VecDestroy(&user->lCentx); CHKERRQ(ierr); }
4208 if (user->lCenty) { ierr = VecDestroy(&user->lCenty); CHKERRQ(ierr); }
4209 if (user->lCentz) { ierr = VecDestroy(&user->lCentz); CHKERRQ(ierr); }
4210
4211 // --- Group G: Turbulence Model Vectors (Finest level, conditional on les) ---
4212 if (user->Nu_t) { ierr = VecDestroy(&user->Nu_t); CHKERRQ(ierr); }
4213 if (user->lNu_t) { ierr = VecDestroy(&user->lNu_t); CHKERRQ(ierr); }
4214 if (user->CS) { ierr = VecDestroy(&user->CS); CHKERRQ(ierr); }
4215 if (user->lCs) { ierr = VecDestroy(&user->lCs); CHKERRQ(ierr); }
4216 if (user->Nu_Wall) { ierr = VecDestroy(&user->Nu_Wall); CHKERRQ(ierr); }
4217 if (user->lNu_Wall) { ierr = VecDestroy(&user->lNu_Wall); CHKERRQ(ierr); }
4218 if (user->Friction_Velocity) { ierr = VecDestroy(&user->Friction_Velocity); CHKERRQ(ierr); }
4219 if (user->lFriction_Velocity) { ierr = VecDestroy(&user->lFriction_Velocity); CHKERRQ(ierr); }
4220
4221 // --- Group H: Particle Vectors (Finest level, conditional on np > 0) ---
4222 if (user->ParticleCount) { ierr = VecDestroy(&user->ParticleCount); CHKERRQ(ierr); }
4223 if (user->lParticleCount) { ierr = VecDestroy(&user->lParticleCount); CHKERRQ(ierr); }
4224 if (user->Psi) { ierr = VecDestroy(&user->Psi); CHKERRQ(ierr); }
4225 if (user->lPsi) { ierr = VecDestroy(&user->lPsi); CHKERRQ(ierr); }
4226
4227 // --- Group I: Boundary Condition Vectors (All levels) ---
4228 if (user->Bcs.Ubcs) { ierr = VecDestroy(&user->Bcs.Ubcs); CHKERRQ(ierr); }
4229 if (user->Bcs.Uch) { ierr = VecDestroy(&user->Bcs.Uch); CHKERRQ(ierr); }
4230
4231 // --- Group J: Post-Processing Vectors (Finest level, postprocessor mode) ---
4232 if (user->P_nodal) { ierr = VecDestroy(&user->P_nodal); CHKERRQ(ierr); }
4233 if (user->Ucat_nodal) { ierr = VecDestroy(&user->Ucat_nodal); CHKERRQ(ierr); }
4234 if (user->Qcrit) { ierr = VecDestroy(&user->Qcrit); CHKERRQ(ierr); }
4235 if (user->lQcrit) { ierr = VecDestroy(&user->lQcrit); CHKERRQ(ierr); }
4236 if (user->Qcrit_nodal) { ierr = VecDestroy(&user->Qcrit_nodal); CHKERRQ(ierr); }
4237 if (user->Psi_nodal) { ierr = VecDestroy(&user->Psi_nodal); CHKERRQ(ierr); }
4238
4239 // --- Group K: Interpolation Vectors (Lazy allocation) ---
4240 if (user->fieldStatisticsStorage) {
4241 SimCtx *stats_ctx = user->simCtx;
4242 const PetscInt window_count = stats_ctx ? stats_ctx->fieldStatisticsWindowCount : 0;
4243 for (PetscInt w = 0; w < window_count; ++w) {
4244 ierr = PicurvWindowStorageDestroy(&user->fieldStatisticsStorage[w]); CHKERRQ(ierr);
4245 }
4246 ierr = PetscFree(user->fieldStatisticsStorage); CHKERRQ(ierr);
4247 user->fieldStatisticsStorage = NULL;
4248 }
4249 if (user->CellScalarAtCorner) { ierr = VecDestroy(&user->CellScalarAtCorner); CHKERRQ(ierr); }
4250 if (user->lCellScalarAtCorner) { ierr = VecDestroy(&user->lCellScalarAtCorner); CHKERRQ(ierr); }
4251 if (user->CellVectorAtCorner) { ierr = VecDestroy(&user->CellVectorAtCorner); CHKERRQ(ierr); }
4252 if (user->PostScalar) { ierr = VecDestroy(&user->PostScalar); CHKERRQ(ierr); }
4253 if (user->lPostScalar) { ierr = VecDestroy(&user->lPostScalar); CHKERRQ(ierr); }
4254 if (user->PostScalarNodal) { ierr = VecDestroy(&user->PostScalarNodal); CHKERRQ(ierr); }
4255 if (user->PostVector) { ierr = VecDestroy(&user->PostVector); CHKERRQ(ierr); }
4256 if (user->lPostVector) { ierr = VecDestroy(&user->lPostVector); CHKERRQ(ierr); }
4257 if (user->PostVectorNodal) { ierr = VecDestroy(&user->PostVectorNodal); CHKERRQ(ierr); }
4258 if (user->lCellVectorAtCorner) { ierr = VecDestroy(&user->lCellVectorAtCorner); CHKERRQ(ierr); }
4259
4260 // --- Group L: Implicit Solver Temporary Vectors (Destroyed after use, but check anyway) ---
4261 if (user->Rhs) { ierr = VecDestroy(&user->Rhs); CHKERRQ(ierr); }
4262 if (user->dUcont) { ierr = VecDestroy(&user->dUcont); CHKERRQ(ierr); }
4263 if (user->pUcont) { ierr = VecDestroy(&user->pUcont); CHKERRQ(ierr); }
4264
4265 // --- Group M: Poisson Solver Vectors (kept for the run by PoissonSolver_Multigrid) ---
4266 if (user->B) { ierr = VecDestroy(&user->B); CHKERRQ(ierr); }
4267 if (user->R) { ierr = VecDestroy(&user->R); CHKERRQ(ierr); }
4268
4269 LOG_ALLOW(LOCAL, LOG_DEBUG, "All vectors destroyed for UserCtx.\n");
4270 PetscFunctionReturn(0);
4271}
PetscErrorCode PicurvWindowStorageDestroy(PicurvWindowStorage *storage)
Releases accumulator state previously created for one window.
Vec pUcont
Definition variables.h:1121
Vec dUcont
Definition variables.h:1121
Here is the call graph for this function:
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, MR, MP, ksp, nullsp)
  4. Application ordering (AO)
  5. Distributed mesh objects (DMs) - most derived first
  6. Raw PetscMalloc'd arrays (RankCellInfoMap)

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 4278 of file setup.c.

4279{
4280 PetscErrorCode ierr;
4281 PetscFunctionBeginUser;
4282
4283 if (!user) {
4284 LOG_ALLOW(LOCAL, LOG_WARNING, "DestroyUserContext called with NULL user pointer.\n");
4285 PetscFunctionReturn(0);
4286 }
4287
4288 LOG_ALLOW(LOCAL, LOG_INFO, "Destroying UserCtx at level %d...\n", user->thislevel);
4289
4290 // --- Step 1: Destroy Boundary Condition System ---
4291 // This handles all BC handlers and their private data.
4292 ierr = BoundarySystem_Destroy(user); CHKERRQ(ierr);
4293 LOG_ALLOW(LOCAL, LOG_DEBUG, " Boundary system destroyed.\n");
4294
4295 // --- Step 2: Destroy All Vectors ---
4296 // Handles ~74 Vec objects with proper NULL checking.
4297 ierr = DestroyUserVectors(user); CHKERRQ(ierr);
4298 LOG_ALLOW(LOCAL, LOG_DEBUG, " All vectors destroyed.\n");
4299
4300 // --- Step 3: Destroy Matrix and Solver Objects ---
4301 // Destroy pressure-Poisson matrices and solver.
4302 if (user->A) {
4303 ierr = MatDestroy(&user->A); CHKERRQ(ierr);
4304 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix A destroyed.\n");
4305 }
4306 if (user->MR) {
4307 ierr = MatDestroy(&user->MR); CHKERRQ(ierr);
4308 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix MR destroyed.\n");
4309 }
4310 if (user->MP) {
4311 ierr = MatDestroy(&user->MP); CHKERRQ(ierr);
4312 LOG_ALLOW(LOCAL, LOG_DEBUG, " Matrix MP destroyed.\n");
4313 }
4314 if (user->ksp) {
4315 ierr = KSPDestroy(&user->ksp); CHKERRQ(ierr);
4316 LOG_ALLOW(LOCAL, LOG_DEBUG, " KSP solver destroyed.\n");
4317 }
4318 if (user->nullsp) {
4319 ierr = MatNullSpaceDestroy(&user->nullsp); CHKERRQ(ierr);
4320 LOG_ALLOW(LOCAL, LOG_DEBUG, " MatNullSpace destroyed.\n");
4321 }
4322
4323 // --- Step 4: Destroy Application Ordering ---
4324 if (user->ao) {
4325 ierr = AODestroy(&user->ao); CHKERRQ(ierr);
4326 LOG_ALLOW(LOCAL, LOG_DEBUG, " AO destroyed.\n");
4327 }
4328
4329 // --- Step 5: Destroy DM Objects ---
4330 // Destroy in reverse order of dependency: post_swarm, swarm, fda6, fda, da
4331 if (user->post_swarm) {
4332 ierr = DMDestroy(&user->post_swarm); CHKERRQ(ierr);
4333 LOG_ALLOW(LOCAL, LOG_DEBUG, " post_swarm DM destroyed.\n");
4334 }
4335 if (user->swarm) {
4336 ierr = DMDestroy(&user->swarm); CHKERRQ(ierr);
4337 LOG_ALLOW(LOCAL, LOG_DEBUG, " swarm DM destroyed.\n");
4338 }
4339 if (user->fda6) {
4340 ierr = DMDestroy(&user->fda6); CHKERRQ(ierr);
4341 LOG_ALLOW(LOCAL, LOG_DEBUG, " fda6 DM destroyed.\n");
4342 }
4343 if (user->da) {
4344 ierr = DMDestroy(&user->da); CHKERRQ(ierr);
4345 LOG_ALLOW(LOCAL, LOG_DEBUG, " da DM destroyed.\n");
4346 }
4347
4348 // --- Step 6: Free PetscMalloc'd Arrays ---
4349 // Free arrays allocated with PetscMalloc1
4350 if (user->RankCellInfoMap) {
4351 ierr = PetscFree(user->RankCellInfoMap); CHKERRQ(ierr);
4352 user->RankCellInfoMap = NULL;
4353 LOG_ALLOW(LOCAL, LOG_DEBUG, " RankCellInfoMap freed.\n");
4354 }
4355
4356 LOG_ALLOW(LOCAL, LOG_INFO, "UserCtx at level %d fully destroyed.\n", user->thislevel);
4357 PetscFunctionReturn(0);
4358}
PetscErrorCode BoundarySystem_Destroy(UserCtx *user)
Cleans up and destroys all boundary system resources.
PetscErrorCode DestroyUserVectors(UserCtx *user)
Internal helper implementation: DestroyUserVectors().
Definition setup.c:4128
MatNullSpace nullsp
Definition variables.h:1142
DM post_swarm
Definition variables.h:1175
PetscInt thislevel
Definition variables.h:1165
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 4368 of file setup.c.

4369{
4370 PetscErrorCode ierr;
4371 PetscFunctionBeginUser;
4372
4373 if (!simCtx) {
4374 LOG_ALLOW(GLOBAL, LOG_WARNING, "FinalizeSimulation called with NULL SimCtx pointer.\n");
4375 PetscFunctionReturn(0);
4376 }
4377
4378 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
4379 LOG_ALLOW(GLOBAL, LOG_INFO, "Beginning simulation memory cleanup...\n");
4380 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
4381
4382 // ============================================================================
4383 // PHASE 1: DESTROY MULTIGRID HIERARCHY (All UserCtx structures)
4384 // ============================================================================
4385
4386 ierr = DestroySolutionConvergenceState(simCtx); CHKERRQ(ierr);
4387 ierr = DestroyFieldStatisticsConfig(simCtx); CHKERRQ(ierr);
4388 ierr = ParticleFieldPlanDestroy(&simCtx->particleFieldPlan); CHKERRQ(ierr);
4389
4390 if (simCtx->usermg.mgctx) {
4391 LOG_ALLOW(GLOBAL, LOG_INFO, "Destroying multigrid hierarchy (%d levels)...\n",
4392 simCtx->usermg.mglevels);
4393
4394 // Destroy each UserCtx from finest to coarsest (reverse order is safer)
4395 for (PetscInt level = simCtx->usermg.mglevels - 1; level >= 0; level--) {
4396 UserCtx *user = simCtx->usermg.mgctx[level].user;
4397 if (user) {
4398 LOG_ALLOW(LOCAL, LOG_INFO, " Destroying level %d of %d...\n",
4399 level, simCtx->usermg.mglevels - 1);
4400 ierr = DestroyUserContext(user); CHKERRQ(ierr);
4401
4402 // Free the UserCtx structure itself
4403 ierr = PetscFree(user); CHKERRQ(ierr);
4404 simCtx->usermg.mgctx[level].user = NULL;
4405 }
4406
4407 // Destroy the MGCtx-level packer DM
4408 if (simCtx->usermg.mgctx[level].packer) {
4409 ierr = DMDestroy(&simCtx->usermg.mgctx[level].packer); CHKERRQ(ierr);
4410 LOG_ALLOW(LOCAL, LOG_DEBUG, " MGCtx[%d].packer destroyed.\n", level);
4411 }
4412 }
4413
4414 // Free the MGCtx array itself
4415 ierr = PetscFree(simCtx->usermg.mgctx); CHKERRQ(ierr);
4416 simCtx->usermg.mgctx = NULL;
4417 LOG_ALLOW(GLOBAL, LOG_INFO, "All multigrid levels destroyed.\n");
4418 }
4419
4420 // ============================================================================
4421 // PHASE 2: DESTROY USERMG-LEVEL OBJECTS
4422 // ============================================================================
4423
4424 if (simCtx->usermg.packer) {
4425 ierr = DMDestroy(&simCtx->usermg.packer); CHKERRQ(ierr);
4426 LOG_ALLOW(LOCAL, LOG_DEBUG, "UserMG.packer DM destroyed.\n");
4427 }
4428
4429 if (simCtx->usermg.snespacker) {
4430 ierr = SNESDestroy(&simCtx->usermg.snespacker); CHKERRQ(ierr);
4431 LOG_ALLOW(LOCAL, LOG_DEBUG, "UserMG.snespacker SNES destroyed.\n");
4432 }
4433
4434 // ============================================================================
4435 // PHASE 3: DESTROY SIMCTX-LEVEL OBJECTS
4436 // ============================================================================
4437
4438 LOG_ALLOW(GLOBAL, LOG_INFO, "Destroying SimCtx-level objects...\n");
4439
4440 // --- PetscViewer for logging ---
4441 if (simCtx->logviewer) {
4442 ierr = PetscViewerDestroy(&simCtx->logviewer); CHKERRQ(ierr);
4443 LOG_ALLOW(LOCAL, LOG_DEBUG, " logviewer destroyed.\n");
4444 }
4445
4446 // --- Particle System DM ---
4447 if (simCtx->dm_swarm) {
4448 ierr = DMDestroy(&simCtx->dm_swarm); CHKERRQ(ierr);
4449 LOG_ALLOW(LOCAL, LOG_DEBUG, " dm_swarm destroyed.\n");
4450 }
4451
4452 // --- BoundingBox List (Array of BoundingBox structs) ---
4453 if (simCtx->bboxlist) {
4454 ierr = PetscFree(simCtx->bboxlist); CHKERRQ(ierr);
4455 simCtx->bboxlist = NULL;
4456 LOG_ALLOW(LOCAL, LOG_DEBUG, " bboxlist freed.\n");
4457 }
4458
4459 // --- Boundary Condition Files (Array of strings) ---
4460 if (simCtx->bcs_files) {
4461 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
4462 if (simCtx->bcs_files[i]) {
4463 ierr = PetscFree(simCtx->bcs_files[i]); CHKERRQ(ierr);
4464 }
4465 }
4466 ierr = PetscFree(simCtx->bcs_files); CHKERRQ(ierr);
4467 simCtx->bcs_files = NULL;
4468 LOG_ALLOW(LOCAL, LOG_DEBUG, " bcs_files array freed (%d files).\n", simCtx->num_bcs_files);
4469 }
4470
4471 // --- Brownian Motion RNG ---
4472 if (simCtx->BrownianMotionRNG) {
4473 ierr = PetscRandomDestroy(&simCtx->BrownianMotionRNG); CHKERRQ(ierr);
4474 LOG_ALLOW(LOCAL, LOG_DEBUG, " BrownianMotionRNG destroyed.\n");
4475 }
4476 // --- Post-Processing Parameters ---
4477 // pps is allocated with PetscNew and contains only static char arrays and basic types.
4478 // No internal dynamic allocations need to be freed.
4479 if (simCtx->pps) {
4480 ierr = PetscFree(simCtx->pps); CHKERRQ(ierr);
4481 simCtx->pps = NULL;
4482 LOG_ALLOW(LOCAL, LOG_DEBUG, " PostProcessParams freed.\n");
4483 }
4484
4485 // --- IBM/FSI Objects ---
4486 // Note: These are initialized to NULL and currently have no dedicated destroy functions.
4487 // If these modules are extended with cleanup routines, call them here.
4488 if (simCtx->ibm != NULL) {
4489 LOG_ALLOW(GLOBAL, LOG_WARNING, " WARNING: simCtx->ibm is non-NULL but no destroy function exists. Potential memory leak.\n");
4490 }
4491 if (simCtx->ibmv != NULL) {
4492 LOG_ALLOW(GLOBAL, LOG_WARNING, " WARNING: simCtx->ibmv is non-NULL but no destroy function exists. Potential memory leak.\n");
4493 }
4494 if (simCtx->fsi != NULL) {
4495 LOG_ALLOW(GLOBAL, LOG_WARNING, " WARNING: simCtx->fsi is non-NULL but no destroy function exists. Potential memory leak.\n");
4496 }
4497
4498 // --- Logging Allowed Functions (Array of strings) ---
4499 // Note: The logging system maintains its own copy via set_allowed_functions(),
4500 // so freeing simCtx->allowedFuncs will NOT affect LOG_ALLOW functionality.
4501 if (simCtx->allowedFuncs) {
4502 for (PetscInt i = 0; i < simCtx->nAllowed; i++) {
4503 if (simCtx->allowedFuncs[i]) {
4504 ierr = PetscFree(simCtx->allowedFuncs[i]); CHKERRQ(ierr);
4505 }
4506 }
4507 ierr = PetscFree(simCtx->allowedFuncs); CHKERRQ(ierr);
4508 simCtx->allowedFuncs = NULL;
4509 LOG_ALLOW(LOCAL, LOG_DEBUG, " allowedFuncs array freed (%d functions).\n", simCtx->nAllowed);
4510 }
4511
4512 // --- Profiling Critical Functions (Array of strings) ---
4513 if (simCtx->profilingSelectedFuncs) {
4514 for (PetscInt i = 0; i < simCtx->nProfilingSelectedFuncs; i++) {
4515 if (simCtx->profilingSelectedFuncs[i]) {
4516 ierr = PetscFree(simCtx->profilingSelectedFuncs[i]); CHKERRQ(ierr);
4517 }
4518 }
4519 ierr = PetscFree(simCtx->profilingSelectedFuncs); CHKERRQ(ierr);
4520 simCtx->profilingSelectedFuncs = NULL;
4521 LOG_ALLOW(LOCAL, LOG_DEBUG, " profilingSelectedFuncs array freed (%d functions).\n", simCtx->nProfilingSelectedFuncs);
4522 }
4523
4524 // ============================================================================
4525 // PHASE 4: FINAL SUMMARY
4526 // ============================================================================
4527
4528 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
4529 LOG_ALLOW(GLOBAL, LOG_INFO, "Simulation cleanup completed successfully.\n");
4530 LOG_ALLOW(GLOBAL, LOG_INFO, "All PETSc objects have been destroyed.\n");
4531 LOG_ALLOW(GLOBAL, LOG_INFO, "========================================\n");
4532
4533 ierr = PetscFree(simCtx); CHKERRQ(ierr);
4534 PetscFunctionReturn(0);
4535}
PetscErrorCode ParticleFieldPlanDestroy(ParticleFieldPlan **plan)
Free a plan and its compiled expressions.
PetscErrorCode DestroyUserContext(UserCtx *user)
Internal helper implementation: DestroyUserContext().
Definition setup.c:4278
PetscErrorCode DestroySolutionConvergenceState(SimCtx *simCtx)
Implementation of DestroySolutionConvergenceState().
Definition setup.c:148
PetscErrorCode DestroyFieldStatisticsConfig(SimCtx *simCtx)
Releases the window definitions resolved by ParseFieldStatisticsConfig().
DM packer
Definition variables.h:740
SNES snespacker
Definition variables.h:741
DM packer
Definition variables.h:731
Here is the call graph for this function:
Here is the caller graph for this function: