PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
setup.c File Reference

// Setup code for running any simulation More...

#include "setup.h"
Include dependency graph for setup.c:

Go to the source code of this file.

Macros

#define __FUNCT__   "CreateSimulationContext"
 
#define __FUNCT__   "PetscMkdirRecursive"
 
#define __FUNCT__   "SetupSimulationEnvironment"
 
#define __FUNCT__   "AllocateContextHeirarchy"
 
#define __FUNCT__   "SetupSolverParameters"
 
#define __FUNCT__   "SetupGridAndSolvers"
 
#define __FUNCT__   "CreateAndInitializeAllVectors"
 
#define __FUNCT__   "UpdateLocalGhosts"
 
#define __FUNCT__   "SetupBoundaryConditions"
 
#define __FUNCT__   "GetOwnedCellRange"
 
#define __FUNCT__   "ComputeAndStoreNeighborRanks"
 
#define __FUNCT__   "SetDMDAProcLayout"
 
#define __FUNCT__   "SetupDomainRankInfo"
 
#define __FUNCT__   "Contra2Cart"
 
#define __FUNCT__   "SetupDomainCellDecompositionMap"
 
#define __FUNCT__   "BinarySearchInt64"
 
#define __FUNCT__   "ComputeDivergence"
 
#define __FUNCT__   "InitializeRandomGenerators"
 
#define __FUNCT__   "InitializeLogicalSpaceRNGs"
 
#define __FUNCT__   "ComputeVectorFieldDerivatives"
 

Functions

PetscErrorCode CreateSimulationContext (int argc, char **argv, SimCtx **p_simCtx)
 Allocates and populates the master SimulationContext object.
 
static PetscErrorCode PetscMkdirRecursive (const char *path)
 Creates a directory path recursively, similar to mkdir -p.
 
PetscErrorCode SetupSimulationEnvironment (SimCtx *simCtx)
 Verifies and prepares the complete I/O environment for a simulation run.
 
static PetscErrorCode AllocateContextHierarchy (SimCtx *simCtx)
 Allocates the memory for the UserMG and UserCtx hierarchy.
 
static PetscErrorCode SetupSolverParameters (SimCtx *simCtx)
 
PetscErrorCode SetupGridAndSolvers (SimCtx *simCtx)
 The main orchestrator for setting up all grid-related components.
 
PetscErrorCode CreateAndInitializeAllVectors (SimCtx *simCtx)
 Creates and initializes all PETSc Vec objects for all fields.
 
PetscErrorCode UpdateLocalGhosts (UserCtx *user, const char *fieldName)
 Updates the local vector (including ghost points) from its corresponding global vector.
 
PetscErrorCode SetupBoundaryConditions (SimCtx *simCtx)
 (Orchestrator) Sets up all boundary conditions for the simulation.
 
PetscErrorCode 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 3D array of Cmpnts structures using PetscCalloc.
 
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)
 Gets the global starting index of cells owned by this rank and the number of such cells.
 
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 for all blocks.
 
PetscErrorCode Contra2Cart (UserCtx *user)
 Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on cell faces.
 
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.
 
static PetscInt Gidx (PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
 
PetscErrorCode ComputeDivergence (UserCtx *user)
 
PetscErrorCode InitializeRandomGenerators (UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
 Initializes random number generators for assigning particle properties.
 
PetscErrorCode InitializeLogicalSpaceRNGs (PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
 Initializes random number generators for logical space operations [0.0, 1.0).
 
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)
 Transforms derivatives from computational space to physical space using the chain rule.
 
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.
 

Detailed Description

// Setup code for running any simulation

Test program for DMSwarm interpolation using the fdf-curvIB method. Provides the setup to start any simulation with DMSwarm and DMDAs.

Definition in file setup.c.

Macro Definition Documentation

◆ __FUNCT__ [1/20]

#define __FUNCT__   "CreateSimulationContext"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [2/20]

#define __FUNCT__   "PetscMkdirRecursive"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [3/20]

#define __FUNCT__   "SetupSimulationEnvironment"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [4/20]

#define __FUNCT__   "AllocateContextHeirarchy"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [5/20]

#define __FUNCT__   "SetupSolverParameters"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [6/20]

#define __FUNCT__   "SetupGridAndSolvers"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [7/20]

#define __FUNCT__   "CreateAndInitializeAllVectors"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [8/20]

#define __FUNCT__   "UpdateLocalGhosts"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [9/20]

#define __FUNCT__   "SetupBoundaryConditions"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [10/20]

#define __FUNCT__   "GetOwnedCellRange"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [11/20]

#define __FUNCT__   "ComputeAndStoreNeighborRanks"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [12/20]

#define __FUNCT__   "SetDMDAProcLayout"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [13/20]

#define __FUNCT__   "SetupDomainRankInfo"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [14/20]

#define __FUNCT__   "Contra2Cart"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [15/20]

#define __FUNCT__   "SetupDomainCellDecompositionMap"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [16/20]

#define __FUNCT__   "BinarySearchInt64"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [17/20]

#define __FUNCT__   "ComputeDivergence"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [18/20]

#define __FUNCT__   "InitializeRandomGenerators"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [19/20]

#define __FUNCT__   "InitializeLogicalSpaceRNGs"

Definition at line 10 of file setup.c.

◆ __FUNCT__ [20/20]

#define __FUNCT__   "ComputeVectorFieldDerivatives"

Definition at line 10 of file setup.c.

Function Documentation

◆ CreateSimulationContext()

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

Allocates and populates the master SimulationContext object.

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

The function follows a strict sequence:

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

Definition at line 44 of file setup.c.

45{
46 PetscErrorCode ierr;
47 SimCtx *simCtx;
48 char control_filename[PETSC_MAX_PATH_LEN] = ""; // Temporary placeholder for control file name.
49 PetscBool control_flg; // Temporary placeholder for control file tag existence check flag.
50
51 PetscFunctionBeginUser;
52
54
55 // === 1. Allocate the Context Struct and Set ALL Defaults ==================
56 ierr = PetscNew(p_simCtx); CHKERRQ(ierr);
57 simCtx = *p_simCtx;
58
59 // --- Group 1: Parallelism & MPI ---
60 simCtx->rank = 0; simCtx->size = 1;
61
62 // --- Group 2: Simulation Control, Time, and I/O ---
63 simCtx->step = 0; simCtx->ti = 0.0; simCtx->StartStep = 0; simCtx->StepsToRun = 10;
64 simCtx->tiout = 10; simCtx->StartTime = 0.0; simCtx->dt = 0.001;
65 simCtx->OnlySetup = PETSC_FALSE;
66 simCtx->logviewer = NULL; simCtx->OutputFreq = simCtx->tiout;
67 strcpy(simCtx->eulerianSource,"solve");
68 strcpy(simCtx->restart_dir,"results");
69 strcpy(simCtx->output_dir,"results");
70 strcpy(simCtx->log_dir,"logs");
71 strcpy(simCtx->euler_subdir,"eulerian");
72 strcpy(simCtx->particle_subdir,"particles");
73 simCtx->_io_context_buffer[0] = '\0';
74 simCtx->current_io_directory = NULL;
75
76 // --- Group 3: High-Level Physics & Model Selection Flags ---
77 simCtx->immersed = 0; simCtx->movefsi = 0; simCtx->rotatefsi = 0;
78 simCtx->sediment = 0; simCtx->rheology = 0; simCtx->invicid = 0;
79 simCtx->TwoD = 0; simCtx->thin = 0; simCtx->moveframe = 0;
80 simCtx->rotateframe = 0; simCtx->blank = 0;
81 simCtx->dgf_x = 0; simCtx->dgf_y = 1; simCtx->dgf_z = 0;
82 simCtx->dgf_ax = 1; simCtx->dgf_ay = 0; simCtx->dgf_az = 0;
83 simCtx->st = 1.0;
84
85 // --- Group 4: Specific Simulation Case Flags --- (DEPRICATED)
86 simCtx->cop=0; simCtx->fish=0; simCtx->fish_c=0; simCtx->fishcyl=0;
87 simCtx->eel=0; simCtx->pizza=0; simCtx->turbine=0; simCtx->Pipe=0;
88 simCtx->wing=0; simCtx->hydro=0; simCtx->MHV=0; simCtx->LV=0;
89
90 // --- Group 5: Solver & Numerics Parameters ---
91 simCtx->implicit = 0; simCtx->implicit_type = 0; simCtx->imp_MAX_IT = 50;
92 simCtx->imp_atol = 1e-7; simCtx->imp_rtol = 1e-4; simCtx->imp_stol = 1.e-8;
93 simCtx->mglevels = 3; simCtx->mg_MAX_IT = 30; simCtx->mg_idx = 1;
94 simCtx->mg_preItr = 1; simCtx->mg_poItr = 1;
95 simCtx->poisson = 0; simCtx->poisson_tol = 5.e-9;
96 simCtx->STRONG_COUPLING = 0;simCtx->central=0;
97 simCtx->ren = 100.0; simCtx->cfl = 0.1; simCtx->vnn = 0.1;
98 simCtx->cdisx = 0.0; simCtx->cdisy = 0.0; simCtx->cdisz = 0.0;
99 simCtx->FieldInitialization = 0;
100 simCtx->InitialConstantContra.x = 0.0;
101 simCtx->InitialConstantContra.y = 0.0;
102 simCtx->InitialConstantContra.z = 0.0;
103
104 // --- Group 6: Physical & Geometric Parameters ---
105 simCtx->NumberOfBodies = 1; simCtx->Flux_in = 1.0; simCtx->angle = 0.0;
106 simCtx->max_angle = -54. * 3.1415926 / 180.;
107 simCtx->CMx_c=0.0; simCtx->CMy_c=0.0; simCtx->CMz_c=0.0;
108
109 // --- Group 7: Grid, Domain, and Boundary Condition Settings ---
110 simCtx->block_number = 1; simCtx->inletprofile = 1;
111 simCtx->grid1d = 0; simCtx->Ogrid = 0; simCtx->channelz = 0;
112 simCtx->i_periodic = 0; simCtx->j_periodic = 0; simCtx->k_periodic = 0;
113 simCtx->blkpbc = 10; simCtx->pseudo_periodic = 0;
114 strcpy(simCtx->grid_file, "config/grid.run");
115 simCtx->generate_grid = PETSC_FALSE;
116 simCtx->da_procs_x = PETSC_DECIDE;
117 simCtx->da_procs_y = PETSC_DECIDE;
118 simCtx->da_procs_z = PETSC_DECIDE;
119 simCtx->grid_rotation_angle = 0.0;
120 simCtx->Croty = 0.0; simCtx->Crotz = 0.0;
121 simCtx->num_bcs_files = 1;
122 ierr = PetscMalloc1(1, &simCtx->bcs_files); CHKERRQ(ierr);
123 ierr = PetscStrallocpy("config/bcs.run", &simCtx->bcs_files[0]); CHKERRQ(ierr);
124 simCtx->FluxInSum = 0.0; simCtx->FluxOutSum = 0.0; simCtx->Fluxsum = 0.0;
125 simCtx->AreaInSum = 0.0; simCtx->AreaOutSum = 0.0;
126 simCtx->U_bc = 0.0; simCtx->ccc = 0;
127 simCtx->ratio = 0.0;
128
129
130 // --- Group 8: Turbulence Modeling (LES/RANS) ---
131 simCtx->averaging = PETSC_FALSE; simCtx->les = 0; simCtx->rans = 0;
132 simCtx->wallfunction = 0; simCtx->mixed = 0; simCtx->clark = 0;
133 simCtx->dynamic_freq = 1; simCtx->max_cs = 0.5;
134 simCtx->Const_CS = 0.03;
135 simCtx->testfilter_ik = 0; simCtx->testfilter_1d = 0;
136 simCtx->i_homo_filter = 0; simCtx->j_homo_filter = 0; simCtx->k_homo_filter = 0;
137
138 // --- Group 9: Particle / DMSwarm Data & Settings ---
139 simCtx->np = 0; simCtx->readFields = PETSC_FALSE;
140 simCtx->dm_swarm = NULL; simCtx->bboxlist = NULL;
141 simCtx->ParticleInitialization = 0;
142 strcpy(simCtx->particleRestartMode,"load");
143
144 // --- Group 10: Immersed Boundary & FSI Data Object Pointers ---
145 simCtx->ibm = NULL; simCtx->ibmv = NULL; simCtx->fsi = NULL;
146 simCtx->rstart_fsi = PETSC_FALSE; simCtx->duplicate = 0;
147
148 // --- Group 11: Logging and Custom Configuration ---
149 strcpy(simCtx->allowedFile, "config/whitelist.run");
150 simCtx->useCfg = PETSC_FALSE;
151 simCtx->allowedFuncs = NULL;
152 simCtx->nAllowed = 0;
153 simCtx->LoggingFrequency = 10;
154 simCtx->summationRHS = 0.0;
155 simCtx->MaxDiv = 0.0;
156 simCtx->MaxDivFlatArg = 0; simCtx->MaxDivx = 0; simCtx->MaxDivy = 0; simCtx->MaxDivz = 0;
157 strcpy(simCtx->criticalFuncsFile, "config/profile.run");
158 simCtx->useCriticalFuncsCfg = PETSC_FALSE;
159 simCtx->criticalFuncs = NULL;
160 simCtx->nCriticalFuncs = 0;
161 // --- Group 11: Post-Processing Information ---
162 strcpy(simCtx->PostprocessingControlFile, "config/post.run");
163 ierr = PetscNew(&simCtx->pps); CHKERRQ(ierr);
164
165 // === 2. Get MPI Info and Handle Config File =============================
166 // -- Group 1: Parallelism & MPI Information
167 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &simCtx->rank); CHKERRQ(ierr);
168 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &simCtx->size); CHKERRQ(ierr);
169
170 // First, check if the -control_file argument was provided by the user/script.
171 ierr = PetscOptionsGetString(NULL, NULL, "-control_file", control_filename, sizeof(control_filename), &control_flg); CHKERRQ(ierr);
172
173 // If the flag is NOT present or the filename is empty, abort with a helpful error.
174 if (!control_flg || strlen(control_filename) == 0) {
175 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
176 "\n\n*** MANDATORY ARGUMENT MISSING ***\n"
177 "The -control_file argument was not provided.\n"
178 "This program must be launched with a configuration file.\n"
179 "Example: mpiexec -n 4 ./picsolver -control_file /path/to/your/config.control\n"
180 "This is typically handled automatically by the 'pic-flow' script.\n");
181 }
182
183 // At this point, we have a valid filename. Attempt to load it.
184 LOG(GLOBAL, LOG_INFO, "Loading mandatory configuration from: %s\n", control_filename);
185 ierr = PetscOptionsInsertFile(PETSC_COMM_WORLD, NULL, control_filename, PETSC_FALSE);
186 if (ierr == PETSC_ERR_FILE_OPEN) {
187 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_FILE_OPEN, "The specified control file was not found or could not be opened: %s", control_filename);
188 }
189 CHKERRQ(ierr);
190
191 // === 3. A Configure Logging System ========================================
192 // This logic determines the logging configuration and STORES it in simCtx for
193 // later reference and cleanup.
194 ierr = PetscOptionsGetString(NULL, NULL, "-whitelist_config_file", simCtx->allowedFile, PETSC_MAX_PATH_LEN, &simCtx->useCfg); CHKERRQ(ierr);
195
196 if (simCtx->useCfg) {
197 ierr = LoadAllowedFunctionsFromFile(simCtx->allowedFile, &simCtx->allowedFuncs, &simCtx->nAllowed);
198 if (ierr) {
199 // Use direct PetscPrintf as logging system isn't fully active yet.
200 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Failed to load allowed functions from '%s'. Falling back to default list.\n", __func__, simCtx->allowedFile);
201 simCtx->useCfg = PETSC_FALSE; // Mark as failed.
202 ierr = 0; // Clear the error to allow fallback.
203 }
204 }
205 if (!simCtx->useCfg) {
206 // Fallback to default logging functions if no file was used or if loading failed.
207 simCtx->nAllowed = 2;
208 ierr = PetscMalloc1(simCtx->nAllowed, &simCtx->allowedFuncs); CHKERRQ(ierr);
209 ierr = PetscStrallocpy("main", &simCtx->allowedFuncs[0]); CHKERRQ(ierr);
210 ierr = PetscStrallocpy("CreateSimulationContext", &simCtx->allowedFuncs[1]); CHKERRQ(ierr);
211 }
212
213 // Activate the configuration by passing it to the logging module's setup function.
214 set_allowed_functions((const char**)simCtx->allowedFuncs, (size_t)simCtx->nAllowed);
215
216 // Now that the logger is configured, we can use it.
217 LOG_ALLOW_SYNC(LOCAL, LOG_INFO, "Context created. Initializing on rank %d of %d.\n", simCtx->rank, simCtx->size);
218 print_log_level(); // This will now correctly reflect the LOG_LEVEL environment variable.
219
220 // === 3.B Configure Profiling System ========================================
221 ierr = PetscOptionsGetString(NULL, NULL, "-profile_config_file", simCtx->criticalFuncsFile, PETSC_MAX_PATH_LEN, &simCtx->useCriticalFuncsCfg); CHKERRQ(ierr);
222 if (simCtx->useCriticalFuncsCfg) {
224 if (ierr) {
225 PetscPrintf(PETSC_COMM_SELF, "[%s] WARNING: Failed to load critical profiling functions from '%s'. Falling back to default list.\n", __func__, simCtx->criticalFuncsFile);
226 simCtx->useCriticalFuncsCfg = PETSC_FALSE;
227 ierr = 0;
228 }
229 }
230 if (!simCtx->useCriticalFuncsCfg) {
231 // Fallback to a hardcoded default list if no file or loading failed
232 simCtx->nCriticalFuncs = 4;
233 ierr = PetscMalloc1(simCtx->nCriticalFuncs, &simCtx->criticalFuncs); CHKERRQ(ierr);
234 ierr = PetscStrallocpy("FlowSolver", &simCtx->criticalFuncs[0]); CHKERRQ(ierr);
235 ierr = PetscStrallocpy("AdvanceSimulation", &simCtx->criticalFuncs[1]); CHKERRQ(ierr);
236 ierr = PetscStrallocpy("LocateAllParticlesInGrid", &simCtx->criticalFuncs[2]); CHKERRQ(ierr);
237 ierr = PetscStrallocpy("InterpolateAllFieldsToSwarm", &simCtx->criticalFuncs[3]); CHKERRQ(ierr);
238 }
239
240 // Initialize the profiling system with the current updated simulation context.
241 ierr = ProfilingInitialize(simCtx); CHKERRQ(ierr);
242
243 // === 4. Parse All Command Line Options ==================================
244 LOG_ALLOW(GLOBAL, LOG_INFO, "Parsing command-line options...\n");
245
246 // --- Group 2
247 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 2: Simulation Control,Time and I/O.\n");
248 // Read the physical time to start from.
249 // The default is already 0.0, so this will only be non-zero if the user provides it.
250 ierr = PetscOptionsGetInt(NULL, NULL, "-start_step", &simCtx->StartStep, NULL); CHKERRQ(ierr);
251 ierr = PetscOptionsGetInt(NULL,NULL, "-totalsteps", &simCtx->StepsToRun, NULL); CHKERRQ(ierr);
252 ierr = PetscOptionsGetBool(NULL, NULL, "-only_setup", &simCtx->OnlySetup, NULL); CHKERRQ(ierr);
253 ierr = PetscOptionsGetReal(NULL, NULL, "-dt", &simCtx->dt, NULL); CHKERRQ(ierr);
254 ierr = PetscOptionsGetInt(NULL, NULL, "-tio", &simCtx->tiout, NULL); CHKERRQ(ierr);
255 ierr = PetscOptionsGetString(NULL,NULL,"-euler_field_source",simCtx->eulerianSource,64,NULL);CHKERRQ(ierr);
256 ierr = PetscOptionsGetString(NULL,NULL,"-output_dir",&simCtx->output_dir,sizeof(simCtx->output_dir),NULL);CHKERRQ(ierr);
257 ierr = PetscOptionsGetString(NULL,NULL,"-restart_dir",&simCtx->restart_dir,sizeof(simCtx->restart_dir),NULL);CHKERRQ(ierr);
258 ierr = PetscOptionsGetString(NULL,NULL,"-log_dir",&simCtx->log_dir,sizeof(simCtx->log_dir),NULL);CHKERRQ(ierr);
259 ierr = PetscOptionsGetString(NULL,NULL,"-euler_subdir",&simCtx->euler_subdir,sizeof(simCtx->euler_subdir),NULL);CHKERRQ(ierr);
260 ierr = PetscOptionsGetString(NULL,NULL,"-particle_subdir",&simCtx->particle_subdir,sizeof(simCtx->particle_subdir),NULL);CHKERRQ(ierr);
261
262 simCtx->OutputFreq = simCtx->tiout; // backward compatibility related redundancy.
263 if(strcmp(simCtx->eulerianSource,"solve")!= 0 && strcmp(simCtx->eulerianSource,"load") != 0){
264 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Invalid value for -euler_field_source. Must be 'load' or 'solve'. You provided '%s'.",simCtx->eulerianSource);
265 }
266
267 // --- Group 3
268 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 3: High-Level Physics & Model Selection Flags\n");
269 ierr = PetscOptionsGetInt(NULL, NULL, "-imm", &simCtx->immersed, NULL); CHKERRQ(ierr);
270 ierr = PetscOptionsGetInt(NULL, NULL, "-fsi", &simCtx->movefsi, NULL); CHKERRQ(ierr);
271 ierr = PetscOptionsGetInt(NULL, NULL, "-rfsi", &simCtx->rotatefsi, NULL); CHKERRQ(ierr);
272 ierr = PetscOptionsGetInt(NULL, NULL, "-sediment", &simCtx->sediment, NULL); CHKERRQ(ierr);
273 ierr = PetscOptionsGetInt(NULL, NULL, "-rheology", &simCtx->rheology, NULL); CHKERRQ(ierr);
274 ierr = PetscOptionsGetInt(NULL, NULL, "-inv", &simCtx->invicid, NULL); CHKERRQ(ierr);
275 ierr = PetscOptionsGetInt(NULL, NULL, "-TwoD", &simCtx->TwoD, NULL); CHKERRQ(ierr);
276 ierr = PetscOptionsGetInt(NULL, NULL, "-thin", &simCtx->thin, NULL); CHKERRQ(ierr);
277 ierr = PetscOptionsGetInt(NULL, NULL, "-mframe", &simCtx->moveframe, NULL); CHKERRQ(ierr);
278 ierr = PetscOptionsGetInt(NULL, NULL, "-rframe", &simCtx->rotateframe, NULL); CHKERRQ(ierr);
279 ierr = PetscOptionsGetInt(NULL, NULL, "-blk", &simCtx->blank, NULL); CHKERRQ(ierr);
280 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_z", &simCtx->dgf_z, NULL); CHKERRQ(ierr);
281 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_y", &simCtx->dgf_y, NULL); CHKERRQ(ierr);
282 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_x", &simCtx->dgf_x, NULL); CHKERRQ(ierr);
283 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_az", &simCtx->dgf_az, NULL); CHKERRQ(ierr);
284 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_ay", &simCtx->dgf_ay, NULL); CHKERRQ(ierr);
285 ierr = PetscOptionsGetInt(NULL, NULL, "-dgf_ax", &simCtx->dgf_ax, NULL); CHKERRQ(ierr);
286
287 // --- Group 4
288 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 4: Specific Simulation Case Flags \n");
289 ierr = PetscOptionsGetInt(NULL, NULL, "-cop", &simCtx->cop, NULL); CHKERRQ(ierr);
290 ierr = PetscOptionsGetInt(NULL, NULL, "-fish", &simCtx->fish, NULL); CHKERRQ(ierr);
291 ierr = PetscOptionsGetInt(NULL, NULL, "-pizza", &simCtx->pizza, NULL); CHKERRQ(ierr);
292 ierr = PetscOptionsGetInt(NULL, NULL, "-turbine", &simCtx->turbine, NULL); CHKERRQ(ierr);
293 ierr = PetscOptionsGetInt(NULL, NULL, "-fishcyl", &simCtx->fishcyl, NULL); CHKERRQ(ierr);
294 ierr = PetscOptionsGetInt(NULL, NULL, "-eel", &simCtx->eel, NULL); CHKERRQ(ierr);
295 ierr = PetscOptionsGetInt(NULL, NULL, "-cstart", &simCtx->fish_c, NULL); CHKERRQ(ierr);
296 ierr = PetscOptionsGetInt(NULL, NULL, "-wing", &simCtx->wing, NULL); CHKERRQ(ierr);
297 ierr = PetscOptionsGetInt(NULL, NULL, "-mhv", &simCtx->MHV, NULL); CHKERRQ(ierr);
298 ierr = PetscOptionsGetInt(NULL, NULL, "-hydro", &simCtx->hydro, NULL); CHKERRQ(ierr);
299 ierr = PetscOptionsGetInt(NULL, NULL, "-lv", &simCtx->LV, NULL); CHKERRQ(ierr);
300 ierr = PetscOptionsGetInt(NULL, NULL, "-Pipe", &simCtx->Pipe, NULL); CHKERRQ(ierr);
301
302 // --- Group 5
303 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 5: Solver & Numerics Parameters \n");
304 ierr = PetscOptionsGetInt(NULL, NULL, "-imp", &simCtx->implicit, NULL); CHKERRQ(ierr);
305 ierr = PetscOptionsGetInt(NULL, NULL, "-imp_type", &simCtx->implicit_type, NULL); CHKERRQ(ierr);
306 ierr = PetscOptionsGetInt(NULL, NULL, "-imp_MAX_IT", &simCtx->imp_MAX_IT, NULL); CHKERRQ(ierr);
307 ierr = PetscOptionsGetReal(NULL, NULL, "-imp_atol", &simCtx->imp_atol, NULL); CHKERRQ(ierr);
308 ierr = PetscOptionsGetReal(NULL, NULL, "-imp_rtol", &simCtx->imp_rtol, NULL); CHKERRQ(ierr);
309 ierr = PetscOptionsGetReal(NULL, NULL, "-imp_stol", &simCtx->imp_stol, NULL); CHKERRQ(ierr);
310 ierr = PetscOptionsGetInt(NULL, NULL, "-central", &simCtx->central, NULL); CHKERRQ(ierr);
311
312 // --- Multigrid Options ---
313 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_level", &simCtx->mglevels, NULL); CHKERRQ(ierr);
314 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_max_it", &simCtx->mg_MAX_IT, NULL); CHKERRQ(ierr);
315 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_idx", &simCtx->mg_idx, NULL); CHKERRQ(ierr);
316 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_pre_it", &simCtx->mg_preItr, NULL); CHKERRQ(ierr);
317 ierr = PetscOptionsGetInt(NULL, NULL, "-mg_post_it", &simCtx->mg_poItr, NULL); CHKERRQ(ierr);
318
319 // --- Other Solver Options ---
320 ierr = PetscOptionsGetInt(NULL, NULL, "-poisson", &simCtx->poisson, NULL); CHKERRQ(ierr);
321 ierr = PetscOptionsGetReal(NULL, NULL, "-poisson_tol", &simCtx->poisson_tol, NULL); CHKERRQ(ierr);
322 ierr = PetscOptionsGetInt(NULL, NULL, "-str", &simCtx->STRONG_COUPLING, NULL); CHKERRQ(ierr);
323 ierr = PetscOptionsGetReal(NULL, NULL, "-ren", &simCtx->ren, NULL); CHKERRQ(ierr);
324 ierr = PetscOptionsGetReal(NULL, NULL, "-cfl", &simCtx->cfl, NULL); CHKERRQ(ierr);
325 ierr = PetscOptionsGetReal(NULL, NULL, "-vnn", &simCtx->vnn, NULL); CHKERRQ(ierr);
326 ierr = PetscOptionsGetInt(NULL, NULL, "-finit", &simCtx->FieldInitialization, NULL); CHKERRQ(ierr);
327 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_x", &simCtx->InitialConstantContra.x, NULL); CHKERRQ(ierr);
328 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_y", &simCtx->InitialConstantContra.y, NULL); CHKERRQ(ierr);
329 ierr = PetscOptionsGetReal(NULL, NULL, "-ucont_z", &simCtx->InitialConstantContra.z, NULL); CHKERRQ(ierr);
330 // NOTE: cdisx,cdisy,cdisz haven't been parsed, add if necessary.
331
332 // --- Group 6
333 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 6: Physical & Geometric Parameters \n");
334 ierr = PetscOptionsGetInt(NULL, NULL, "-no_of_bodies", &simCtx->NumberOfBodies, NULL); CHKERRQ(ierr);
335 // NOTE: angle is not parsed in the original code, it set programmatically. We will follow that.
336 // NOTE: max_angle is calculated based on other flags (like MHV) in the legacy code.
337 // We will defer that logic to a later setup stage and not parse them directly.
338 // The Scaling Information is calculated here
339 ierr = ParseScalingInformation(simCtx); CHKERRQ(ierr);
340
341 // --- Group 7
342 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 7: Grid, Domain, and Boundary Condition Settings \n");
343 ierr = PetscOptionsGetInt(NULL, NULL, "-nblk", &simCtx->block_number, NULL); CHKERRQ(ierr); // This is also a modern option
344 ierr = PetscOptionsGetInt(NULL, NULL, "-inlet", &simCtx->inletprofile, NULL); CHKERRQ(ierr);
345 ierr = PetscOptionsGetInt(NULL, NULL, "-Ogrid", &simCtx->Ogrid, NULL); CHKERRQ(ierr);
346 // NOTE: channelz was not parsed, likely set programmatically. We will omit its parsing call.
347 ierr = PetscOptionsGetInt(NULL, NULL, "-grid1d", &simCtx->grid1d, NULL); CHKERRQ(ierr);
348 ierr = PetscOptionsGetBool(NULL, NULL, "-grid", &simCtx->generate_grid, NULL); CHKERRQ(ierr);
349 ierr = PetscOptionsGetString(NULL, NULL, "-grid_file", simCtx->grid_file, PETSC_MAX_PATH_LEN, NULL); CHKERRQ(ierr);
350 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_x", &simCtx->da_procs_x, NULL); CHKERRQ(ierr);
351 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_y", &simCtx->da_procs_y, NULL); CHKERRQ(ierr);
352 ierr = PetscOptionsGetInt(NULL, NULL, "-da_processors_z", &simCtx->da_procs_z, NULL); CHKERRQ(ierr);
353 ierr = PetscOptionsGetInt(NULL, NULL, "-i_periodic", &simCtx->i_periodic, NULL); CHKERRQ(ierr);
354 ierr = PetscOptionsGetInt(NULL, NULL, "-j_periodic", &simCtx->j_periodic, NULL); CHKERRQ(ierr);
355 ierr = PetscOptionsGetInt(NULL, NULL, "-k_periodic", &simCtx->k_periodic, NULL); CHKERRQ(ierr);
356 ierr = PetscOptionsGetInt(NULL, NULL, "-pbc_domain", &simCtx->blkpbc, NULL); CHKERRQ(ierr);
357 // NOTE: pseudo_periodic was not parsed. We will omit its parsing call.
358 ierr = PetscOptionsGetReal(NULL, NULL, "-grid_rotation_angle", &simCtx->grid_rotation_angle, NULL); CHKERRQ(ierr);
359 ierr = PetscOptionsGetReal(NULL, NULL, "-Croty", &simCtx->Croty, NULL); CHKERRQ(ierr);
360 ierr = PetscOptionsGetReal(NULL, NULL, "-Crotz", &simCtx->Crotz, NULL); CHKERRQ(ierr);
361 PetscBool bcs_flg;
362 char file_list_str[PETSC_MAX_PATH_LEN * 10]; // Buffer for comma-separated list
363
364 ierr = PetscOptionsGetString(NULL, NULL, "-bcs_files", file_list_str, sizeof(file_list_str), &bcs_flg); CHKERRQ(ierr);
365 ierr = PetscOptionsGetReal(NULL, NULL, "-U_bc", &simCtx->U_bc, NULL); CHKERRQ(ierr);
366
367 if (bcs_flg) {
368 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Found -bcs_files option, overriding default.\n");
369
370 // A. Clean up the default memory we allocated in Phase 1.
371 ierr = PetscFree(simCtx->bcs_files[0]); CHKERRQ(ierr);
372 ierr = PetscFree(simCtx->bcs_files); CHKERRQ(ierr);
373 simCtx->num_bcs_files = 0;
374 simCtx->bcs_files = NULL;
375
376 // B. Parse the user-provided comma-separated list.
377 char *token;
378 char *str_copy;
379 ierr = PetscStrallocpy(file_list_str, &str_copy); CHKERRQ(ierr);
380
381 // First pass: count the number of files.
382 token = strtok(str_copy, ",");
383 while (token) {
384 simCtx->num_bcs_files++;
385 token = strtok(NULL, ",");
386 }
387 ierr = PetscFree(str_copy); CHKERRQ(ierr);
388
389 // Second pass: allocate memory and store the filenames.
390 ierr = PetscMalloc1(simCtx->num_bcs_files, &simCtx->bcs_files); CHKERRQ(ierr);
391 ierr = PetscStrallocpy(file_list_str, &str_copy); CHKERRQ(ierr);
392 token = strtok(str_copy, ",");
393 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
394 ierr = PetscStrallocpy(token, &simCtx->bcs_files[i]); CHKERRQ(ierr);
395 token = strtok(NULL, ",");
396 }
397 ierr = PetscFree(str_copy); CHKERRQ(ierr);
398 }
399
400
401 // --- Group 8
402 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 8: Turbulence Modeling (LES/RANS) \n");
403 ierr = PetscOptionsGetInt(NULL, NULL, "-les", &simCtx->les, NULL); CHKERRQ(ierr);
404 ierr = PetscOptionsGetInt(NULL, NULL, "-rans", &simCtx->rans, NULL); CHKERRQ(ierr);
405 ierr = PetscOptionsGetInt(NULL, NULL, "-wallfunction", &simCtx->wallfunction, NULL); CHKERRQ(ierr);
406 ierr = PetscOptionsGetInt(NULL, NULL, "-mixed", &simCtx->mixed, NULL); CHKERRQ(ierr);
407 ierr = PetscOptionsGetInt(NULL, NULL, "-clark", &simCtx->clark, NULL); CHKERRQ(ierr);
408 ierr = PetscOptionsGetInt(NULL, NULL, "-dynamic_freq", &simCtx->dynamic_freq, NULL); CHKERRQ(ierr);
409 ierr = PetscOptionsGetReal(NULL, NULL, "-max_cs", &simCtx->max_cs, NULL); CHKERRQ(ierr);
410 ierr = PetscOptionsGetReal(NULL, NULL, "-const_cs", &simCtx->Const_CS, NULL); CHKERRQ(ierr);
411 ierr = PetscOptionsGetInt(NULL, NULL, "-testfilter_ik", &simCtx->testfilter_ik, NULL); CHKERRQ(ierr);
412 ierr = PetscOptionsGetInt(NULL, NULL, "-testfilter_1d", &simCtx->testfilter_1d, NULL); CHKERRQ(ierr);
413 ierr = PetscOptionsGetInt(NULL, NULL, "-i_homo_filter", &simCtx->i_homo_filter, NULL); CHKERRQ(ierr);
414 ierr = PetscOptionsGetInt(NULL, NULL, "-j_homo_filter", &simCtx->j_homo_filter, NULL); CHKERRQ(ierr);
415 ierr = PetscOptionsGetInt(NULL, NULL, "-k_homo_filter", &simCtx->k_homo_filter, NULL); CHKERRQ(ierr);
416 ierr = PetscOptionsGetBool(NULL, NULL, "-averaging", &simCtx->averaging, NULL); CHKERRQ(ierr);
417
418 // --- Group 9
419 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 9: Particle / DMSwarm Data & Settings \n");
420 ierr = PetscOptionsGetInt(NULL, NULL, "-numParticles", &simCtx->np, NULL); CHKERRQ(ierr);
421 ierr = PetscOptionsGetBool(NULL, NULL, "-read_fields", &simCtx->readFields, NULL); CHKERRQ(ierr);
422 ierr = PetscOptionsGetInt(NULL, NULL, "-pinit", &simCtx->ParticleInitialization, NULL); CHKERRQ(ierr);
423 ierr = PetscOptionsGetString(NULL,NULL,"-particle_restart_mode",simCtx->particleRestartMode,sizeof(simCtx->particleRestartMode),NULL); CHKERRQ(ierr);
424 // Validation for Particle Restart Mode
425 if (strcmp(simCtx->particleRestartMode, "load") != 0 && strcmp(simCtx->particleRestartMode, "init") != 0) {
426 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Invalid value for -particle_restart_mode. Must be 'load' or 'init'. You provided '%s'.", simCtx->particleRestartMode);
427 }
428 // --- Group 10
429 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 10: Immersed Boundary & FSI Data Object Pointers \n");
430 ierr = PetscOptionsGetBool(NULL, NULL, "-rs_fsi", &simCtx->rstart_fsi, NULL); CHKERRQ(ierr);
431 ierr = PetscOptionsGetInt(NULL, NULL, "-duplicate", &simCtx->duplicate, NULL); CHKERRQ(ierr);
432
433 // --- Group 11
434 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 11: Top-Level Managers & Custom Configuration \n");
435 ierr = PetscOptionsGetInt(NULL, NULL, "-logfreq", &simCtx->LoggingFrequency, NULL); CHKERRQ(ierr);
436
437 if (simCtx->num_bcs_files != simCtx->block_number) {
438 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);
439 }
440
441 // --- Group 12
442 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Parsing Group 12: Post-Processing Information.\n");
443 // This logic determines the Post Processing configuration and STORES it in simCtx for later reference and cleanup.
444 ierr = PetscOptionsGetString(NULL,NULL,"-postprocessing_config_file",simCtx->PostprocessingControlFile,PETSC_MAX_PATH_LEN,NULL); CHKERRQ(ierr);
445 ierr = PetscNew(&simCtx->pps); CHKERRQ(ierr);
446 ierr = ParsePostProcessingSettings(simCtx);
447
448 // === 5. Dependent Parameter Calculations ================================
449 // Some parameters depend on others, so we calculate them here.
450 simCtx->StartTime = (PetscReal)simCtx->StartStep*simCtx->dt;
451 simCtx->ti = simCtx->StartTime;
452 simCtx->step = simCtx->StartStep;
453
454 // === 5. Log Summary and Finalize Setup ==================================
455 LOG_ALLOW(GLOBAL, LOG_DEBUG, "-- Console Output Functions [Total : %d] : --\n", simCtx->nAllowed);
456 for (PetscInt i = 0; i < simCtx->nAllowed; ++i) {
457 LOG_ALLOW(GLOBAL, LOG_DEBUG, " [%2d] «%s»\n", i, simCtx->allowedFuncs[i]);
458 }
459
460 LOG_ALLOW(GLOBAL, LOG_INFO, "Configuration complete. Key parameters:\n");
461 LOG_ALLOW(GLOBAL, LOG_INFO, " - Run mode: %s\n", simCtx->OnlySetup ? "SETUP ONLY" : "Full Simulation");
462 LOG_ALLOW(GLOBAL, LOG_INFO, " - Time steps: %d (from %d to %d)\n", simCtx->StepsToRun, simCtx->StartStep, simCtx->StartStep + simCtx->StepsToRun);
463 LOG_ALLOW(GLOBAL, LOG_INFO, " - Time step size (dt): %g\n", simCtx->dt);
464 LOG_ALLOW(GLOBAL, LOG_INFO, " - Immersed Boundary: %s\n", simCtx->immersed ? "ENABLED" : "DISABLED");
465 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particles: %d\n", simCtx->np);
466 if (simCtx->StartStep > 0 && simCtx->np > 0) {
467 LOG_ALLOW(GLOBAL, LOG_INFO, " - Particle Restart Mode: %s\n", simCtx->particleRestartMode);
468 }
469
470 // --- Initialize PETSc's internal performance logging stage ---
471 ierr = PetscLogDefaultBegin(); CHKERRQ(ierr); // REDUNDANT but safe.
472
473 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Finished CreateSimulationContext successfully on rank %d.\n", simCtx->rank);
474
476 PetscFunctionReturn(0);
477}
PetscErrorCode ParsePostProcessingSettings(SimCtx *simCtx)
Initializes post-processing settings from a config file and command-line overrides.
Definition io.c:2199
PetscErrorCode ParseScalingInformation(SimCtx *simCtx)
Parses physical scaling parameters from command-line options.
Definition io.c:2334
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
Definition logging.c:122
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
----— DEBUG ---------------------------------------— #define LOG_ALLOW(scope, level,...
Definition logging.h:268
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:46
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:47
#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:201
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
Definition logging.c:82
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:740
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:85
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
Definition logging.c:566
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:998
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:32
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:33
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:731
PetscInt MHV
Definition variables.h:572
PetscInt turbine
Definition variables.h:572
PetscInt fishcyl
Definition variables.h:572
PetscInt clark
Definition variables.h:610
PetscInt implicit_type
Definition variables.h:575
PetscInt movefsi
Definition variables.h:567
PetscInt moveframe
Definition variables.h:568
PetscInt TwoD
Definition variables.h:568
PetscInt pseudo_periodic
Definition variables.h:594
PetscInt fish_c
Definition variables.h:572
PetscInt dgf_z
Definition variables.h:569
PetscReal poisson_tol
Definition variables.h:579
PetscMPIInt rank
Definition variables.h:541
PetscInt fish
Definition variables.h:572
PetscInt LV
Definition variables.h:572
PetscReal angle
Definition variables.h:588
PetscInt thin
Definition variables.h:568
PetscInt grid1d
Definition variables.h:593
char eulerianSource[64]
Definition variables.h:557
PetscInt block_number
Definition variables.h:593
PetscInt da_procs_z
Definition variables.h:599
PetscInt blkpbc
Definition variables.h:594
PetscInt sediment
Definition variables.h:567
PetscInt channelz
Definition variables.h:593
char euler_subdir[PETSC_MAX_PATH_LEN]
Definition variables.h:560
PetscInt rans
Definition variables.h:609
PetscReal StartTime
Definition variables.h:551
PetscInt dgf_az
Definition variables.h:569
PetscReal FluxOutSum
Definition variables.h:602
PetscReal CMy_c
Definition variables.h:589
char ** bcs_files
Definition variables.h:601
PetscReal max_angle
Definition variables.h:588
PetscReal imp_rtol
Definition variables.h:576
PetscReal st
Definition variables.h:581
PetscInt duplicate
Definition variables.h:628
PetscInt tiout
Definition variables.h:550
PetscInt implicit
Definition variables.h:575
char allowedFile[PETSC_MAX_PATH_LEN]
Definition variables.h:632
PetscInt da_procs_y
Definition variables.h:599
PetscReal imp_atol
Definition variables.h:576
PetscInt testfilter_1d
Definition variables.h:612
PetscInt FieldInitialization
Definition variables.h:582
PetscReal ren
Definition variables.h:581
PetscReal Crotz
Definition variables.h:597
PetscInt mixed
Definition variables.h:610
IBMVNodes * ibmv
Definition variables.h:625
char criticalFuncsFile[PETSC_MAX_PATH_LEN]
Definition variables.h:641
char output_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:559
PetscReal dt
Definition variables.h:552
PetscInt StepsToRun
Definition variables.h:549
PetscInt k_periodic
Definition variables.h:594
PetscInt inletprofile
Definition variables.h:593
PetscReal cdisy
Definition variables.h:581
char ** criticalFuncs
Definition variables.h:643
PetscBool rstart_fsi
Definition variables.h:627
PetscInt np
Definition variables.h:616
PetscBool averaging
Definition variables.h:613
PetscInt ccc
Definition variables.h:605
PetscReal ratio
Definition variables.h:606
PetscInt mg_idx
Definition variables.h:577
PetscInt StartStep
Definition variables.h:548
PetscInt mg_MAX_IT
Definition variables.h:577
PetscBool OnlySetup
Definition variables.h:553
PetscInt rotatefsi
Definition variables.h:567
PetscReal cdisz
Definition variables.h:581
PetscScalar x
Definition variables.h:101
PetscInt dgf_x
Definition variables.h:569
char * current_io_directory
Definition variables.h:564
PetscInt pizza
Definition variables.h:572
PetscReal MaxDiv
Definition variables.h:638
char grid_file[PETSC_MAX_PATH_LEN]
Definition variables.h:598
PetscReal max_cs
Definition variables.h:611
PetscInt invicid
Definition variables.h:568
char ** allowedFuncs
Definition variables.h:634
PetscInt mg_poItr
Definition variables.h:577
PetscInt STRONG_COUPLING
Definition variables.h:580
PetscInt MaxDivx
Definition variables.h:639
PetscInt poisson
Definition variables.h:578
PetscInt k_homo_filter
Definition variables.h:612
PetscInt MaxDivy
Definition variables.h:639
PetscInt NumberOfBodies
Definition variables.h:587
char particleRestartMode[16]
Definition variables.h:621
PetscInt Ogrid
Definition variables.h:593
char particle_subdir[PETSC_MAX_PATH_LEN]
Definition variables.h:561
PetscInt MaxDivz
Definition variables.h:639
BoundingBox * bboxlist
Definition variables.h:619
PetscInt j_homo_filter
Definition variables.h:612
PetscInt eel
Definition variables.h:572
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:562
PetscInt MaxDivFlatArg
Definition variables.h:639
PetscReal FluxInSum
Definition variables.h:602
PetscReal CMz_c
Definition variables.h:589
PetscBool generate_grid
Definition variables.h:595
PetscReal imp_stol
Definition variables.h:576
PetscInt nAllowed
Definition variables.h:635
PetscScalar z
Definition variables.h:101
PetscInt OutputFreq
Definition variables.h:555
PetscReal Const_CS
Definition variables.h:611
PetscInt i_homo_filter
Definition variables.h:612
PetscInt wallfunction
Definition variables.h:610
PetscInt rheology
Definition variables.h:567
PetscReal Flux_in
Definition variables.h:588
PetscReal cdisx
Definition variables.h:581
PetscInt dgf_ax
Definition variables.h:569
PetscReal cfl
Definition variables.h:581
PetscInt mglevels
Definition variables.h:577
PetscInt num_bcs_files
Definition variables.h:600
DM dm_swarm
Definition variables.h:618
PetscBool useCfg
Definition variables.h:633
PetscBool readFields
Definition variables.h:617
PetscInt central
Definition variables.h:580
PetscBool useCriticalFuncsCfg
Definition variables.h:642
PetscReal Fluxsum
Definition variables.h:602
PetscReal Croty
Definition variables.h:597
PetscReal grid_rotation_angle
Definition variables.h:596
PetscInt dynamic_freq
Definition variables.h:610
PetscInt da_procs_x
Definition variables.h:599
PetscReal U_bc
Definition variables.h:604
Cmpnts InitialConstantContra
Definition variables.h:583
PetscInt i_periodic
Definition variables.h:594
PetscInt step
Definition variables.h:546
PetscReal AreaOutSum
Definition variables.h:603
PetscInt dgf_ay
Definition variables.h:569
PetscInt testfilter_ik
Definition variables.h:612
PetscInt hydro
Definition variables.h:572
PostProcessParams * pps
Definition variables.h:648
PetscScalar y
Definition variables.h:101
PetscMPIInt size
Definition variables.h:542
char _io_context_buffer[PETSC_MAX_PATH_LEN]
Definition variables.h:563
PetscInt les
Definition variables.h:609
PetscInt mg_preItr
Definition variables.h:577
PetscViewer logviewer
Definition variables.h:554
PetscInt ParticleInitialization
Definition variables.h:620
PetscInt imp_MAX_IT
Definition variables.h:575
PetscInt cop
Definition variables.h:572
PetscReal ti
Definition variables.h:547
PetscInt Pipe
Definition variables.h:572
PetscReal vnn
Definition variables.h:581
PetscInt rotateframe
Definition variables.h:568
IBMNodes * ibm
Definition variables.h:624
PetscReal AreaInSum
Definition variables.h:603
PetscInt nCriticalFuncs
Definition variables.h:644
PetscReal summationRHS
Definition variables.h:637
PetscInt immersed
Definition variables.h:567
char PostprocessingControlFile[PETSC_MAX_PATH_LEN]
Definition variables.h:647
char restart_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:558
PetscInt blank
Definition variables.h:568
PetscInt dgf_y
Definition variables.h:569
PetscInt LoggingFrequency
Definition variables.h:636
PetscReal CMx_c
Definition variables.h:589
PetscInt j_periodic
Definition variables.h:594
PetscInt wing
Definition variables.h:572
FSInfo * fsi
Definition variables.h:626
The master context for the entire simulation.
Definition variables.h:538
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PetscMkdirRecursive()

static PetscErrorCode PetscMkdirRecursive ( const char *  path)
static

Creates a directory path recursively, similar to mkdir -p.

This function is designed to be called by Rank 0 only. It takes a full path, parses it, and creates each directory component in sequence.

Parameters
[in]pathThe full directory path to create.
Returns
PetscErrorCode

Definition at line 491 of file setup.c.

492{
493 PetscErrorCode ierr;
494 char tmp_path[PETSC_MAX_PATH_LEN];
495 char *p = NULL;
496 size_t len;
497 PetscBool exists;
498
499 PetscFunctionBeginUser;
500
501 // Create a mutable copy of the path
502 len = strlen(path);
503 if (len >= sizeof(tmp_path)) {
504 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Path is too long to process: %s", path);
505 }
506 strcpy(tmp_path, path);
507
508 // If the path ends with a separator, remove it
509 if (tmp_path[len - 1] == '/') {
510 tmp_path[len - 1] = 0;
511 }
512
513 // Iterate through the path, creating each directory level
514 for (p = tmp_path + 1; *p; p++) {
515 if (*p == '/') {
516 *p = 0; // Temporarily terminate the string
517
518 // Check if this directory level exists
519 ierr = PetscTestDirectory(tmp_path, 'r', &exists); CHKERRQ(ierr);
520 if (!exists) {
521 ierr = PetscMkdir(tmp_path); CHKERRQ(ierr);
522 }
523
524 *p = '/'; // Restore the separator
525 }
526 }
527
528 // Create the final, full directory path
529 ierr = PetscTestDirectory(tmp_path, 'r', &exists); CHKERRQ(ierr);
530 if (!exists) {
531 ierr = PetscMkdir(tmp_path); CHKERRQ(ierr);
532 }
533
534 PetscFunctionReturn(0);
535}
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.

Definition at line 558 of file setup.c.

559{
560 PetscErrorCode ierr;
561 PetscMPIInt rank;
562 PetscBool exists;
563
564 PetscFunctionBeginUser;
565 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
566
567 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Setting up simulation environment ---\n");
568
569 /* =====================================================================
570 * Phase 1: Check for all required and optional INPUT files.
571 * ===================================================================== */
572 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 1: Verifying input files...\n");
573
574 // --- Mandatory Inputs ---
575 if (!simCtx->generate_grid) {
576 ierr = VerifyPathExistence(simCtx->grid_file, PETSC_FALSE, PETSC_FALSE, "Grid file", &exists); CHKERRQ(ierr);
577 }
578 for (PetscInt i = 0; i < simCtx->num_bcs_files; i++) {
579 char desc[128];
580 ierr = PetscSNPrintf(desc, sizeof(desc), "BCS file #%d", i + 1); CHKERRQ(ierr);
581 ierr = VerifyPathExistence(simCtx->bcs_files[i], PETSC_FALSE, PETSC_FALSE, desc, &exists); CHKERRQ(ierr);
582 }
583
584 // --- Optional Inputs (these produce warnings if missing) ---
585 if (simCtx->useCfg) {
586 ierr = VerifyPathExistence(simCtx->allowedFile, PETSC_FALSE, PETSC_TRUE, "Whitelist config file", &exists); CHKERRQ(ierr);
587 }
588 if (simCtx->useCriticalFuncsCfg) {
589 ierr = VerifyPathExistence(simCtx->criticalFuncsFile, PETSC_FALSE, PETSC_TRUE, "Profiling config file", &exists); CHKERRQ(ierr);
590 }
591 if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
592 ierr = VerifyPathExistence(simCtx->PostprocessingControlFile, PETSC_FALSE, PETSC_TRUE, "Post-processing control file", &exists); CHKERRQ(ierr);
593 }
594
595
596 /* =====================================================================
597 * Phase 2: Validate directories specific to the execution mode.
598 * ===================================================================== */
599 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 2: Verifying execution mode directories...\n");
600 // The data source directory must exist if we intend to load any data from it.
601 // This is true if:
602 // 1. We are restarting from a previous time step (StartStep > 0), which implies
603 // loading Eulerian fields and/or particle fields.
604 // 2. We are starting from t=0 but are explicitly told to load the initial
605 // Eulerian fields from a file (eulerianSource == "load").
606 if (simCtx->StartStep > 0 || strcmp(simCtx->eulerianSource,"load")== 0){ // If this is a restart run
607 ierr = VerifyPathExistence(simCtx->restart_dir, PETSC_TRUE, PETSC_FALSE, "Restart source directory", &exists); CHKERRQ(ierr);
608 }
609 if (simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) {
610 ierr = VerifyPathExistence(simCtx->pps->source_dir, PETSC_TRUE, PETSC_FALSE, "Post-processing source directory", &exists); CHKERRQ(ierr);
611 }
612
613 /* =====================================================================
614 * Phase 3: Create and prepare all OUTPUT directories.
615 * ===================================================================== */
616 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Phase 3: Preparing output directories...\n");
617
618 if (rank == 0){
619 if(simCtx->exec_mode == EXEC_MODE_SOLVER){
620 // --- Prepare Log Directory ---
621 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating/cleaning log directory: %s\n", simCtx->log_dir);
622 ierr = PetscRMTree(simCtx->log_dir); // Wipes the directory and its contents
623 if (ierr) { /* Ignore file-not-found error, but fail on others */
624 PetscError(PETSC_COMM_SELF, __LINE__, __FUNCT__, __FILE__, ierr, PETSC_ERROR_INITIAL, "Could not remove existing log directory '%s'. Check permissions.", simCtx->log_dir);
625 }
626 ierr = PetscMkdir(simCtx->log_dir); CHKERRQ(ierr);
627
628 // --- Prepare Output Directories ---
629 char path_buffer[PETSC_MAX_PATH_LEN];
630
631 // 1. Check/Create the main output directory
632 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying main output directory: %s\n", simCtx->output_dir);
633 ierr = PetscTestDirectory(simCtx->output_dir, 'r', &exists); CHKERRQ(ierr);
634 if (!exists) {
635 LOG_ALLOW(GLOBAL, LOG_INFO, "Output directory not found. Creating: %s\n", simCtx->output_dir);
636 ierr = PetscMkdir(simCtx->output_dir); CHKERRQ(ierr);
637 }
638
639 // 2. Check/Create the Eulerian subdirectory
640 ierr = PetscSNPrintf(path_buffer, sizeof(path_buffer), "%s/%s", simCtx->output_dir, simCtx->euler_subdir); CHKERRQ(ierr);
641 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying Eulerian subdirectory: %s\n", path_buffer);
642 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
643 if (!exists) {
644 LOG_ALLOW(GLOBAL, LOG_INFO, "Eulerian subdirectory not found. Creating: %s\n", path_buffer);
645 ierr = PetscMkdir(path_buffer); CHKERRQ(ierr);
646 }
647
648 // 3. Check/Create the Particle subdirectory if needed
649 if (simCtx->np > 0) {
650 ierr = PetscSNPrintf(path_buffer, sizeof(path_buffer), "%s/%s", simCtx->output_dir, simCtx->particle_subdir); CHKERRQ(ierr);
651 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying Particle subdirectory: %s\n", path_buffer);
652 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
653 if (!exists) {
654 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle subdirectory not found. Creating: %s\n", path_buffer);
655 ierr = PetscMkdir(path_buffer); CHKERRQ(ierr);
656 }
657 }
658 } else if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
659 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Preparing post-processing output directories ...\n");
660
661 PostProcessParams *pps = simCtx->pps;
662 char path_buffer[PETSC_MAX_PATH_LEN];
663
664 const char *last_slash_euler = strrchr(pps->output_prefix, '/');
665 if(last_slash_euler){
666 size_t dir_len = last_slash_euler - pps->output_prefix;
667 if(dir_len > 0){
668 if(dir_len >= sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing output prefix path is too long.");
669 strncpy(path_buffer, pps->output_prefix, dir_len);
670 path_buffer[dir_len] = '\0';
671
672 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
673 if (!exists){
674 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Eulerian output directory: %s\n", path_buffer);
675 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
676 }
677 }
678 }
679
680 // Particle output directory
681 if(pps->outputParticles){
682 const char *last_slash_particle = strrchr(pps->particle_output_prefix, '/');
683 if(last_slash_particle){
684 size_t dir_len = last_slash_particle - pps->particle_output_prefix;
685 if(dir_len > 0){
686 if(dir_len > sizeof(path_buffer)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Post-processing particle output prefix path is too long.");
687 strncpy(path_buffer, pps->particle_output_prefix, dir_len);
688 path_buffer[dir_len] = '\0';
689
690 ierr = PetscTestDirectory(path_buffer, 'r', &exists); CHKERRQ(ierr);
691
692 if (!exists){
693 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating post-processing Particle output directory: %s\n", path_buffer);
694 ierr = PetscMkdirRecursive(path_buffer); CHKERRQ(ierr);
695 }
696 }
697 }
698 }
699 }
700 }
701
702 // Synchronize all processes before proceeding
703 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRMPI(ierr);
704
705 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Environment setup complete ---\n");
706
707 PetscFunctionReturn(0);
708}
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:590
static PetscErrorCode PetscMkdirRecursive(const char *path)
Creates a directory path recursively, similar to mkdir -p.
Definition setup.c:491
#define __FUNCT__
Definition setup.c:10
char particle_output_prefix[256]
Definition variables.h:469
char output_prefix[256]
Definition variables.h:466
char source_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:454
PetscBool outputParticles
Definition variables.h:460
@ EXEC_MODE_SOLVER
Definition variables.h:511
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:512
ExecutionMode exec_mode
Definition variables.h:556
Holds all configuration parameters for a post-processing run.
Definition variables.h:452
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AllocateContextHierarchy()

static PetscErrorCode AllocateContextHierarchy ( SimCtx simCtx)
static

Allocates the memory for the UserMG and UserCtx hierarchy.

This function performs the foundational memory allocation for the solver's data structures. It reads the number of multigrid levels and grid blocks from the master SimulationContext, then allocates the arrays for MGCtx and UserCtx.

It performs three critical tasks:

  1. Allocates the MGCtx array within the UserMG struct.
  2. For each level, allocates the UserCtx array for all blocks.
  3. Sets the simCtx back-pointer in every single UserCtx, linking it to the master configuration.
Parameters
simCtxThe master SimulationContext, which contains configuration and will store the resulting allocated hierarchy in its usermg member.
Returns
PetscErrorCode

Definition at line 730 of file setup.c.

731{
732 PetscErrorCode ierr;
733 UserMG *usermg = &simCtx->usermg;
734 MGCtx *mgctx;
735 PetscInt nblk = simCtx->block_number;
736 PetscBool found;
737 PetscFunctionBeginUser;
739
740 LOG_ALLOW(GLOBAL, LOG_INFO, "Allocating context hierarchy for %d levels and %d blocks...\n", simCtx->mglevels, nblk);
741
742 // Store the number of levels in the UserMG struct itself
743 usermg->mglevels = simCtx->mglevels;
744
745 // --- 1. Allocate the array of MGCtx structs ---
746 ierr = PetscMalloc(usermg->mglevels * sizeof(MGCtx), &usermg->mgctx); CHKERRQ(ierr);
747 mgctx = usermg->mgctx;
748 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Allocated MGCtx array of size %d.\n", simCtx->rank, usermg->mglevels);
749
750 // --- 2. Parse semi-coarsening options (logic from MG_Initial) ---
751 // These flags determine if a dimension is coarsened in the multigrid hierarchy.
752 PetscInt *isc, *jsc, *ksc;
753 ierr = PetscMalloc3(nblk, &isc, nblk, &jsc, nblk, &ksc); CHKERRQ(ierr);
754 // Set defaults to FALSE (full coarsening)
755 for (PetscInt i = 0; i < nblk; ++i) {
756 isc[i] = 0; jsc[i] = 0; ksc[i] = 0;
757 }
758
759// Use a temporary variable for the 'count' argument to the parsing function.
760 // This protects the original 'nblk' which is needed for the loop bounds.
761 PetscInt n_opts_found = nblk;
762 ierr = PetscOptionsGetIntArray(NULL, NULL, "-mg_i_semi", isc, &n_opts_found, &found); CHKERRQ(ierr);
763
764 n_opts_found = nblk; // Reset the temp variable before the next call
765 ierr = PetscOptionsGetIntArray(NULL, NULL, "-mg_j_semi", jsc, &n_opts_found, &found); CHKERRQ(ierr);
766
767 n_opts_found = nblk; // Reset the temp variable before the next call
768 ierr = PetscOptionsGetIntArray(NULL, NULL, "-mg_k_semi", ksc, &n_opts_found, &found); CHKERRQ(ierr);
769
770 // --- 3. Loop over levels and blocks to allocate UserCtx arrays ---
771 for (PetscInt level = 0; level < simCtx->mglevels; level++) {
772
773 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Setting up MG Level %d...\n", simCtx->rank, level);
774 // Allocate the array of UserCtx structs for this level
775 ierr = PetscMalloc(nblk * sizeof(UserCtx), &mgctx[level].user); CHKERRQ(ierr);
776 // It's good practice to zero out the memory to avoid uninitialized values
777 ierr = PetscMemzero(mgctx[level].user, nblk * sizeof(UserCtx)); CHKERRQ(ierr);
778 mgctx[level].thislevel = level;
779
780 for (PetscInt bi = 0; bi < nblk; bi++) {
781 UserCtx *currentUser = &mgctx[level].user[bi];
782 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Initializing UserCtx for Level %d, Block %d.\n", simCtx->rank, level, bi);
783
784 // --- CRITICAL STEP: Set the back-pointer to the master context ---
785 currentUser->simCtx = simCtx;
786
787 // Initialize other per-context values
788 currentUser->thislevel = level;
789 currentUser->_this = bi; //
790 currentUser->mglevels = usermg->mglevels;
791
792 // Assign semi-coarsening flags
793 currentUser->isc = isc[bi];
794 currentUser->jsc = jsc[bi];
795 currentUser->ksc = ksc[bi];
796
797 // Link to finer/coarser contexts for multigrid operations
798 if (level > 0) {
799 currentUser->user_c = &mgctx[level-1].user[bi];
800 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "Rank %d: -> Linked to coarser context (user_c).\n", simCtx->rank);
801 }
802 if (level < usermg->mglevels - 1) {
803 currentUser->user_f = &mgctx[level+1].user[bi];
804 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "Rank %d: -> Linked to finer context (user_f).\n", simCtx->rank);
805 }
806 }
807 }
808
809 // Log a summary of the parsed flags on each rank.
810 if (get_log_level() >= LOG_DEBUG && nblk > 0) {
811 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Final semi-coarsening configuration view:\n", simCtx->rank);
812 for (PetscInt bi = 0; bi < nblk; ++bi) {
813 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d: i-semi=%d, j-semi=%d, k-semi=%d\n", simCtx->rank, bi, isc[bi], jsc[bi], ksc[bi]);
814 }
815 }
816
817 // Clean up temporary arrays
818 ierr = PetscFree3(isc, jsc, ksc); CHKERRQ(ierr);
819
820 LOG_ALLOW(GLOBAL, LOG_INFO, "Context hierarchy allocation complete.\n");
822 PetscFunctionReturn(0);
823}
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:39
PetscInt isc
Definition variables.h:674
UserCtx * user
Definition variables.h:427
PetscInt mglevels
Definition variables.h:721
UserCtx * user_f
Definition variables.h:722
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:664
PetscInt ksc
Definition variables.h:674
UserMG usermg
Definition variables.h:631
PetscInt _this
Definition variables.h:674
PetscInt jsc
Definition variables.h:674
PetscInt thislevel
Definition variables.h:428
UserCtx * user_c
Definition variables.h:722
PetscInt thislevel
Definition variables.h:721
PetscInt mglevels
Definition variables.h:434
MGCtx * mgctx
Definition variables.h:437
Context for Multigrid operations.
Definition variables.h:426
User-defined context containing data specific to a single computational grid level.
Definition variables.h:661
User-level context for managing the entire multigrid hierarchy.
Definition variables.h:433
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetupSolverParameters()

static PetscErrorCode SetupSolverParameters ( SimCtx simCtx)
static

Definition at line 827 of file setup.c.

827 {
828
829 PetscFunctionBeginUser;
831
832 LOG_ALLOW(GLOBAL,LOG_INFO, " -- Setting up solver parameters -- .\n");
833
834 UserMG *usermg = &simCtx->usermg;
835 MGCtx *mgctx = usermg->mgctx;
836 PetscInt nblk = simCtx->block_number;
837
838 for (PetscInt level = usermg->mglevels-1; level >=0; level--) {
839 for (PetscInt bi = 0; bi < nblk; bi++) {
840 UserCtx *user = &mgctx[level].user[bi];
841 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Rank %d: Setting up parameters for level %d, block %d\n", simCtx->rank, level, bi);
842
843 user->assignedA = PETSC_FALSE;
844 user->multinullspace = PETSC_FALSE;
845 }
846 }
848 PetscFunctionReturn(0);
849}
PetscBool assignedA
Definition variables.h:701
PetscBool multinullspace
Definition variables.h:698
Here is the caller graph for this function:

◆ SetupGridAndSolvers()

PetscErrorCode SetupGridAndSolvers ( SimCtx simCtx)

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

(Implementation of the orchestrator function itself)

Definition at line 857 of file setup.c.

858{
859 PetscErrorCode ierr;
860 PetscFunctionBeginUser;
861
863
864 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Starting Grid and Solvers Setup ---\n");
865
866 // Phase 1: Allocate the UserMG and UserCtx hierarchy
867 ierr = AllocateContextHierarchy(simCtx); CHKERRQ(ierr);
868
869 // [ The next phases will be added here ]
870 ierr = DefineAllGridDimensions(simCtx); CHKERRQ(ierr);
871 ierr = InitializeAllGridDMs(simCtx); CHKERRQ(ierr);
872 ierr = AssignAllGridCoordinates(simCtx);
873 ierr = CreateAndInitializeAllVectors(simCtx); CHKERRQ(ierr);
874 ierr = SetupSolverParameters(simCtx); CHKERRQ(ierr);
875 ierr = CalculateAllGridMetrics(simCtx); CHKERRQ(ierr);
876
877 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Grid and Solvers Setup Complete ---\n");
878
880 PetscFunctionReturn(0);
881}
PetscErrorCode CalculateAllGridMetrics(SimCtx *simCtx)
Orchestrates the calculation of all grid metrics.
Definition Metric.c:1809
PetscErrorCode DefineAllGridDimensions(SimCtx *simCtx)
Orchestrates the parsing and setting of grid dimensions for all blocks.
Definition grid.c:65
PetscErrorCode InitializeAllGridDMs(SimCtx *simCtx)
Orchestrates the creation of DMDA objects for every block and multigrid level.
Definition grid.c:247
PetscErrorCode AssignAllGridCoordinates(SimCtx *simCtx)
Orchestrates the assignment of physical coordinates to all DMDA objects.
Definition grid.c:340
static PetscErrorCode SetupSolverParameters(SimCtx *simCtx)
Definition setup.c:827
PetscErrorCode CreateAndInitializeAllVectors(SimCtx *simCtx)
Creates and initializes all PETSc Vec objects for all fields.
Definition setup.c:897
static PetscErrorCode AllocateContextHierarchy(SimCtx *simCtx)
Allocates the memory for the UserMG and UserCtx hierarchy.
Definition setup.c:730
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

Definition at line 897 of file setup.c.

898{
899 PetscErrorCode ierr;
900 UserMG *usermg = &simCtx->usermg;
901 MGCtx *mgctx = usermg->mgctx;
902 PetscInt nblk = simCtx->block_number;
903
904 PetscFunctionBeginUser;
905
907
908 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating and initializing all simulation vectors...\n");
909
910 for (PetscInt level = usermg->mglevels-1; level >=0; level--) {
911 for (PetscInt bi = 0; bi < nblk; bi++) {
912 UserCtx *user = &mgctx[level].user[bi];
913
914 if(!user->da || !user->fda) {
915 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "DMs not properly initialized in UserCtx before vector creation.");
916 }
917
918 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Rank %d: Creating vectors for level %d, block %d\n", simCtx->rank, level, bi);
919
920 // --- Group A: Primary Flow Fields (Global and Local) ---
921 // These are the core solution variables.
922 ierr = DMCreateGlobalVector(user->fda, &user->Ucont); CHKERRQ(ierr); ierr = VecSet(user->Ucont, 0.0); CHKERRQ(ierr);
923 ierr = DMCreateGlobalVector(user->fda, &user->Ucat); CHKERRQ(ierr); ierr = VecSet(user->Ucat, 0.0); CHKERRQ(ierr);
924 ierr = DMCreateGlobalVector(user->da, &user->P); CHKERRQ(ierr); ierr = VecSet(user->P, 0.0); CHKERRQ(ierr);
925 ierr = DMCreateGlobalVector(user->da, &user->Nvert); CHKERRQ(ierr); ierr = VecSet(user->Nvert, 0.0); CHKERRQ(ierr);
926
927 ierr = DMCreateLocalVector(user->fda, &user->lUcont); CHKERRQ(ierr); ierr = VecSet(user->lUcont, 0.0); CHKERRQ(ierr);
928 ierr = DMCreateLocalVector(user->fda, &user->lUcat); CHKERRQ(ierr); ierr = VecSet(user->lUcat, 0.0); CHKERRQ(ierr);
929 ierr = DMCreateLocalVector(user->da, &user->lP); CHKERRQ(ierr); ierr = VecSet(user->lP, 0.0); CHKERRQ(ierr);
930 ierr = DMCreateLocalVector(user->da, &user->lNvert); CHKERRQ(ierr); ierr = VecSet(user->lNvert, 0.0); CHKERRQ(ierr);
931
932 // -- Group B: Solver Work Vectors (Global and Local) ---
933 ierr = VecDuplicate(user->P, &user->Phi); CHKERRQ(ierr); ierr = VecSet(user->Phi, 0.0); CHKERRQ(ierr);
934 ierr = VecDuplicate(user->lP, &user->lPhi); CHKERRQ(ierr); ierr = VecSet(user->lPhi, 0.0); CHKERRQ(ierr);
935
936 // --- Group C: Time-Stepping & Workspace Fields (Finest Level Only) ---
937 if (level == usermg->mglevels - 1) {
938 ierr = VecDuplicate(user->Ucont, &user->Ucont_o); CHKERRQ(ierr); ierr = VecSet(user->Ucont_o, 0.0); CHKERRQ(ierr);
939 ierr = VecDuplicate(user->Ucont, &user->Ucont_rm1); CHKERRQ(ierr); ierr = VecSet(user->Ucont_rm1, 0.0); CHKERRQ(ierr);
940 ierr = VecDuplicate(user->Ucat, &user->Ucat_o); CHKERRQ(ierr); ierr = VecSet(user->Ucat_o, 0.0); CHKERRQ(ierr);
941 ierr = VecDuplicate(user->P, &user->P_o); CHKERRQ(ierr); ierr = VecSet(user->P_o, 0.0); CHKERRQ(ierr);
942 ierr = VecDuplicate(user->lUcont, &user->lUcont_o); CHKERRQ(ierr); ierr = VecSet(user->lUcont_o, 0.0); CHKERRQ(ierr);
943 ierr = VecDuplicate(user->lUcont, &user->lUcont_rm1); CHKERRQ(ierr); ierr = VecSet(user->lUcont_rm1, 0.0); CHKERRQ(ierr);
944 ierr = DMCreateLocalVector(user->da, &user->lNvert_o); CHKERRQ(ierr); ierr = VecSet(user->lNvert_o, 0.0); CHKERRQ(ierr);
945 ierr = VecDuplicate(user->Nvert, &user->Nvert_o); CHKERRQ(ierr); ierr = VecSet(user->Nvert_o, 0.0); CHKERRQ(ierr);
946 }
947
948 // --- Group D: Grid Metrics (Cell-Centered) ---
949 ierr = DMCreateGlobalVector(user->fda, &user->Csi); CHKERRQ(ierr); ierr = VecSet(user->Csi, 0.0); CHKERRQ(ierr);
950 ierr = VecDuplicate(user->Csi, &user->Eta); CHKERRQ(ierr); ierr = VecSet(user->Eta, 0.0); CHKERRQ(ierr);
951 ierr = VecDuplicate(user->Csi, &user->Zet); CHKERRQ(ierr); ierr = VecSet(user->Zet, 0.0); CHKERRQ(ierr);
952 ierr = DMCreateGlobalVector(user->da, &user->Aj); CHKERRQ(ierr); ierr = VecSet(user->Aj, 0.0); CHKERRQ(ierr);
953
954 ierr = DMCreateLocalVector(user->fda, &user->lCsi); CHKERRQ(ierr); ierr = VecSet(user->lCsi, 0.0); CHKERRQ(ierr);
955 ierr = VecDuplicate(user->lCsi, &user->lEta); CHKERRQ(ierr); ierr = VecSet(user->lEta, 0.0); CHKERRQ(ierr);
956 ierr = VecDuplicate(user->lCsi, &user->lZet); CHKERRQ(ierr); ierr = VecSet(user->lZet, 0.0); CHKERRQ(ierr);
957 ierr = DMCreateLocalVector(user->da, &user->lAj); CHKERRQ(ierr); ierr = VecSet(user->lAj, 0.0); CHKERRQ(ierr);
958
959
960 // --- Group E: Grid Metrics (Face-Centered) ---
961 // Vector metrics are duplicated from Csi (DOF=3, fda-based)
962 ierr = VecDuplicate(user->Csi, &user->ICsi); CHKERRQ(ierr); ierr = VecSet(user->ICsi, 0.0); CHKERRQ(ierr);
963 ierr = VecDuplicate(user->Csi, &user->IEta); CHKERRQ(ierr); ierr = VecSet(user->IEta, 0.0); CHKERRQ(ierr);
964 ierr = VecDuplicate(user->Csi, &user->IZet); CHKERRQ(ierr); ierr = VecSet(user->IZet, 0.0); CHKERRQ(ierr);
965 ierr = VecDuplicate(user->Csi, &user->JCsi); CHKERRQ(ierr); ierr = VecSet(user->JCsi, 0.0); CHKERRQ(ierr);
966 ierr = VecDuplicate(user->Csi, &user->JEta); CHKERRQ(ierr); ierr = VecSet(user->JEta, 0.0); CHKERRQ(ierr);
967 ierr = VecDuplicate(user->Csi, &user->JZet); CHKERRQ(ierr); ierr = VecSet(user->JZet, 0.0); CHKERRQ(ierr);
968 ierr = VecDuplicate(user->Csi, &user->KCsi); CHKERRQ(ierr); ierr = VecSet(user->KCsi, 0.0); CHKERRQ(ierr);
969 ierr = VecDuplicate(user->Csi, &user->KEta); CHKERRQ(ierr); ierr = VecSet(user->KEta, 0.0); CHKERRQ(ierr);
970 ierr = VecDuplicate(user->Csi, &user->KZet); CHKERRQ(ierr); ierr = VecSet(user->KZet, 0.0); CHKERRQ(ierr);
971 // Scalar metrics are duplicated from Aj (DOF=1, da-based)
972 ierr = VecDuplicate(user->Aj, &user->IAj); CHKERRQ(ierr); ierr = VecSet(user->IAj, 0.0); CHKERRQ(ierr);
973 ierr = VecDuplicate(user->Aj, &user->JAj); CHKERRQ(ierr); ierr = VecSet(user->JAj, 0.0); CHKERRQ(ierr);
974 ierr = VecDuplicate(user->Aj, &user->KAj); CHKERRQ(ierr); ierr = VecSet(user->KAj, 0.0); CHKERRQ(ierr);
975
976 ierr = VecDuplicate(user->lCsi, &user->lICsi); CHKERRQ(ierr); ierr = VecSet(user->lICsi, 0.0); CHKERRQ(ierr);
977 ierr = VecDuplicate(user->lCsi, &user->lIEta); CHKERRQ(ierr); ierr = VecSet(user->lIEta, 0.0); CHKERRQ(ierr);
978 ierr = VecDuplicate(user->lCsi, &user->lIZet); CHKERRQ(ierr); ierr = VecSet(user->lIZet, 0.0); CHKERRQ(ierr);
979 ierr = VecDuplicate(user->lCsi, &user->lJCsi); CHKERRQ(ierr); ierr = VecSet(user->lJCsi, 0.0); CHKERRQ(ierr);
980 ierr = VecDuplicate(user->lCsi, &user->lJEta); CHKERRQ(ierr); ierr = VecSet(user->lJEta, 0.0); CHKERRQ(ierr);
981 ierr = VecDuplicate(user->lCsi, &user->lJZet); CHKERRQ(ierr); ierr = VecSet(user->lJZet, 0.0); CHKERRQ(ierr);
982 ierr = VecDuplicate(user->lCsi, &user->lKCsi); CHKERRQ(ierr); ierr = VecSet(user->lKCsi, 0.0); CHKERRQ(ierr);
983 ierr = VecDuplicate(user->lCsi, &user->lKEta); CHKERRQ(ierr); ierr = VecSet(user->lKEta, 0.0); CHKERRQ(ierr);
984 ierr = VecDuplicate(user->lCsi, &user->lKZet); CHKERRQ(ierr); ierr = VecSet(user->lKZet, 0.0); CHKERRQ(ierr);
985
986 ierr = VecDuplicate(user->lAj, &user->lIAj); CHKERRQ(ierr); ierr = VecSet(user->lIAj, 0.0); CHKERRQ(ierr);
987 ierr = VecDuplicate(user->lAj, &user->lJAj); CHKERRQ(ierr); ierr = VecSet(user->lJAj, 0.0); CHKERRQ(ierr);
988 ierr = VecDuplicate(user->lAj, &user->lKAj); CHKERRQ(ierr); ierr = VecSet(user->lKAj, 0.0); CHKERRQ(ierr);
989
990 // --- Group F: Cell/Face Center Coordinates and Grid Spacing ---
991 ierr = DMCreateGlobalVector(user->fda, &user->Cent); CHKERRQ(ierr); ierr = VecSet(user->Cent, 0.0); CHKERRQ(ierr);
992 ierr = DMCreateLocalVector(user->fda, &user->lCent); CHKERRQ(ierr); ierr = VecSet(user->lCent, 0.0); CHKERRQ(ierr);
993
994 ierr = VecDuplicate(user->Cent, &user->GridSpace); CHKERRQ(ierr); ierr = VecSet(user->GridSpace, 0.0); CHKERRQ(ierr);
995 ierr = VecDuplicate(user->lCent, &user->lGridSpace); CHKERRQ(ierr); ierr = VecSet(user->lGridSpace, 0.0); CHKERRQ(ierr);
996
997 // Face-center coordinate vectors are LOCAL to hold calculated values before scattering
998 ierr = VecDuplicate(user->lCent, &user->Centx); CHKERRQ(ierr); ierr = VecSet(user->Centx, 0.0); CHKERRQ(ierr);
999 ierr = VecDuplicate(user->lCent, &user->Centy); CHKERRQ(ierr); ierr = VecSet(user->Centy, 0.0); CHKERRQ(ierr);
1000 ierr = VecDuplicate(user->lCent, &user->Centz); CHKERRQ(ierr); ierr = VecSet(user->Centz, 0.0); CHKERRQ(ierr);
1001
1002 if(level == usermg->mglevels -1){
1003 // --- Group G: Turbulence Models (Finest Level Only) ---
1004 if (simCtx->les || simCtx->rans) {
1005 ierr = DMCreateGlobalVector(user->da, &user->Nu_t); CHKERRQ(ierr); ierr = VecSet(user->Nu_t, 0.0); CHKERRQ(ierr);
1006 ierr = DMCreateLocalVector(user->da, &user->lNu_t); CHKERRQ(ierr); ierr = VecSet(user->lNu_t, 0.0); CHKERRQ(ierr);
1007 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Turbulence viscosity (Nu_t) vectors created for LES/RANS model.\n");
1008 if(simCtx->les){
1009 ierr = DMCreateGlobalVector(user->da,&user->CS); CHKERRQ(ierr); ierr = VecSet(user->CS,0.0); CHKERRQ(ierr);
1010 ierr = DMCreateLocalVector(user->da,&user->lCs); CHKERRQ(ierr); ierr = VecSet(user->lCs,0.0); CHKERRQ(ierr);
1011 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Smagorinsky constant (CS) vectors created for LES model.\n");
1012 }
1013 // Add K_Omega etc. here as needed
1014
1015 // Note: Add any other vectors from the legacy MG_Initial here as needed.
1016 // For example: Rhs, Forcing, turbulence Vecs (K_Omega, Nu_t)...
1017
1018 }
1019 // --- Group H: Particle Methods
1020 if(simCtx->np>0){
1021 ierr = DMCreateGlobalVector(user->da,&user->ParticleCount); CHKERRQ(ierr); ierr = VecSet(user->ParticleCount,0.0); CHKERRQ(ierr);
1022 ierr = DMCreateLocalVector(user->da,&user->lParticleCount); CHKERRQ(ierr); ierr = VecSet(user->lParticleCount,0.0); CHKERRQ(ierr);
1023 // Scalar field to hold particle scalar property (e.g., temperature, concentration)
1024 ierr = DMCreateGlobalVector(user->da,&user->Psi); CHKERRQ(ierr); ierr = VecSet(user->Psi,0.0); CHKERRQ(ierr);
1025 ierr = DMCreateLocalVector(user->da,&user->lPsi); CHKERRQ(ierr); ierr = VecSet(user->lPsi,0.0); CHKERRQ(ierr);
1026 LOG_ALLOW(GLOBAL,LOG_DEBUG,"ParticleCount & Scalar(Psi) created for %d particles.\n",simCtx->np);
1027 }
1028 }
1029 // --- Group I: Boundary Condition vectors needed by the legacy FormBCS ---
1030 ierr = DMCreateGlobalVector(user->fda, &user->Bcs.Ubcs); CHKERRQ(ierr);
1031 ierr = VecSet(user->Bcs.Ubcs, 0.0); CHKERRQ(ierr);
1032 ierr = DMCreateGlobalVector(user->fda, &user->Bcs.Uch); CHKERRQ(ierr);
1033 ierr = VecSet(user->Bcs.Uch, 0.0); CHKERRQ(ierr);
1034
1035 if(level == usermg->mglevels - 1){
1036 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1037 LOG_ALLOW(LOCAL, LOG_DEBUG, "Post-processor mode detected. Allocating derived field vectors.\n");
1038
1039 ierr = VecDuplicate(user->P, &user->P_nodal); CHKERRQ(ierr);
1040 ierr = VecSet(user->P_nodal, 0.0); CHKERRQ(ierr);
1041
1042 ierr = VecDuplicate(user->Ucat, &user->Ucat_nodal); CHKERRQ(ierr);
1043 ierr = VecSet(user->Ucat_nodal, 0.0); CHKERRQ(ierr);
1044
1045 ierr = VecDuplicate(user->P, &user->Qcrit); CHKERRQ(ierr);
1046 ierr = VecSet(user->Qcrit, 0.0); CHKERRQ(ierr);
1047
1048 LOG_ALLOW(LOCAL, LOG_DEBUG, "Derived field vectors P_nodal, Ucat_nodal, and Qcrit created.\n");
1049
1050 if(simCtx->np>0){
1051 ierr = VecDuplicate(user->Psi, &user->Psi_nodal); CHKERRQ(ierr);
1052 ierr = VecSet(user->Psi_nodal, 0.0); CHKERRQ(ierr);
1053
1054 LOG_ALLOW(LOCAL, LOG_DEBUG, "Derived field vector Psi_nodal created for particle scalar property.\n");
1055
1056 }
1057 }else{
1058 user->P_nodal = NULL;
1059 user->Ucat_nodal = NULL;
1060 user->Qcrit = NULL;
1061 user->Psi_nodal = NULL;
1062 }
1063 }
1064
1065 }
1066}
1067
1068 LOG_ALLOW(GLOBAL, LOG_INFO, "All simulation vectors created and initialized.\n");
1069
1071 PetscFunctionReturn(0);
1072}
Vec lCent
Definition variables.h:705
Vec GridSpace
Definition variables.h:705
Vec P_nodal
Definition variables.h:734
Vec JCsi
Definition variables.h:708
Vec KAj
Definition variables.h:709
Vec JEta
Definition variables.h:708
Vec Zet
Definition variables.h:705
Vec lIEta
Definition variables.h:707
Vec lIZet
Definition variables.h:707
Vec lNvert
Definition variables.h:688
Vec Phi
Definition variables.h:688
Vec IZet
Definition variables.h:707
Vec Centz
Definition variables.h:706
Vec IEta
Definition variables.h:707
Vec lZet
Definition variables.h:705
Vec Csi
Definition variables.h:705
Vec lUcont_rm1
Definition variables.h:692
Vec lIAj
Definition variables.h:707
Vec lKEta
Definition variables.h:709
Vec Ucat_nodal
Definition variables.h:735
Vec lPsi
Definition variables.h:730
Vec lJCsi
Definition variables.h:708
Vec lCs
Definition variables.h:712
Vec Ucont
Definition variables.h:688
Vec Ubcs
Boundary condition velocity values. (Comment: "An ugly hack, waste of memory")
Definition variables.h:121
Vec Qcrit
Definition variables.h:736
Vec JZet
Definition variables.h:708
Vec Centx
Definition variables.h:706
BCS Bcs
Definition variables.h:682
Vec lPhi
Definition variables.h:688
Vec lParticleCount
Definition variables.h:729
Vec lUcont_o
Definition variables.h:691
Vec Ucat_o
Definition variables.h:691
Vec lKZet
Definition variables.h:709
Vec Eta
Definition variables.h:705
Vec lNu_t
Definition variables.h:712
Vec Nu_t
Definition variables.h:712
Vec lJEta
Definition variables.h:708
Vec lCsi
Definition variables.h:705
Vec lGridSpace
Definition variables.h:705
Vec ICsi
Definition variables.h:707
Vec lKCsi
Definition variables.h:709
Vec Ucat
Definition variables.h:688
Vec ParticleCount
Definition variables.h:729
Vec Ucont_o
Definition variables.h:691
Vec lJZet
Definition variables.h:708
Vec Nvert_o
Definition variables.h:691
Vec IAj
Definition variables.h:707
Vec Psi_nodal
Definition variables.h:737
Vec JAj
Definition variables.h:708
Vec KEta
Definition variables.h:709
Vec Ucont_rm1
Definition variables.h:692
Vec lUcont
Definition variables.h:688
Vec lAj
Definition variables.h:705
Vec lICsi
Definition variables.h:707
Vec lUcat
Definition variables.h:688
Vec lEta
Definition variables.h:705
Vec KZet
Definition variables.h:709
Vec Cent
Definition variables.h:705
Vec Nvert
Definition variables.h:688
Vec KCsi
Definition variables.h:709
Vec lNvert_o
Definition variables.h:691
Vec Centy
Definition variables.h:706
Vec lJAj
Definition variables.h:708
Vec lKAj
Definition variables.h:709
Vec Psi
Definition variables.h:730
Vec P_o
Definition variables.h:691
Vec Uch
Characteristic velocity for boundary conditions.
Definition variables.h:122
Here is the caller graph for this function:

◆ UpdateLocalGhosts()

PetscErrorCode UpdateLocalGhosts ( UserCtx user,
const char *  fieldName 
)

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

This function identifies the correct global vector, local vector, and DM based on the provided fieldName and performs the standard PETSc DMGlobalToLocalBegin/End sequence. Includes optional debugging output (max norms before/after).

Parameters
userThe UserCtx structure containing the vectors and DMs.
fieldNameThe name of the field to update ("Ucat", "Ucont", "P", "Nvert", etc.).
Returns
PetscErrorCode 0 on success, non-zero on failure.
Note
This function assumes the global vector associated with fieldName has already been populated with the desired data (including any boundary conditions).

Definition at line 1091 of file setup.c.

1092{
1093 PetscErrorCode ierr;
1094 PetscMPIInt rank;
1095 Vec globalVec = NULL;
1096 Vec localVec = NULL;
1097 DM dm = NULL; // The DM associated with this field pair
1098
1099 PetscFunctionBeginUser; // Use User version for application code
1101 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1102 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Starting ghost update for field '%s'.\n", rank, fieldName);
1103
1104 // --- 1. Identify the correct Vectors and DM ---
1105 if (strcmp(fieldName, "Ucat") == 0) {
1106 globalVec = user->Ucat;
1107 localVec = user->lUcat;
1108 dm = user->fda;
1109 } else if (strcmp(fieldName, "Ucont") == 0) {
1110 globalVec = user->Ucont;
1111 localVec = user->lUcont;
1112 dm = user->fda;
1113 } else if (strcmp(fieldName, "P") == 0) {
1114 globalVec = user->P;
1115 localVec = user->lP;
1116 dm = user->da;
1117 } else if (strcmp(fieldName, "Csi") == 0) {
1118 globalVec = user->Csi;
1119 localVec = user->lCsi;
1120 dm = user->fda;
1121 } else if (strcmp(fieldName, "Eta") == 0) {
1122 globalVec = user->Eta;
1123 localVec = user->lEta;
1124 dm = user->fda;
1125 } else if (strcmp(fieldName, "Zet") == 0) {
1126 globalVec = user->Zet;
1127 localVec = user->lZet;
1128 dm = user->fda;
1129 }else if (strcmp(fieldName, "Nvert") == 0) {
1130 globalVec = user->Nvert;
1131 localVec = user->lNvert;
1132 dm = user->da;
1133 // Add other fields as needed
1134 } else if (strcmp(fieldName, "Aj") == 0) {
1135 globalVec = user->Aj;
1136 localVec = user->lAj;
1137 dm = user->da;
1138 } else if (strcmp(fieldName, "Cent") == 0) {
1139 globalVec = user->Cent;
1140 localVec = user->lCent;
1141 dm = user->fda;
1142 }else if (strcmp(fieldName, "GridSpace") == 0) {
1143 globalVec = user->GridSpace;
1144 localVec = user->lGridSpace;
1145 dm = user->fda;
1146 }else if (strcmp(fieldName,"ICsi") == 0){
1147 globalVec = user->ICsi;
1148 localVec = user->lICsi;
1149 dm = user->fda;
1150 }else if (strcmp(fieldName,"IEta") == 0){
1151 globalVec = user->IEta;
1152 localVec = user->lIEta;
1153 dm = user->fda;
1154 }else if (strcmp(fieldName,"IZet") == 0){
1155 globalVec = user->IZet;
1156 localVec = user->lIZet;
1157 dm = user->fda;
1158 }else if (strcmp(fieldName,"JCsi") == 0){
1159 globalVec = user->JCsi;
1160 localVec = user->lJCsi;
1161 dm = user->fda;
1162 }else if (strcmp(fieldName,"JEta") == 0){
1163 globalVec = user->JEta;
1164 localVec = user->lJEta;
1165 dm = user->fda;
1166 }else if (strcmp(fieldName,"JZet") == 0){
1167 globalVec = user->JZet;
1168 localVec = user->lJZet;
1169 dm = user->fda;
1170 }else if (strcmp(fieldName,"KCsi") == 0){
1171 globalVec = user->KCsi;
1172 localVec = user->lKCsi;
1173 dm = user->fda;
1174 }else if (strcmp(fieldName,"KEta") == 0){
1175 globalVec = user->KEta;
1176 localVec = user->lKEta;
1177 dm = user->fda;
1178 }else if (strcmp(fieldName,"KZet") == 0){
1179 globalVec = user->KZet;
1180 localVec = user->lKZet;
1181 dm = user->fda;
1182 }else if (strcmp(fieldName,"IAj") == 0){
1183 globalVec = user->IAj;
1184 localVec = user->lIAj;
1185 dm = user->da;
1186 }else if (strcmp(fieldName,"JAj") == 0){
1187 globalVec = user->JAj;
1188 localVec = user->lJAj;
1189 dm = user->da;
1190 }else if (strcmp(fieldName,"KAj") == 0){
1191 globalVec = user->KAj;
1192 localVec = user->lKAj;
1193 dm = user->da;
1194 }else if (strcmp(fieldName,"Phi") == 0){ // Pressure correction term.
1195 globalVec = user->Phi;
1196 localVec = user->lPhi;
1197 dm = user->da;
1198 }else if (strcmp(fieldName,"Psi") == 0){ // Particle scalar property.
1199 globalVec = user->Psi;
1200 localVec = user->lPsi;
1201 dm = user->da;
1202 }else {
1203 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Field '%s' not recognized for ghost update.", fieldName);
1204 }
1205
1206 // --- 2. Check if components were found ---
1207 if (!globalVec) {
1208 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Global vector for field '%s' is NULL.", fieldName);
1209 }
1210 if (!localVec) {
1211 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Local vector for field '%s' is NULL.", fieldName);
1212 }
1213 if (!dm) {
1214 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM for field '%s' is NULL.", fieldName);
1215 }
1216
1217 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Identified components for '%s': DM=%p, GlobalVec=%p, LocalVec=%p.\n",
1218 rank, fieldName, (void*)dm, (void*)globalVec, (void*)localVec);
1219
1220 // --- 3. Optional Debugging: Norm Before Update ---
1221 // Use your logging convention check
1222 // if (get_log_level() >= LOG_LEVEL_DEBUG && is_function_allowed("UpdateLocalGhosts")) { // Example check
1223 if(get_log_level() == LOG_DEBUG && is_function_allowed(__func__)){
1224 PetscReal norm_global_before;
1225 ierr = VecNorm(globalVec, NORM_INFINITY, &norm_global_before); CHKERRQ(ierr);
1226 LOG_ALLOW(GLOBAL, LOG_INFO,"Max norm '%s' (Global) BEFORE Ghost Update: %g\n", fieldName, norm_global_before);
1227 // Optional: Norm of local vector before update (might contain old ghost values)
1228 // PetscReal norm_local_before;
1229 // ierr = VecNorm(localVec, NORM_INFINITY, &norm_local_before); CHKERRQ(ierr);
1230 // LOG_ALLOW(GLOBAL, LOG_DEBUG,"Max norm '%s' (Local) BEFORE Ghost Update: %g\n", fieldName, norm_local_before);
1231 }
1232
1233 // --- 4. Perform the Global-to-Local Transfer (Ghost Update) ---
1234 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Calling DMGlobalToLocalBegin/End for '%s'.\n", rank, fieldName);
1235 ierr = DMGlobalToLocalBegin(dm, globalVec, INSERT_VALUES, localVec); CHKERRQ(ierr);
1236 ierr = DMGlobalToLocalEnd(dm, globalVec, INSERT_VALUES, localVec); CHKERRQ(ierr);
1237 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Completed DMGlobalToLocalBegin/End for '%s'.\n", rank, fieldName);
1238
1239 // --- 5. Optional Debugging: Norm After Update ---
1240 // Use your logging convention check
1241 // if (get_log_level() >= LOG_LEVEL_DEBUG && is_function_allowed("UpdateLocalGhosts")) { // Example check
1242 if(get_log_level() == LOG_DEBUG && is_function_allowed(__func__)){ // Using your specific check
1243 PetscReal norm_local_after;
1244 ierr = VecNorm(localVec, NORM_INFINITY, &norm_local_after); CHKERRQ(ierr);
1245 LOG_ALLOW(GLOBAL, LOG_INFO,"Max norm '%s' (Local) AFTER Ghost Update: %g\n", fieldName, norm_local_after);
1246
1247 // --- 6. Optional Debugging: Specific Point Checks (Example for Ucat on Rank 0/1) ---
1248 // (Keep this conditional if it's only for specific debug scenarios)
1249 if (strcmp(fieldName, "Ucat") == 0) { // Only do detailed checks for Ucat for now
1250 PetscMPIInt rank_test;
1251 MPI_Comm_rank(PETSC_COMM_WORLD, &rank_test);
1252
1253 // Get Local Info needed for indexing checks
1254 DMDALocalInfo info_check;
1255 ierr = DMDAGetLocalInfo(dm, &info_check); CHKERRQ(ierr); // Use the correct dm
1256
1257 // Buffer for array pointer
1258 Cmpnts ***lUcat_arr_test = NULL;
1259 PetscErrorCode ierr_test = 0;
1260
1261 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Testing '%s' access immediately after ghost update...\n", rank_test, fieldName);
1262 ierr_test = DMDAVecGetArrayDOFRead(dm, localVec, &lUcat_arr_test); // Use correct dm and localVec
1263
1264 if (ierr_test) {
1265 LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR %d getting '%s' array after ghost update!\n", rank_test, ierr_test, fieldName);
1266 } else if (!lUcat_arr_test) {
1267 LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR NULL pointer getting '%s' array after ghost update!\n", rank_test, fieldName);
1268 }
1269 else {
1270 // Check owned interior point (e.g., first interior point)
1271 PetscInt k_int = info_check.zs + (info_check.zm > 1 ? 1 : 0); // Global k index (at least zs+1 if possible)
1272 PetscInt j_int = info_check.ys + (info_check.ym > 1 ? 1 : 0); // Global j index
1273 PetscInt i_int = info_check.xs + (info_check.xm > 1 ? 1 : 0); // Global i index
1274 // Ensure indices are within global bounds if domain is very small
1275 //if (k_int >= info_check.mz-1) k_int = info_check.mz-2; if (k_int < 1) k_int = 1;
1276 //if (j_int >= info_check.my-1) j_int = info_check.my-2; if (j_int < 1) j_int = 1;
1277 // if (i_int >= info_check.mx-1) i_int = info_check.mx-2; if (i_int < 1) i_int = 1;
1278 // clamp k_int to [1 .. mz-2]
1279 if (k_int >= info_check.mz - 1) {
1280 k_int = info_check.mz - 2;
1281 }
1282 if (k_int < 1) {
1283 k_int = 1;
1284 }
1285
1286 // clamp j_int to [1 .. my-2]
1287 if (j_int >= info_check.my - 1) {
1288 j_int = info_check.my - 2;
1289 }
1290 if (j_int < 1) {
1291 j_int = 1;
1292 }
1293
1294 // clamp i_int to [1 .. mx-2]
1295 if (i_int >= info_check.mx - 1) {
1296 i_int = info_check.mx - 2;
1297 }
1298 if (i_int < 1) {
1299 i_int = 1;
1300 }
1301
1302 // Only attempt read if indices are actually owned (relevant for multi-rank)
1303 if (k_int >= info_check.zs && k_int < info_check.zs + info_check.zm &&
1304 j_int >= info_check.ys && j_int < info_check.ys + info_check.ym &&
1305 i_int >= info_check.xs && i_int < info_check.xs + info_check.xm)
1306 {
1307 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);
1308 Cmpnts test_val_owned_interior = lUcat_arr_test[k_int][j_int][i_int];
1309 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading owned interior: x=%g\n", rank_test, test_val_owned_interior.x);
1310 } else {
1311 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);
1312 }
1313
1314
1315 // Check owned boundary point (e.g., first owned point)
1316 PetscInt k_bnd = info_check.zs; // Global k index
1317 PetscInt j_bnd = info_check.ys; // Global j index
1318 PetscInt i_bnd = info_check.xs; // Global i index
1319 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);
1320 Cmpnts test_val_owned_boundary = lUcat_arr_test[k_bnd][j_bnd][i_bnd];
1321 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading owned boundary: x=%g\n", rank_test, test_val_owned_boundary.x);
1322
1323
1324 // Check ghost point (e.g., one layer below in k, if applicable)
1325 if (info_check.zs > 0) { // Only if there's a rank below
1326 PetscInt k_ghost = info_check.zs - 1;
1327 PetscInt j_ghost = info_check.ys; // Use start of owned y, simple example
1328 PetscInt i_ghost = info_check.xs; // Use start of owned x, simple example
1329 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Attempting test read GHOST [%d][%d][%d] (Global)\n", rank_test, k_ghost, j_ghost, i_ghost);
1330 Cmpnts test_val_ghost = lUcat_arr_test[k_ghost][j_ghost][i_ghost];
1331 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: SUCCESS reading ghost: x=%g\n", rank_test, test_val_ghost.x);
1332 } else {
1333 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Skipping ghost test read (zs=0).\n", rank_test);
1334 }
1335
1336 // Restore the array
1337 ierr_test = DMDAVecRestoreArrayDOFRead(dm, localVec, &lUcat_arr_test);
1338 if(ierr_test){ LOG_ALLOW(LOCAL, LOG_ERROR, "Rank %d: ERROR %d restoring '%s' array after test read!\n", rank_test, ierr_test, fieldName); }
1339 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Finished testing '%s' access.\n", rank_test, fieldName);
1340 }
1341 } // end if Ucat
1342 } // end debug logging check
1343
1344 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Completed ghost update for field '%s'.\n", rank, fieldName);
1346 PetscFunctionReturn(0);
1347}
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:157
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
A 3D point or vector with PetscScalar components.
Definition variables.h:100
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.

Definition at line 1354 of file setup.c.

1355{
1356 PetscErrorCode ierr;
1357 PetscFunctionBeginUser;
1358
1360
1361 LOG_ALLOW(GLOBAL,LOG_INFO, "--- Setting up Boundary Conditions ---\n");
1362
1363 // --- Parse and Adapt for each block on the finest level ---
1364 LOG_ALLOW(GLOBAL,LOG_INFO,"Parsing BC configuration file and adapting to legacy system for finest grid.\n");
1365 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels-1].user;
1366 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
1367 LOG_ALLOW(GLOBAL,LOG_DEBUG, " -> Processing Block %d:\n", bi);
1368
1369 // --- Generate the filename for the current block ---
1370 const char *current_bc_filename = simCtx->bcs_files[bi];
1371 LOG_ALLOW(GLOBAL,LOG_DEBUG," -> Processing Block %d using config file '%s'\n", bi, current_bc_filename);
1372 // This will populate user_finest[bi].boundary_faces
1373 ierr = ParseAllBoundaryConditions(&user_finest[bi],current_bc_filename); CHKERRQ(ierr);
1374
1375 // Call the adapter to translate into the legacy format
1376 ierr = TranslateModernBCsToLegacy(&user_finest[bi]); CHKERRQ(ierr);
1377
1378 // Call the function to calculate the center of the inlet face, which may be used to calculate Boundary values.
1379 ierr = CalculateInletCenter(&user_finest[bi]); CHKERRQ(ierr);
1380 }
1381
1382 LOG_ALLOW(GLOBAL,LOG_INFO, "--- Boundary Conditions setup complete ---\n");
1383
1384
1386 PetscFunctionReturn(0);
1387}
PetscErrorCode TranslateModernBCsToLegacy(UserCtx *user)
Definition Boundaries.c:635
PetscErrorCode CalculateInletCenter(UserCtx *user)
Calculates the geometric center of the primary inlet face.
Definition grid.c:1054
PetscErrorCode ParseAllBoundaryConditions(UserCtx *user, const char *bcs_input_filename)
Parses the boundary conditions file to configure the type, handler, and any associated parameters for...
Definition io.c:399
Here is the call graph for this function:
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.

Definition at line 1411 of file setup.c.

1412{
1413 PetscErrorCode ierr;
1414 PetscReal ***data;
1415 PetscReal *dataContiguous;
1416 PetscInt k, j;
1417
1418 PetscFunctionBegin;
1419 /* Step 1: Allocate memory for an array of nz layer pointers (zero-initialized) */
1420 ierr = PetscCalloc1(nz, &data); CHKERRQ(ierr);
1421
1422 /* Step 2: Allocate memory for all row pointers (nz * ny pointers) */
1423 ierr = PetscCalloc1(nz * ny, &data[0]); CHKERRQ(ierr);
1424 for (k = 1; k < nz; k++) {
1425 data[k] = data[0] + k * ny;
1426 }
1427
1428 /* Step 3: Allocate one contiguous block for all data elements (nz*ny*nx) */
1429 ierr = PetscCalloc1(nz * ny * nx, &dataContiguous); CHKERRQ(ierr);
1430
1431 /* Build the 3D pointer structure: each row pointer gets the correct segment of data */
1432 for (k = 0; k < nz; k++) {
1433 for (j = 0; j < ny; j++) {
1434 data[k][j] = dataContiguous + (k * ny + j) * nx;
1435 /* Memory is already zeroed by PetscCalloc1, so no manual initialization is needed */
1436 }
1437 }
1438 *array = data;
1439 PetscFunctionReturn(0);
1440}

◆ 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.

Definition at line 1456 of file setup.c.

1457{
1458 PetscErrorCode ierr;
1459
1460 PetscFunctionBegin;
1461 if (!array || !array[0] || !array[0][0] ) { // Added more robust check
1462 LOG_ALLOW(GLOBAL, LOG_WARNING, "Deallocate3DArrayScalar called with potentially unallocated or NULL array.\n");
1463 if (array) {
1464 if (array[0]) { // Check if row pointers might exist
1465 // Cannot safely access array[0][0] if array[0] might be invalid/freed
1466 // Standard deallocation below assumes valid pointers.
1467 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free row pointers if they exist
1468 }
1469 ierr = PetscFree(array); CHKERRQ(ierr); // Free layer pointers if they exist
1470 }
1471 PetscFunctionReturn(0);
1472 }
1473
1474 // --- Standard Deallocation (assuming valid allocation) ---
1475
1476 /* 1. Free the contiguous block of PetscReal values.
1477 The starting address was stored in array[0][0]. */
1478 ierr = PetscFree(array[0][0]); CHKERRQ(ierr); // Free the ACTUAL DATA
1479
1480 /* 2. Free the contiguous block of row pointers.
1481 The starting address was stored in array[0]. */
1482 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free the ROW POINTERS
1483
1484 /* 3. Free the layer pointer array.
1485 The starting address is 'array' itself. */
1486 ierr = PetscFree(array); CHKERRQ(ierr); // Free the LAYER POINTERS
1487
1488 PetscFunctionReturn(0);
1489}
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30

◆ Allocate3DArrayVector()

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

Allocates a 3D array of Cmpnts structures using PetscCalloc.

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

This function dynamically allocates memory for a 3D array of Cmpnts (vector) structures with dimensions nz (layers) x ny (rows) x nx (columns). It uses PetscCalloc1 to ensure that all allocated memory is zero-initialized.

The allocation procedure is similar to Allocate3DArrayScalar:

  1. Allocate an array of nz pointers (one for each layer).
  2. Allocate a contiguous block for nz*ny row pointers.
  3. Allocate one contiguous block for nz*ny*nx Cmpnts structures.

After allocation, the array can be accessed as array[k][j][i] and each element (a Cmpnts structure) will have its x, y, and z fields initialized to 0.0.

Parameters
[out]arrayPointer to the 3D array to be allocated.
[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.

Definition at line 1513 of file setup.c.

1514{
1515 PetscErrorCode ierr;
1516 Cmpnts ***data;
1517 Cmpnts *dataContiguous;
1518 PetscInt k, j;
1519 PetscMPIInt rank;
1520
1521 PetscFunctionBegin;
1522
1523 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
1524
1525 /* Step 1: Allocate memory for nz layer pointers (zeroed) */
1526 ierr = PetscCalloc1(nz, &data); CHKERRQ(ierr);
1527
1528 LOG_ALLOW(LOCAL,LOG_DEBUG," [Rank %d] memory allocated for outermost layer (%d k-layer pointers).\n",rank,nz);
1529
1530 /* Step 2: Allocate memory for all row pointers (nz * ny pointers) */
1531 ierr = PetscCalloc1(nz * ny, &data[0]); CHKERRQ(ierr);
1532 for (k = 1; k < nz; k++) {
1533 data[k] = data[0] + k * ny;
1534 }
1535
1536 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d] memory allocated for %dx%d row pointers.\n",rank,nz,ny);
1537
1538 /* Step 3: Allocate one contiguous block for nz*ny*nx Cmpnts structures (zeroed) */
1539 ierr = PetscCalloc1(nz * ny * nx, &dataContiguous); CHKERRQ(ierr);
1540
1541 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[Rank %d] memory allocated for contigous block of %dx%dx%d Cmpnts structures).\n",rank,nz,ny,nx);
1542
1543 /* Build the 3D pointer structure for vector data */
1544 for (k = 0; k < nz; k++) {
1545 for (j = 0; j < ny; j++) {
1546 data[k][j] = dataContiguous + (k * ny + j) * nx;
1547 /* The PetscCalloc1 call has already initialized each Cmpnts to zero. */
1548 }
1549 }
1550
1551 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[Rank %d] 3D pointer structure for vector data created. \n",rank);
1552
1553 *array = data;
1554 PetscFunctionReturn(0);
1555}

◆ 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.

Definition at line 1571 of file setup.c.

1572{
1573 PetscErrorCode ierr;
1574
1575 PetscFunctionBegin;
1576 // If array is NULL or hasn't been allocated properly, just return.
1577 if (!array || !array[0] || !array[0][0] ) {
1578 LOG_ALLOW(GLOBAL, LOG_WARNING, "Deallocate3DArrayVector called with potentially unallocated or NULL array.\n");
1579 // Attempt to free what might exist, but be cautious
1580 if (array) {
1581 if (array[0]) { // Check if row pointers were allocated
1582 // We don't have a direct pointer to the contiguous data block
1583 // saved separately in this allocation scheme. The allocation relies
1584 // on array[0][0] pointing to it. If array[0] was freed first,
1585 // accessing array[0][0] is unsafe.
1586 // The allocation scheme where the contiguous data block is not
1587 // stored separately makes safe deallocation tricky if freeing
1588 // happens out of order or if parts are NULL.
1589
1590 // A SAFER ALLOCATION/DEALLOCATION would store the data pointer separately.
1591 // Given the current allocation scheme, the order MUST be:
1592 // 1. Free the data block (pointed to by array[0][0])
1593 // 2. Free the row pointer block (pointed to by array[0])
1594 // 3. Free the layer pointer block (pointed to by array)
1595
1596 // Let's assume the allocation was successful and pointers are valid.
1597 // Get pointer to the contiguous data block *before* freeing row pointers
1598 Cmpnts *dataContiguous = array[0][0];
1599 ierr = PetscFree(dataContiguous); CHKERRQ(ierr); // Free data block
1600
1601 // Now free the row pointers block
1602 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free row pointers
1603
1604 }
1605 // Finally, free the array of layer pointers
1606 ierr = PetscFree(array); CHKERRQ(ierr);
1607 }
1608 PetscFunctionReturn(0); // Return gracefully if input was NULL initially
1609 }
1610
1611
1612 // --- Standard Deallocation (assuming valid allocation) ---
1613
1614 /* 1. Free the contiguous block of Cmpnts structures.
1615 The starting address was stored in array[0][0] by Allocate3DArrayVector. */
1616 ierr = PetscFree(array[0][0]); CHKERRQ(ierr); // Free the ACTUAL DATA
1617
1618 /* 2. Free the contiguous block of row pointers.
1619 The starting address was stored in array[0]. */
1620 ierr = PetscFree(array[0]); CHKERRQ(ierr); // Free the ROW POINTERS
1621
1622 /* 3. Free the layer pointer array.
1623 The starting address is 'array' itself. */
1624 ierr = PetscFree(array); CHKERRQ(ierr); // Free the LAYER POINTERS
1625
1626 PetscFunctionReturn(0);
1627}

◆ GetOwnedCellRange()

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

Gets the global starting index of cells owned by this rank and the number of such cells.

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

A cell's global index is considered the same as its origin node's global index. This function assumes a node-centered DMDA where info_nodes provides all necessary information:

  • info_nodes->xs, ys, zs: Global starting index of the first node owned by this rank (excluding ghosts).
  • info_nodes->xm, ym, zm: Number of nodes owned by this rank in each dimension (excluding ghosts).
  • info_nodes->mx, my, mz: Total number of global nodes in each dimension for the entire domain.

A cell C_k (0-indexed) is defined by its origin node N_k and extends to node N_{k+1}. Thus, the last node in the global domain cannot be an origin for a cell. The last possible cell origin node index is PhysicalGlobalNodesInDim - 2.

Warning
THIS FUNCTION MAKES A CRITICAL ASSUMPTION: It assumes the DMDA it receives information from was created with dimensions of (physical_nodes_x + 1), (physical_nodes_y + 1), etc., where the +1 node is a "user-defined ghost" not meant for physical calculations. It will internally subtract 1 from the global dimensions (mx, my, mz) before calculating the number of cells.
Parameters
[in]info_nodesPointer to the DMDALocalInfo struct for the current rank. This struct contains local ownership information (xs, xm, etc.) and global domain dimensions (mx, my, mz for nodes).
[in]dimThe dimension for which to get the cell range (0 for i/x, 1 for j/y, 2 for k/z).
[out]xs_cell_global_outPointer to store the global index of the first cell whose origin node is owned by this rank.
[out]xm_cell_local_outPointer to store the number of cells for which this rank owns the origin node.
Returns
PetscErrorCode 0 on success, or an error code on failure.

Definition at line 1663 of file setup.c.

1667{
1668 PetscErrorCode ierr = 0; // Standard PETSc error code, not explicitly set here but good practice.
1669 PetscInt xs_node_global_rank; // Global index of the first node owned by this rank in the specified dimension.
1670 PetscInt num_nodes_owned_rank; // Number of nodes owned by this rank in this dimension (local count, excluding ghosts).
1671 PetscInt GlobalNodesInDim_from_info; // Total number of DA points in this dimension, from DMDALocalInfo.
1672
1673 PetscFunctionBeginUser;
1674
1675 // --- 1. Input Validation ---
1676 if (!info_nodes || !xs_cell_global_out || !xm_cell_local_out) {
1677 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null pointer passed to GetOwnedCellRange.");
1678 }
1679
1680 // --- 2. Extract Node Ownership and Global Dimension Information from DMDALocalInfo ---
1681 if (dim == 0) { // I-direction
1682 xs_node_global_rank = info_nodes->xs;
1683 num_nodes_owned_rank = info_nodes->xm;
1684 GlobalNodesInDim_from_info = info_nodes->mx;
1685 } else if (dim == 1) { // J-direction
1686 xs_node_global_rank = info_nodes->ys;
1687 num_nodes_owned_rank = info_nodes->ym;
1688 GlobalNodesInDim_from_info = info_nodes->my;
1689 } else if (dim == 2) { // K-direction
1690 xs_node_global_rank = info_nodes->zs;
1691 num_nodes_owned_rank = info_nodes->zm;
1692 GlobalNodesInDim_from_info = info_nodes->mz;
1693 } else {
1694 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d in GetOwnedCellRange. Must be 0, 1, or 2.", dim);
1695 }
1696
1697 // --- 3. Correct for User-Defined Ghost Node ---
1698 // Per the function's contract (@warning), the DA size includes an extra, non-physical
1699 // node. We subtract 1 to get the true number of physical nodes for cell calculations.
1700 const PetscInt physical_nodes_in_dim = GlobalNodesInDim_from_info - 1;
1701
1702 // --- 4. Handle Edge Cases for Physical Domain Size ---
1703 // If the physical domain has 0 or 1 node, no cells can be formed.
1704 if (physical_nodes_in_dim <= 1) {
1705 *xs_cell_global_out = xs_node_global_rank; // Still report the rank's starting node
1706 *xm_cell_local_out = 0; // But 0 cells
1707 PetscFunctionReturn(0);
1708 }
1709
1710 // --- 5. Determine Cell Ownership Based on Corrected Node Ownership ---
1711 // The first cell this rank *could* define has its origin at the first node this rank owns.
1712 *xs_cell_global_out = xs_node_global_rank;
1713
1714 // If the rank owns no nodes in this dimension, it can't form any cell origins.
1715 if (num_nodes_owned_rank == 0) {
1716 *xm_cell_local_out = 0;
1717 } else {
1718 // --- BUG FIX APPLIED HERE ---
1719 // The previous logic incorrectly assumed a cell's end node (N_{k+1}) must be on the
1720 // same rank as its origin node (N_k). The correct logic is to find the intersection
1721 // between the nodes this rank owns and the nodes that are valid origins globally.
1722
1723 // The first node owned by the rank is its first potential origin.
1724 PetscInt first_owned_origin = xs_node_global_rank;
1725
1726 // The absolute last node owned by this rank. Any node up to and including this one
1727 // is a potential cell origin from this rank's perspective.
1728 PetscInt last_node_owned_by_rank = xs_node_global_rank + num_nodes_owned_rank - 1;
1729
1730 // The absolute last node in the entire PHYSICAL domain that can serve as a cell origin.
1731 // If there are `N` physical nodes (0 to N-1), this index is `N-2`.
1732 PetscInt last_possible_origin_global_idx = physical_nodes_in_dim - 2;
1733
1734 // The actual last origin this rank can provide is the *minimum* of what it owns
1735 // and what is globally possible. This correctly handles both ranks in the middle of
1736 // the domain and the very last rank.
1737 PetscInt actual_last_origin_this_rank_can_form = PetscMin(last_node_owned_by_rank, last_possible_origin_global_idx);
1738
1739 // If the first potential origin this rank owns is already beyond the actual last
1740 // origin it can form, then this rank forms no valid cell origins. This happens if
1741 // the rank only owns the very last physical node.
1742 if (first_owned_origin > actual_last_origin_this_rank_can_form) {
1743 *xm_cell_local_out = 0;
1744 } else {
1745 // The number of cells is the count of valid origins this rank owns.
1746 // (Count = Last Index - First Index + 1)
1747 *xm_cell_local_out = actual_last_origin_this_rank_can_form - first_owned_origin + 1;
1748 }
1749 }
1750
1751 PetscFunctionReturn(ierr);
1752}
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. If DMDAGetNeighbors returns a negative rank that is not MPI_PROC_NULL (which can happen in some PETSc/MPI configurations for non-periodic boundaries if not fully standard), this function will sanitize it to MPI_PROC_NULL to prevent issues.

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

Definition at line 1770 of file setup.c.

1771{
1772 PetscErrorCode ierr;
1773 PetscMPIInt rank;
1774 PetscMPIInt size; // MPI communicator size
1775 const PetscMPIInt *neighbor_ranks_ptr; // Pointer to raw neighbor data from PETSc
1776
1777 PetscFunctionBeginUser;
1779 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1780 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr); // Get MPI size for validation
1781
1782 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Computing DMDA neighbor ranks.\n", rank);
1783
1784 if (!user || !user->da) {
1785 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx or user->da is NULL in ComputeAndStoreNeighborRanks.");
1786 }
1787
1788 // Get the neighbor information from the DMDA
1789 // neighbor_ranks_ptr will point to an internal PETSc array of 27 ranks.
1790 ierr = DMDAGetNeighbors(user->da, &neighbor_ranks_ptr); CHKERRQ(ierr);
1791
1792 // Log the raw values from DMDAGetNeighbors for boundary-relevant directions for debugging
1793 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",
1794 rank,
1795 neighbor_ranks_ptr[12], neighbor_ranks_ptr[14],
1796 neighbor_ranks_ptr[10], neighbor_ranks_ptr[16],
1797 neighbor_ranks_ptr[4], neighbor_ranks_ptr[22],
1798 (int)MPI_PROC_NULL);
1799
1800 // PETSc standard indices for 3D face neighbors from the 27-point stencil:
1801 // Index = k_offset*9 + j_offset*3 + i_offset (where offsets -1,0,1 map to 0,1,2)
1802 // Center: (i_off=1, j_off=1, k_off=1) => 1*9 + 1*3 + 1 = 13
1803 // X-min: (i_off=0, j_off=1, k_off=1) => 1*9 + 1*3 + 0 = 12
1804 // X-plus: (i_off=2, j_off=1, k_off=1) => 1*9 + 1*3 + 2 = 14
1805 // Y-min: (i_off=1, j_off=0, k_off=1) => 1*9 + 0*3 + 1 = 10
1806 // Y-plus: (i_off=1, j_off=2, k_off=1) => 1*9 + 2*3 + 1 = 16
1807 // Z-min: (i_off=1, j_off=1, k_off=0) => 0*9 + 1*3 + 1 = 4
1808 // Z-plus: (i_off=1, j_off=1, k_off=2) => 2*9 + 1*3 + 1 = 22
1809
1810 if (neighbor_ranks_ptr[13] != rank) {
1811 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",
1812 rank, neighbor_ranks_ptr[13], rank);
1813 // This warning is important. If the center isn't the current rank, the offsets are likely wrong.
1814 // However, PETSc should ensure this unless the DM is too small for a 3x3x3 stencil.
1815 }
1816
1817 // Assign and sanitize each neighbor rank
1818 PetscMPIInt temp_neighbor;
1819
1820 temp_neighbor = neighbor_ranks_ptr[12]; // xm
1821 if (temp_neighbor < 0 || temp_neighbor >= size) {
1822 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);
1823 user->neighbors.rank_xm = MPI_PROC_NULL;
1824 } else {
1825 user->neighbors.rank_xm = temp_neighbor;
1826 }
1827
1828 temp_neighbor = neighbor_ranks_ptr[14]; // xp
1829 if (temp_neighbor < 0 || temp_neighbor >= size) {
1830 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);
1831 user->neighbors.rank_xp = MPI_PROC_NULL;
1832 } else {
1833 user->neighbors.rank_xp = temp_neighbor;
1834 }
1835
1836 temp_neighbor = neighbor_ranks_ptr[10]; // ym
1837 if (temp_neighbor < 0 || temp_neighbor >= size) {
1838 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);
1839 user->neighbors.rank_ym = MPI_PROC_NULL;
1840 } else {
1841 user->neighbors.rank_ym = temp_neighbor;
1842 }
1843
1844 temp_neighbor = neighbor_ranks_ptr[16]; // yp
1845 if (temp_neighbor < 0 || temp_neighbor >= size) {
1846 // The log for index 16 was "zm" in your output, should be yp
1847 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);
1848 user->neighbors.rank_yp = MPI_PROC_NULL;
1849 } else {
1850 user->neighbors.rank_yp = temp_neighbor;
1851 }
1852
1853 temp_neighbor = neighbor_ranks_ptr[4]; // zm
1854 if (temp_neighbor < 0 || temp_neighbor >= size) {
1855 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);
1856 user->neighbors.rank_zm = MPI_PROC_NULL;
1857 } else {
1858 user->neighbors.rank_zm = temp_neighbor;
1859 }
1860
1861 temp_neighbor = neighbor_ranks_ptr[22]; // zp
1862 if (temp_neighbor < 0 || temp_neighbor >= size) {
1863 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);
1864 user->neighbors.rank_zp = MPI_PROC_NULL;
1865 } else {
1866 user->neighbors.rank_zp = temp_neighbor;
1867 }
1868
1869 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,
1870 user->neighbors.rank_xm, user->neighbors.rank_xp,
1871 user->neighbors.rank_ym, user->neighbors.rank_yp,
1872 user->neighbors.rank_zm, user->neighbors.rank_zp);
1873 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); // Ensure logs are flushed
1874
1875 // Note: neighbor_ranks_ptr memory is managed by PETSc, do not free it.
1877 PetscFunctionReturn(0);
1878}
PetscMPIInt rank_zm
Definition variables.h:179
PetscMPIInt rank_yp
Definition variables.h:178
PetscMPIInt rank_ym
Definition variables.h:178
PetscMPIInt rank_xp
Definition variables.h:177
RankNeighbors neighbors
Definition variables.h:673
PetscMPIInt rank_xm
Definition variables.h:177
PetscMPIInt rank_zp
Definition variables.h:179
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.

Definition at line 1897 of file setup.c.

1898{
1899 PetscErrorCode ierr;
1900 PetscMPIInt size, rank;
1901 PetscInt px = PETSC_DECIDE, py = PETSC_DECIDE, pz = PETSC_DECIDE;
1902 PetscBool px_set = PETSC_FALSE, py_set = PETSC_FALSE, pz_set = PETSC_FALSE;
1903 SimCtx *simCtx = user->simCtx;
1904
1905 // Set no.of processors in direction 1
1906 if(simCtx->da_procs_x) {
1907 px_set = PETSC_TRUE;
1908 px = simCtx->da_procs_x;
1909 }
1910 // Set no.of processors in direction 2
1911 if(simCtx->da_procs_y) {
1912 py_set = PETSC_TRUE;
1913 py = simCtx->da_procs_y;
1914 }
1915 // Set no.of processors in direction 1
1916 if(simCtx->da_procs_z) {
1917 pz_set = PETSC_TRUE;
1918 pz = simCtx->da_procs_z;
1919 }
1920
1921 PetscFunctionBeginUser;
1923 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size); CHKERRQ(ierr);
1924 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank); CHKERRQ(ierr);
1925 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank %d: Configuring DMDA processor layout for %d total processes.\n", rank, size);
1926
1927 // --- Validate User Input (Optional but Recommended) ---
1928 // Check if specified processor counts multiply to the total MPI size
1929 if (px_set && py_set && pz_set) {
1930 if (px * py * pz != size) {
1931 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP,
1932 "Specified processor layout %d x %d x %d = %d does not match MPI size %d",
1933 px, py, pz, px * py * pz, size);
1934 }
1935 LOG_ALLOW(GLOBAL, LOG_INFO, "Using specified processor layout: %d x %d x %d\n", px, py, pz);
1936 } else if (px_set || py_set || pz_set) {
1937 // If only some are set, PETSC_DECIDE will be used for others
1938 LOG_ALLOW(GLOBAL, LOG_INFO, "Using partially specified processor layout: %d x %d x %d (PETSC_DECIDE for unspecified)\n", px, py, pz);
1939 } else {
1940 LOG_ALLOW(GLOBAL, LOG_INFO, "Using fully automatic processor layout (PETSC_DECIDE x PETSC_DECIDE x PETSC_DECIDE)\n");
1941 }
1942 // Additional checks: Ensure px, py, pz are positive if set
1943 if ((px_set && px <= 0) || (py_set && py <= 0) || (pz_set && pz <= 0)) {
1944 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Specified processor counts must be positive.");
1945 }
1946
1947
1948 // --- Apply the layout to the DMDA ---
1949 ierr = DMDASetNumProcs(dm, px, py, pz); CHKERRQ(ierr);
1950 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Rank %d: DMDASetNumProcs called with px=%d, py=%d, pz=%d.\n", rank, px, py, pz);
1951
1952 // --- Store the values in UserCtx (Optional) ---
1953 // Note: If PETSC_DECIDE was used, PETSc calculates the actual values during DMSetUp.
1954 // We store the *requested* values here. To get the *actual* values used,
1955 // you would need to call DMDAGetInfo after DMSetUp.
1956 /*
1957 if (user) {
1958 user->procs_x = px;
1959 user->procs_y = py;
1960 user->procs_z = pz;
1961 }
1962 */
1964 PetscFunctionReturn(0);
1965}

◆ SetupDomainRankInfo()

PetscErrorCode SetupDomainRankInfo ( SimCtx simCtx)

Sets up the full rank communication infrastructure for all blocks.

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

This function orchestrates the setup of the parallel communication map. It uses the existing helper functions to sequentially gather and broadcast the bounding box information for each computational block. All ranks participate in each step, assembling the final, unified multi-block list in parallel.

Parameters
[in,out]simCtxThe master simulation context. After this call, simCtx->bboxlist and the relevant user->neighbors fields will be populated on all ranks.

Definition at line 1981 of file setup.c.

1982{
1983 PetscErrorCode ierr;
1984 PetscInt nblk = simCtx->block_number;
1985 PetscInt size = simCtx->size;
1986 BoundingBox *final_bboxlist = NULL;
1987
1988 PetscFunctionBeginUser;
1990
1991 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting full rank communication setup for %d block(s).\n", nblk);
1992
1993 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1994
1995 // --- Step 1: Compute neighbor ranks (unchanged) ---
1996 for (int bi = 0; bi < nblk; bi++) {
1997 ierr = ComputeAndStoreNeighborRanks(&user_finest[bi]); CHKERRQ(ierr);
1998 }
1999 LOG_ALLOW(GLOBAL, LOG_INFO, "Neighbor ranks computed and stored for all blocks.\n");
2000
2001 // --- Step 2: Allocate the final, unified list on ALL ranks ---
2002 // Every rank will build this list in parallel.
2003 ierr = PetscMalloc1(size * nblk, &final_bboxlist); CHKERRQ(ierr);
2004
2005 // --- Step 3: Loop through each block, gather then broadcast its bbox list ---
2006 for (int bi = 0; bi < nblk; bi++) {
2007 // This is a temporary pointer for the current block's list.
2008 BoundingBox *block_bboxlist = NULL;
2009
2010 LOG_ALLOW(GLOBAL, LOG_INFO, "Processing bounding boxes for block %d...\n", bi);
2011
2012 // A) GATHER: On rank 0, block_bboxlist is allocated and filled. On others, it's NULL.
2013 ierr = GatherAllBoundingBoxes(&user_finest[bi], &block_bboxlist); CHKERRQ(ierr);
2014 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Gather complete for block %d.\n", bi);
2015
2016 // B) BROADCAST: On non-root ranks, block_bboxlist is allocated. Then, the data
2017 // from rank 0 is broadcast to all ranks. After this call, ALL ranks have
2018 // an identical, complete copy of the bounding boxes for the current block.
2019 ierr = BroadcastAllBoundingBoxes(&user_finest[bi], &block_bboxlist); CHKERRQ(ierr);
2020 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Broadcast complete for block %d.\n", bi);
2021
2022 // C) ASSEMBLE: Every rank now copies the data for this block into the
2023 // correct segment of its final, unified list.
2024 for (int r = 0; r < size; r++) {
2025 // The layout is [r0b0, r1b0, ..., r(size-1)b0, r0b1, r1b1, ...]
2026 final_bboxlist[bi * size + r] = block_bboxlist[r];
2027 }
2028 LOG_ALLOW(GLOBAL, LOG_DEBUG, " -> Assembly into final list complete for block %d.\n", bi);
2029
2030 // D) CLEANUP: Free the temporary list for this block on ALL ranks before the next iteration.
2031 // Your helper functions use malloc, so we must use free.
2032 free(block_bboxlist);
2033 }
2034
2035 // --- Step 4: Assign the final pointer and run the last setup step ---
2036 simCtx->bboxlist = final_bboxlist;
2037 LOG_ALLOW(GLOBAL, LOG_INFO, "Final unified bboxlist created on all ranks and stored in SimCtx.\n");
2038
2039 ierr = SetupDomainCellDecompositionMap(&user_finest[0]); CHKERRQ(ierr);
2040 LOG_ALLOW(GLOBAL, LOG_INFO, "Domain Cell Composition set and broadcasted.\n");
2041
2042 LOG_ALLOW(GLOBAL, LOG_INFO, "SetupDomainRankInfo: Completed successfully.\n");
2043
2045 PetscFunctionReturn(0);
2046}
PetscErrorCode BroadcastAllBoundingBoxes(UserCtx *user, BoundingBox **bboxlist)
Broadcasts the bounding box information collected on rank 0 to all other ranks.
Definition grid.c:996
PetscErrorCode GatherAllBoundingBoxes(UserCtx *user, BoundingBox **allBBoxes)
Gathers local bounding boxes from all MPI processes to rank 0.
Definition grid.c:928
PetscErrorCode ComputeAndStoreNeighborRanks(UserCtx *user)
Computes and stores the Cartesian neighbor ranks for the DMDA decomposition.
Definition setup.c:1770
PetscErrorCode SetupDomainCellDecompositionMap(UserCtx *user)
Creates and distributes a map of the domain's cell decomposition to all ranks.
Definition setup.c:2242
Defines a 3D axis-aligned bounding box.
Definition variables.h:154
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 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 caller is responsible for subsequently applying boundary conditions to user->Ucat and calling UpdateLocalGhosts(user, "Ucat") to populate user->lUcat.

Definition at line 2084 of file setup.c.

2085{
2086 PetscErrorCode ierr;
2087 DMDALocalInfo info;
2088 Cmpnts ***lcsi_arr, ***leta_arr, ***lzet_arr; // Local metric arrays
2089 Cmpnts ***lucont_arr; // Local contravariant velocity array
2090 Cmpnts ***gucat_arr; // Global Cartesian velocity array
2091 PetscReal ***lnvert_arr; // Local Nvert array
2092 PetscReal ***laj_arr; // Local Jacobian Determinant inverse array
2093
2094 PetscFunctionBeginUser;
2096 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Starting Contravariant-to-Cartesian velocity transformation.\n");
2097
2098 // --- 1. Get DMDA Info and Check for Valid Inputs ---
2099 // All inputs (lUcont, lCsi, etc.) and outputs (Ucat) are on DMs from the UserCtx.
2100 // We get local info from fda, which governs the layout of most arrays here.
2101 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2102 if (!user->lUcont || !user->lCsi || !user->lEta || !user->lZet || !user->lNvert || !user->Ucat) {
2103 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Contra2Cart requires lUcont, lCsi/Eta/Zet, lNvert, and Ucat to be non-NULL.");
2104 }
2105
2106
2107 // --- 2. Get Read-Only Array Access to Local Input Vectors (with ghosts) ---
2108 ierr = DMDAVecGetArrayRead(user->fda, user->lUcont, &lucont_arr); CHKERRQ(ierr);
2109 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &lcsi_arr); CHKERRQ(ierr);
2110 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &leta_arr); CHKERRQ(ierr);
2111 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &lzet_arr); CHKERRQ(ierr);
2112 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, &lnvert_arr); CHKERRQ(ierr);
2113 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &laj_arr); CHKERRQ(ierr);
2114
2115 // --- 3. Get Write-Only Array Access to the Global Output Vector ---
2116 // We compute for local owned cells and write into the global vector.
2117 // PETSc handles mapping the global indices to the correct local memory locations.
2118 ierr = DMDAVecGetArray(user->fda, user->Ucat, &gucat_arr); CHKERRQ(ierr);
2119
2120
2121 // --- 4. Define Loop Bounds for INTERIOR Cells ---
2122 // We use adjusted bounds to avoid calculating Ucat on the physical domain boundaries,
2123 // as these are typically set explicitly by boundary condition functions.
2124 // The stencils use indices like i-1, j-1, k-1, so we must start loops at least at index 1.
2125 PetscInt i_start = (info.xs == 0) ? info.xs + 1 : info.xs;
2126 PetscInt i_end = (info.xs + info.xm == info.mx) ? info.xs + info.xm - 1 : info.xs + info.xm;
2127
2128 PetscInt j_start = (info.ys == 0) ? info.ys + 1 : info.ys;
2129 PetscInt j_end = (info.ys + info.ym == info.my) ? info.ys + info.ym - 1 : info.ys + info.ym;
2130
2131 PetscInt k_start = (info.zs == 0) ? info.zs + 1 : info.zs;
2132 PetscInt k_end = (info.zs + info.zm == info.mz) ? info.zs + info.zm - 1 : info.zs + info.zm;
2133
2134 // --- 5. Main Computation Loop ---
2135 // Loops over the GLOBAL indices of interior cells owned by this rank.
2136 for (PetscInt k_cell = k_start; k_cell < k_end; ++k_cell) {
2137 for (PetscInt j_cell = j_start; j_cell < j_end; ++j_cell) {
2138 for (PetscInt i_cell = i_start; i_cell < i_end; ++i_cell) {
2139
2140 // Check if the cell is a fluid cell (not solid/blanked)
2141 // if (lnvert_arr[k_cell][j_cell][i_cell] > 0.1) continue; // Skip solid/blanked cells
2142
2143 // Transformation matrix [mat] is the metric tensor at the cell center,
2144 // estimated by averaging metrics from adjacent faces.
2145 PetscReal mat[3][3];
2146
2147 // PetscReal aj_center = laj_arr[k_cell+1][j_cell+1][i_cell+1];
2148
2149 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;
2150 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;
2151 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;
2152
2153 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;
2154 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;
2155 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;
2156
2157 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;
2158 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;
2159 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;
2160
2161 // Contravariant velocity vector `q` at the cell center,
2162 // estimated by averaging face-based contravariant velocities.
2163 PetscReal q[3];
2164 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
2165 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
2166 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
2167
2168 // Solve the 3x3 system `mat * ucat = q` using Cramer's rule.
2169 PetscReal det = mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
2170 mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
2171 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]);
2172
2173 if (PetscAbsReal(det) < 1.0e-18) {
2174 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);
2175 }
2176
2177 PetscReal det_inv = 1.0 / det;
2178
2179 PetscReal det0 = q[0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
2180 q[1] * (mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) +
2181 q[2] * (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]);
2182
2183 PetscReal det1 = -q[0] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
2184 q[1] * (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) -
2185 q[2] * (mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]);
2186
2187 PetscReal det2 = q[0] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) -
2188 q[1] * (mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) +
2189 q[2] * (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]);
2190
2191 // Store computed Cartesian velocity in the GLOBAL Ucat array at the
2192 // array index corresponding to the cell's origin node.
2193 gucat_arr[k_cell][j_cell][i_cell].x = det0 * det_inv;
2194 gucat_arr[k_cell][j_cell][i_cell].y = det1 * det_inv;
2195 gucat_arr[k_cell][j_cell][i_cell].z = det2 * det_inv;
2196 }
2197 }
2198 }
2199
2200 // --- 6. Restore Array Access ---
2201 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcont, &lucont_arr); CHKERRQ(ierr);
2202 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &lcsi_arr); CHKERRQ(ierr);
2203 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &leta_arr); CHKERRQ(ierr);
2204 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &lzet_arr); CHKERRQ(ierr);
2205 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, &lnvert_arr); CHKERRQ(ierr);
2206 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &laj_arr); CHKERRQ(ierr);
2207 ierr = DMDAVecRestoreArray(user->fda, user->Ucat, &gucat_arr); CHKERRQ(ierr);
2208
2209 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed Contravariant-to-Cartesian velocity transformation. \n");
2211 PetscFunctionReturn(0);
2212}
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.

Definition at line 2242 of file setup.c.

2243{
2244 PetscErrorCode ierr;
2245 DMDALocalInfo local_node_info;
2246 RankCellInfo my_cell_info;
2247 PetscMPIInt rank, size;
2248
2249 PetscFunctionBeginUser;
2251
2252 // --- 1. Input Validation and MPI Info ---
2253 if (!user) {
2254 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx pointer is NULL in SetupDomainCellDecompositionMap.");
2255 }
2256 if (!user->da) {
2257 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "user->da is not initialized in SetupDomainCellDecompositionMap.");
2258 }
2259
2260 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2261 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
2262
2263 LOG_ALLOW(GLOBAL, LOG_INFO, "Setting up domain cell decomposition map for %d ranks.\n", size);
2264
2265 // --- 2. Determine Local Cell Ownership ---
2266 // Get the local node ownership information from the primary DMDA.
2267 ierr = DMDAGetLocalInfo(user->da, &local_node_info); CHKERRQ(ierr);
2268
2269 // Use the robust helper function to convert node ownership to cell ownership.
2270 // A cell's index is defined by its origin node.
2271
2272 ierr = GetOwnedCellRange(&local_node_info, 0, &my_cell_info.xs_cell, &my_cell_info.xm_cell); CHKERRQ(ierr);
2273 ierr = GetOwnedCellRange(&local_node_info, 1, &my_cell_info.ys_cell, &my_cell_info.ym_cell); CHKERRQ(ierr);
2274 ierr = GetOwnedCellRange(&local_node_info, 2, &my_cell_info.zs_cell, &my_cell_info.zm_cell); CHKERRQ(ierr);
2275
2276 // Log the calculated local ownership for debugging purposes.
2277 LOG_ALLOW(LOCAL, LOG_DEBUG, "[Rank %d] Owns cells: i[%d, %d), j[%d, %d), k[%d, %d)\n",
2278 rank, my_cell_info.xs_cell, my_cell_info.xs_cell + my_cell_info.xm_cell,
2279 my_cell_info.ys_cell, my_cell_info.ys_cell + my_cell_info.ym_cell,
2280 my_cell_info.zs_cell, my_cell_info.zs_cell + my_cell_info.zm_cell);
2281
2282 // --- 3. Allocate and Distribute the Global Map ---
2283 // Allocate memory for the global map that will hold information from all ranks.
2284 ierr = PetscMalloc1(size, &user->RankCellInfoMap); CHKERRQ(ierr);
2285
2286 // Perform the collective communication to gather the `RankCellInfo` struct from every rank.
2287 // Each rank sends its `my_cell_info` and receives the complete array in `user->RankCellInfoMap`.
2288 // We use MPI_BYTE to ensure portability across different systems and struct padding.
2289 ierr = MPI_Allgather(&my_cell_info, sizeof(RankCellInfo), MPI_BYTE,
2290 user->RankCellInfoMap, sizeof(RankCellInfo), MPI_BYTE,
2291 PETSC_COMM_WORLD); CHKERRQ(ierr);
2292
2293 LOG_ALLOW(GLOBAL, LOG_INFO, "Domain cell decomposition map created and distributed successfully.\n");
2294
2296 PetscFunctionReturn(0);
2297}
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global_out, PetscInt *xm_cell_local_out)
Gets the global starting index of cells owned by this rank and the number of such cells.
Definition setup.c:1663
PetscInt ys_cell
Definition variables.h:184
PetscInt xs_cell
Definition variables.h:184
PetscInt zm_cell
Definition variables.h:185
PetscInt zs_cell
Definition variables.h:184
PetscInt xm_cell
Definition variables.h:185
RankCellInfo * RankCellInfoMap
Definition variables.h:728
PetscInt ym_cell
Definition variables.h:185
A lean struct to hold the global cell ownership range for a single MPI rank.
Definition variables.h:183
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.

Definition at line 2318 of file setup.c.

2319{
2320 PetscInt low = 0, high = n - 1;
2321
2322 PetscFunctionBeginUser;
2324
2325 // --- 1. Input Validation ---
2326 if (!found) {
2327 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Output pointer 'found' is NULL in PetscBinarySearchInt64.");
2328 }
2329 if (n > 0 && !arr) {
2330 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input array 'arr' is NULL for n > 0.");
2331 }
2332
2333 // Initialize output
2334 *found = PETSC_FALSE;
2335
2336 // --- 2. Binary Search Algorithm ---
2337 while (low <= high) {
2338 // Use this form to prevent potential integer overflow on very large arrays
2339 PetscInt mid = low + (high - low) / 2;
2340
2341 if (arr[mid] == key) {
2342 *found = PETSC_TRUE; // Key found!
2343 break; // Exit the loop
2344 }
2345
2346 if (arr[mid] < key) {
2347 low = mid + 1; // Search in the right half
2348 } else {
2349 high = mid - 1; // Search in the left half
2350 }
2351 }
2352
2354 PetscFunctionReturn(0);
2355}
Here is the caller graph for this function:

◆ Gidx()

static PetscInt Gidx ( PetscInt  i,
PetscInt  j,
PetscInt  k,
UserCtx user 
)
static

Definition at line 2358 of file setup.c.

2359{
2360 PetscInt nidx;
2361 DMDALocalInfo info = user->info;
2362
2363 PetscInt mx = info.mx, my = info.my;
2364
2365 AO ao;
2366 DMDAGetAO(user->da, &ao);
2367 nidx=i+j*mx+k*mx*my;
2368
2369 AOApplicationToPetsc(ao,1,&nidx);
2370
2371 return (nidx);
2372}
DMDALocalInfo info
Definition variables.h:668
Here is the caller graph for this function:

◆ ComputeDivergence()

PetscErrorCode ComputeDivergence ( UserCtx user)

Definition at line 2377 of file setup.c.

2378{
2379 DM da = user->da, fda = user->fda;
2380 DMDALocalInfo info = user->info;
2381
2382 PetscInt ti = user->simCtx->step;
2383
2384 PetscInt xs = info.xs, xe = info.xs + info.xm;
2385 PetscInt ys = info.ys, ye = info.ys + info.ym;
2386 PetscInt zs = info.zs, ze = info.zs + info.zm;
2387 PetscInt mx = info.mx, my = info.my, mz = info.mz;
2388
2389 PetscInt lxs, lys, lzs, lxe, lye, lze;
2390 PetscInt i, j, k;
2391
2392 Vec Div;
2393 PetscReal ***div, ***aj, ***nvert,***p;
2394 Cmpnts ***ucont;
2395 PetscReal maxdiv;
2396
2397 lxs = xs; lxe = xe;
2398 lys = ys; lye = ye;
2399 lzs = zs; lze = ze;
2400
2401 if (xs==0) lxs = xs+1;
2402 if (ys==0) lys = ys+1;
2403 if (zs==0) lzs = zs+1;
2404
2405 if (xe==mx) lxe = xe-1;
2406 if (ye==my) lye = ye-1;
2407 if (ze==mz) lze = ze-1;
2408
2409 PetscFunctionBeginUser;
2411
2412 DMDAVecGetArray(fda,user->lUcont, &ucont);
2413 DMDAVecGetArray(da, user->lAj, &aj);
2414 VecDuplicate(user->P, &Div);
2415 DMDAVecGetArray(da, Div, &div);
2416 DMDAVecGetArray(da, user->lNvert, &nvert);
2417 DMDAVecGetArray(da, user->P, &p);
2418 for (k=lzs; k<lze; k++) {
2419 for (j=lys; j<lye; j++){
2420 for (i=lxs; i<lxe; i++) {
2421 if (k==10 && j==10 && i==1){
2422 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]);
2423 }
2424
2425 if (k==10 && j==10 && i==mx-3)
2426 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]);
2427 }
2428 }
2429 }
2430 DMDAVecRestoreArray(da, user->P, &p);
2431
2432
2433 for (k=lzs; k<lze; k++) {
2434 for (j=lys; j<lye; j++) {
2435 for (i=lxs; i<lxe; i++) {
2436 maxdiv = fabs((ucont[k][j][i].x - ucont[k][j][i-1].x +
2437 ucont[k][j][i].y - ucont[k][j-1][i].y +
2438 ucont[k][j][i].z - ucont[k-1][j][i].z)*aj[k][j][i]);
2439 if (nvert[k][j][i] + nvert[k+1][j][i] + nvert[k-1][j][i] +
2440 nvert[k][j+1][i] + nvert[k][j-1][i] +
2441 nvert[k][j][i+1] + nvert[k][j][i-1] > 0.1) maxdiv = 0.;
2442 div[k][j][i] = maxdiv;
2443
2444 }
2445 }
2446 }
2447
2448 if (zs==0) {
2449 k=0;
2450 for (j=ys; j<ye; j++) {
2451 for (i=xs; i<xe; i++) {
2452 div[k][j][i] = 0.;
2453 }
2454 }
2455 }
2456
2457 if (ze == mz) {
2458 k=mz-1;
2459 for (j=ys; j<ye; j++) {
2460 for (i=xs; i<xe; i++) {
2461 div[k][j][i] = 0.;
2462 }
2463 }
2464 }
2465
2466 if (xs==0) {
2467 i=0;
2468 for (k=zs; k<ze; k++) {
2469 for (j=ys; j<ye; j++) {
2470 div[k][j][i] = 0.;
2471 }
2472 }
2473 }
2474
2475 if (xe==mx) {
2476 i=mx-1;
2477 for (k=zs; k<ze; k++) {
2478 for (j=ys; j<ye; j++) {
2479 div[k][j][i] = 0;
2480 }
2481 }
2482 }
2483
2484 if (ys==0) {
2485 j=0;
2486 for (k=zs; k<ze; k++) {
2487 for (i=xs; i<xe; i++) {
2488 div[k][j][i] = 0.;
2489 }
2490 }
2491 }
2492
2493 if (ye==my) {
2494 j=my-1;
2495 for (k=zs; k<ze; k++) {
2496 for (i=xs; i<xe; i++) {
2497 div[k][j][i] = 0.;
2498 }
2499 }
2500 }
2501 DMDAVecRestoreArray(da, Div, &div);
2502 PetscInt MaxFlatIndex;
2503
2504 VecMax(Div, &MaxFlatIndex, &maxdiv);
2505
2506 LOG_ALLOW(GLOBAL,LOG_INFO,"[Step %d]] The Maximum Divergence is %e at flat index %d.\n",ti,maxdiv,MaxFlatIndex);
2507
2508 user->simCtx->MaxDivFlatArg = MaxFlatIndex;
2509 user->simCtx->MaxDiv = maxdiv;
2510
2511 for (k=zs; k<ze; k++) {
2512 for (j=ys; j<ye; j++) {
2513 for (i=xs; i<xe; i++) {
2514 if (Gidx(i,j,k,user) == MaxFlatIndex) {
2515 LOG_ALLOW(GLOBAL,LOG_INFO,"[Step %d] The Maximum Divergence(%e) is at location [%d][%d][%d]. \n", ti, maxdiv,k,j,i);
2516 user->simCtx->MaxDivz = k;
2517 user->simCtx->MaxDivy = j;
2518 user->simCtx->MaxDivx = i;
2519 }
2520 }
2521 }
2522 }
2523
2524
2525 DMDAVecRestoreArray(da, user->lNvert, &nvert);
2526 DMDAVecRestoreArray(fda, user->lUcont, &ucont);
2527 DMDAVecRestoreArray(da, user->lAj, &aj);
2528 VecDestroy(&Div);
2529
2531 PetscFunctionReturn(0);
2532}
static PetscInt Gidx(PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
Definition setup.c:2358
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.

Definition at line 2549 of file setup.c.

2549 {
2550 PetscErrorCode ierr; // Error code for PETSc functions
2551 PetscMPIInt rank;
2552 PetscFunctionBeginUser;
2554 MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
2555
2556 // Initialize RNG for x-coordinate
2557 ierr = PetscRandomCreate(PETSC_COMM_SELF, randx); CHKERRQ(ierr);
2558 ierr = PetscRandomSetType((*randx), PETSCRAND48); CHKERRQ(ierr);
2559 ierr = PetscRandomSetInterval(*randx, user->bbox.min_coords.x, user->bbox.max_coords.x); CHKERRQ(ierr);
2560 ierr = PetscRandomSetSeed(*randx, rank + 12345); CHKERRQ(ierr); // Unique seed per rank
2561 ierr = PetscRandomSeed(*randx); CHKERRQ(ierr);
2562 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for X-axis.\n",rank);
2563
2564 // Initialize RNG for y-coordinate
2565 ierr = PetscRandomCreate(PETSC_COMM_SELF, randy); CHKERRQ(ierr);
2566 ierr = PetscRandomSetType((*randy), PETSCRAND48); CHKERRQ(ierr);
2567 ierr = PetscRandomSetInterval(*randy, user->bbox.min_coords.y, user->bbox.max_coords.y); CHKERRQ(ierr);
2568 ierr = PetscRandomSetSeed(*randy, rank + 67890); CHKERRQ(ierr); // Unique seed per rank
2569 ierr = PetscRandomSeed(*randy); CHKERRQ(ierr);
2570 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for Y-axis.\n",rank);
2571
2572 // Initialize RNG for z-coordinate
2573 ierr = PetscRandomCreate(PETSC_COMM_SELF, randz); CHKERRQ(ierr);
2574 ierr = PetscRandomSetType((*randz), PETSCRAND48); CHKERRQ(ierr);
2575 ierr = PetscRandomSetInterval(*randz, user->bbox.min_coords.z, user->bbox.max_coords.z); CHKERRQ(ierr);
2576 ierr = PetscRandomSetSeed(*randz, rank + 54321); CHKERRQ(ierr); // Unique seed per rank
2577 ierr = PetscRandomSeed(*randz); CHKERRQ(ierr);
2578 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "[Rank %d]Initialized RNG for Z-axis.\n",rank);
2579
2581 PetscFunctionReturn(0);
2582}
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:35
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:156
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:155
BoundingBox bbox
Definition variables.h:672
Here is the caller graph for this function:

◆ InitializeLogicalSpaceRNGs()

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

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

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

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

Definition at line 2600 of file setup.c.

2600 {
2601 PetscErrorCode ierr;
2602 PetscMPIInt rank;
2603 PetscFunctionBeginUser;
2604
2606
2607 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2608
2609 // --- RNG for i-logical dimension ---
2610 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_i); CHKERRQ(ierr);
2611 ierr = PetscRandomSetType((*rand_logic_i), PETSCRAND48); CHKERRQ(ierr);
2612 ierr = PetscRandomSetInterval(*rand_logic_i, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
2613 ierr = PetscRandomSetSeed(*rand_logic_i, rank + 202401); CHKERRQ(ierr); // Unique seed
2614 ierr = PetscRandomSeed(*rand_logic_i); CHKERRQ(ierr);
2615 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for i-logical dimension [0,1).\n",rank);
2616
2617 // --- RNG for j-logical dimension ---
2618 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_j); CHKERRQ(ierr);
2619 ierr = PetscRandomSetType((*rand_logic_j), PETSCRAND48); CHKERRQ(ierr);
2620 ierr = PetscRandomSetInterval(*rand_logic_j, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
2621 ierr = PetscRandomSetSeed(*rand_logic_j, rank + 202402); CHKERRQ(ierr);
2622 ierr = PetscRandomSeed(*rand_logic_j); CHKERRQ(ierr);
2623 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for j-logical dimension [0,1).\n",rank);
2624
2625 // --- RNG for k-logical dimension ---
2626 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_k); CHKERRQ(ierr);
2627 ierr = PetscRandomSetType((*rand_logic_k), PETSCRAND48); CHKERRQ(ierr);
2628 ierr = PetscRandomSetInterval(*rand_logic_k, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
2629 ierr = PetscRandomSetSeed(*rand_logic_k, rank + 202403); CHKERRQ(ierr);
2630 ierr = PetscRandomSeed(*rand_logic_k); CHKERRQ(ierr);
2631 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d] Initialized RNG for k-logical dimension [0,1).\n",rank);
2632
2633
2635 PetscFunctionReturn(0);
2636}
Here is the caller graph for this function:

◆ TransformDerivativesToPhysical()

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 
)
static

Transforms derivatives from computational space to physical space using the chain rule.

Definition at line 2643 of file setup.c.

2646{
2647 // Derivatives of the first component (u)
2648 dudx->x = jacobian * (deriv_csi.x * csi_metrics.x + deriv_eta.x * eta_metrics.x + deriv_zet.x * zet_metrics.x);
2649 dudx->y = jacobian * (deriv_csi.x * csi_metrics.y + deriv_eta.x * eta_metrics.y + deriv_zet.x * zet_metrics.y);
2650 dudx->z = jacobian * (deriv_csi.x * csi_metrics.z + deriv_eta.x * eta_metrics.z + deriv_zet.x * zet_metrics.z);
2651 // Derivatives of the second component (v)
2652 dvdx->x = jacobian * (deriv_csi.y * csi_metrics.x + deriv_eta.y * eta_metrics.x + deriv_zet.y * zet_metrics.x);
2653 dvdx->y = jacobian * (deriv_csi.y * csi_metrics.y + deriv_eta.y * eta_metrics.y + deriv_zet.y * zet_metrics.y);
2654 dvdx->z = jacobian * (deriv_csi.y * csi_metrics.z + deriv_eta.y * eta_metrics.z + deriv_zet.y * zet_metrics.z);
2655 // Derivatives of the third component (w)
2656 dwdx->x = jacobian * (deriv_csi.z * csi_metrics.x + deriv_eta.z * eta_metrics.x + deriv_zet.z * zet_metrics.x);
2657 dwdx->y = jacobian * (deriv_csi.z * csi_metrics.y + deriv_eta.z * eta_metrics.y + deriv_zet.z * zet_metrics.y);
2658 dwdx->z = jacobian * (deriv_csi.z * csi_metrics.z + deriv_eta.z * eta_metrics.z + deriv_zet.z * zet_metrics.z);
2659}
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
userThe user context for the current computational block.
i,j,kThe grid indices of the cell center where derivatives are required.
field_dataA 3D array pointer to the raw local data of the vector field (e.g., from lUcat).
dudxOutput: A Cmpnts struct storing [du/dx, du/dy, du/dz].
dvdxOutput: A Cmpnts struct storing [dv/dx, dv/dy, dv/dz].
dwdxOutput: A Cmpnts struct storing [dw/dx, dw/dy, dw/dz].
Returns
PetscErrorCode 0 on success.

Definition at line 2678 of file setup.c.

2680{
2681 PetscErrorCode ierr;
2682 Cmpnts ***csi, ***eta, ***zet;
2683 PetscReal ***jac;
2684 PetscFunctionBeginUser;
2685
2686 // 1. Get read-only access to the necessary metric data arrays
2687 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
2688 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
2689 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
2690 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
2691
2692 // 2. Calculate derivatives in computational space using central differencing
2693 Cmpnts deriv_csi, deriv_eta, deriv_zet;
2694 deriv_csi.x = (field_data[k][j][i+1].x - field_data[k][j][i-1].x) * 0.5;
2695 deriv_csi.y = (field_data[k][j][i+1].y - field_data[k][j][i-1].y) * 0.5;
2696 deriv_csi.z = (field_data[k][j][i+1].z - field_data[k][j][i-1].z) * 0.5;
2697
2698 deriv_eta.x = (field_data[k][j+1][i].x - field_data[k][j-1][i].x) * 0.5;
2699 deriv_eta.y = (field_data[k][j+1][i].y - field_data[k][j-1][i].y) * 0.5;
2700 deriv_eta.z = (field_data[k][j+1][i].z - field_data[k][j-1][i].z) * 0.5;
2701
2702 deriv_zet.x = (field_data[k+1][j][i].x - field_data[k-1][j][i].x) * 0.5;
2703 deriv_zet.y = (field_data[k+1][j][i].y - field_data[k-1][j][i].y) * 0.5;
2704 deriv_zet.z = (field_data[k+1][j][i].z - field_data[k-1][j][i].z) * 0.5;
2705
2706 // 3. Transform derivatives to physical space
2707 TransformDerivativesToPhysical(jac[k][j][i], csi[k][j][i], eta[k][j][i], zet[k][j][i],
2708 deriv_csi, deriv_eta, deriv_zet,
2709 dudx, dvdx, dwdx);
2710
2711 // 4. Restore access to the PETSc data arrays
2712 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi); CHKERRQ(ierr);
2713 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta); CHKERRQ(ierr);
2714 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet); CHKERRQ(ierr);
2715 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &jac); CHKERRQ(ierr);
2716
2717 PetscFunctionReturn(0);
2718}
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)
Transforms derivatives from computational space to physical space using the chain rule.
Definition setup.c:2643
Here is the call graph for this function:
Here is the caller graph for this function: