PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
ParticleSwarm.c
Go to the documentation of this file.
1 // ParticleSwarm.c
2
3#include "ParticleSwarm.h"
4
5#define INTERPOLATION_DISTANCE_TOLERANCE 1.0e-14
6
7#undef __FUNCT__
8#define __FUNCT__ "InitializeSwarm"
9/**
10 * @brief Implementation of \ref InitializeSwarm().
11 * @details Full API contract (arguments, ownership, side effects) is documented with
12 * the header declaration in `include/ParticleSwarm.h`.
13 * @see InitializeSwarm()
14 */
15PetscErrorCode InitializeSwarm(UserCtx* user) {
16 PetscErrorCode ierr; // Error code for PETSc functions
17
18 PetscFunctionBeginUser;
20 // Create the DMSwarm object for particle management
21 ierr = DMCreate(PETSC_COMM_WORLD, &user->swarm); CHKERRQ(ierr);
22 ierr = DMSetType(user->swarm, DMSWARM); CHKERRQ(ierr);
23 ierr = DMSetDimension(user->swarm, 3); CHKERRQ(ierr);
24 ierr = DMSwarmSetType(user->swarm, DMSWARM_BASIC); CHKERRQ(ierr);
25 LOG_ALLOW(LOCAL,LOG_INFO, "DMSwarm created and configured.\n");
26
28 PetscFunctionReturn(0);
29}
30
31#undef __FUNCT__
32#define __FUNCT__ "RegisterSwarmField"
33
34/**
35 * @brief Internal helper implementation: `RegisterSwarmField()`.
36 * @details Local to this translation unit.
37 */
38PetscErrorCode RegisterSwarmField(DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
39{
40 PetscErrorCode ierr;
41 PetscFunctionBeginUser;
42
43 ierr = DMSwarmRegisterPetscDatatypeField(swarm, fieldName, fieldDim, dtype); CHKERRQ(ierr);
44 // PetscDataTypes is an extern char* [] defined in petscsystypes.h that gives string names for PetscDataType enums
45 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field '%s' with dimension=%d, type=%s.\n",
46 fieldName, fieldDim, PetscDataTypes[dtype]);
47
48 PetscFunctionReturn(0);
49}
50
51#undef __FUNCT__
52#define __FUNCT__ "RegisterParticleFields"
53
54/**
55 * @brief Implementation of \ref RegisterParticleFields().
56 * @details Full API contract (arguments, ownership, side effects) is documented with
57 * the header declaration in `include/ParticleSwarm.h`.
58 * @see RegisterParticleFields()
59 */
60
61PetscErrorCode RegisterParticleFields(DM swarm)
62{
63 PetscErrorCode ierr;
64 PetscFunctionBeginUser;
65
66 // Register each field using the helper function
67 ierr = RegisterSwarmField(swarm, "position", 3 ,PETSC_REAL); CHKERRQ(ierr);
68 LOG_ALLOW(LOCAL,LOG_DEBUG, "Registered field 'position'.\n");
69
70 ierr = RegisterSwarmField(swarm, "velocity", 3, PETSC_REAL); CHKERRQ(ierr);
71 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'velocity'.\n");
72
73 ierr = RegisterSwarmField(swarm, "DMSwarm_CellID", 3, PETSC_INT); CHKERRQ(ierr);
74 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'DMSwarm_CellID'.\n");
75
76 ierr = RegisterSwarmField(swarm, "weight", 3,PETSC_REAL); CHKERRQ(ierr);
77 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'weight'.\n");
78
79 ierr = RegisterSwarmField(swarm,"Diffusivity", 1,PETSC_REAL); CHKERRQ(ierr);
80 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'Diffusivity' - Scalar.\n");
81
82 ierr = RegisterSwarmField(swarm,"DiffusivityGradient", 3,PETSC_REAL); CHKERRQ(ierr);
83 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'DiffusivityGradient' - Vector.\n");
84
85 ierr = RegisterSwarmField(swarm,"Psi", 1,PETSC_REAL); CHKERRQ(ierr);
86 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'Psi' - Scalar.\n");
87
88 ierr = RegisterSwarmField(swarm,"DMSwarm_location_status",1,PETSC_INT);CHKERRQ(ierr);
89 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'DMSwarm_location_status' - Status of Location of Particle(located,lost etc).\n");
90
91 // Finalize the field registration after all fields have been added
92 ierr = DMSwarmFinalizeFieldRegister(swarm); CHKERRQ(ierr);
93 LOG_ALLOW(LOCAL,LOG_INFO,"RegisterParticleFields - Finalized field registration.\n");
94
95 PetscFunctionReturn(0);
96}
97
98#undef __FUNCT__
99#define __FUNCT__ "DetermineVolumetricInitializationParameters"
100/**
101 * @brief Internal helper implementation: `DetermineVolumetricInitializationParameters()`.
102 * @details Local to this translation unit.
103 */
105 UserCtx *user, DMDALocalInfo *info,
106 PetscInt xs_gnode, PetscInt ys_gnode, PetscInt zs_gnode,
107 PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr, /* Pointers to RNGs */
108 PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out,
109 PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out,
110 PetscBool *can_place_in_volume_out)
111{
112 PetscErrorCode ierr = 0;
113 (void)user;
114 PetscReal r_val; // Temporary for random numbers from [0,1) RNGs
115 PetscInt local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k;
116 PetscMPIInt rank_for_logging; // For logging if needed
117
118 PetscFunctionBeginUser;
119
121
122 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_for_logging); CHKERRQ(ierr);
123
124 *can_place_in_volume_out = PETSC_FALSE; // Default to: cannot place
125
126 // Default intra-cell logicals and cell node indices (e.g. if placement fails)
127 *xi_metric_logic_out = 0.5; *eta_metric_logic_out = 0.5; *zta_metric_logic_out = 0.5;
128 *ci_metric_lnode_out = xs_gnode; *cj_metric_lnode_out = ys_gnode; *ck_metric_lnode_out = zs_gnode;
129
130 // Calculate number of owned cells in each direction from node counts in info
131 // Get number of cells this rank owns in each dimension (tangential to the face mainly)
132 PetscInt owned_start_cell_i, num_owned_cells_on_rank_i;
133 PetscInt owned_start_cell_j, num_owned_cells_on_rank_j;
134 PetscInt owned_start_cell_k, num_owned_cells_on_rank_k;
135
136 ierr = GetOwnedCellRange(info, 0, &owned_start_cell_i, &num_owned_cells_on_rank_i); CHKERRQ(ierr);
137 ierr = GetOwnedCellRange(info, 1, &owned_start_cell_j, &num_owned_cells_on_rank_j); CHKERRQ(ierr);
138 ierr = GetOwnedCellRange(info, 2, &owned_start_cell_k, &num_owned_cells_on_rank_k); CHKERRQ(ierr);
139
140 if (num_owned_cells_on_rank_i > 0 && num_owned_cells_on_rank_j > 0 && num_owned_cells_on_rank_k > 0) { // If rank owns any 3D cells
141 *can_place_in_volume_out = PETSC_TRUE;
142
143 // --- 1. Select a Random Owned Cell ---
144 // The selected index will be a 0-based index relative to the start of this rank's owned cells.
145
146 // Select random local owned cell index in I-direction
147 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
148 local_owned_cell_idx_i = (PetscInt)(r_val * num_owned_cells_on_rank_i);
149 // Clamp to be safe: local_owned_cell_idx_i should be in [0, num_owned_cells_on_rank_i - 1]
150 local_owned_cell_idx_i = PetscMin(PetscMax(0, local_owned_cell_idx_i), num_owned_cells_on_rank_i - 1);
151 *ci_metric_lnode_out = xs_gnode + local_owned_cell_idx_i; // Convert to local node index for cell origin
152
153 // Select random local owned cell index in J-direction
154 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
155 local_owned_cell_idx_j = (PetscInt)(r_val * num_owned_cells_on_rank_j);
156 local_owned_cell_idx_j = PetscMin(PetscMax(0, local_owned_cell_idx_j), num_owned_cells_on_rank_j - 1);
157 *cj_metric_lnode_out = ys_gnode + local_owned_cell_idx_j;
158
159 // Select random local owned cell index in K-direction
160 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
161 local_owned_cell_idx_k = (PetscInt)(r_val * num_owned_cells_on_rank_k);
162 local_owned_cell_idx_k = PetscMin(PetscMax(0, local_owned_cell_idx_k), num_owned_cells_on_rank_k - 1);
163 *ck_metric_lnode_out = zs_gnode + local_owned_cell_idx_k;
164
165 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Selected Cell (Owned Idx: %d,%d,%d -> LNodeStart: %d,%d,%d). OwnedCells(i,j,k): (%d,%d,%d). GhostNodeStarts(xs,ys,zs): (%d,%d,%d) \n",
166 rank_for_logging, local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k,
167 *ci_metric_lnode_out, *cj_metric_lnode_out, *ck_metric_lnode_out,
168 num_owned_cells_on_rank_i, num_owned_cells_on_rank_j, num_owned_cells_on_rank_k,
169 xs_gnode, ys_gnode, zs_gnode);
170
171
172 // --- 2. Generate Random Intra-Cell Logical Coordinates [0,1) for MetricLogicalToPhysical ---
173 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, xi_metric_logic_out); CHKERRQ(ierr); // Re-use RNGs
174 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, eta_metric_logic_out); CHKERRQ(ierr);
175 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, zta_metric_logic_out); CHKERRQ(ierr);
176
177 // Ensure logical coordinates are strictly within [0,1) for robustness with MetricLogicalToPhysical
178 *xi_metric_logic_out = PetscMin(*xi_metric_logic_out, 1.0 - 1.0e-7);
179 *eta_metric_logic_out = PetscMin(*eta_metric_logic_out, 1.0 - 1.0e-7);
180 *zta_metric_logic_out = PetscMin(*zta_metric_logic_out, 1.0 - 1.0e-7);
181 // Ensure they are not negative either (though [0,1) RNGs shouldn't produce this)
182 *xi_metric_logic_out = PetscMax(*xi_metric_logic_out, 0.0);
183 *eta_metric_logic_out = PetscMax(*eta_metric_logic_out, 0.0);
184 *zta_metric_logic_out = PetscMax(*zta_metric_logic_out, 0.0);
185
186 } else {
187 // This rank does not own any 3D cells (e.g., in a 1D or 2D decomposition,
188 // or if the global domain itself is not 3D in terms of cells).
189 // *can_place_in_volume_out remains PETSC_FALSE.
190 LOG_ALLOW(LOCAL, LOG_WARNING, "Rank %d: Cannot place particle volumetrically. Rank has zero owned cells in at least one dimension (owned cells i,j,k: %d,%d,%d).\n",
191 rank_for_logging, num_owned_cells_on_rank_i, num_owned_cells_on_rank_j, num_owned_cells_on_rank_k);
192 }
193
195 PetscFunctionReturn(0);
196}
197
198#undef __FUNCT__
199#define __FUNCT__ "InitializeParticleBasicProperties"
200
201/**
202 * @brief Internal helper implementation: `InitializeParticleBasicProperties()`.
203 * @details Local to this translation unit.
204 */
205static PetscErrorCode InitializeParticleBasicProperties(UserCtx *user,
206 PetscInt particlesPerProcess,
207 PetscRandom *rand_logic_i,
208 PetscRandom *rand_logic_j,
209 PetscRandom *rand_logic_k,
210 BoundingBox *bboxlist) // bboxlist unused for placement
211{
212 PetscErrorCode ierr;
213 (void)bboxlist;
214 DM swarm = user->swarm;
215 PetscReal *positions_field = NULL; // Pointer to swarm field for physical positions (x,y,z)
216 PetscInt64 *particleIDs = NULL; // Pointer to swarm field for Particle IDs
217 PetscInt *cellIDs_petsc = NULL; // Pointer to swarm field for DMSwarm_CellID (i,j,k of containing cell)
218 PetscInt *status_field = NULL; // Pointer to swarm field for DMSwarm_location_status(NEEDS_LOCATION etc)
219 PetscMPIInt rank,size; // MPI rank of the current process, and total number of ranks.
220 const Cmpnts ***coor_nodes_local_array; // Read-only access to local node coordinates (from user->da)
221 Vec Coor_local; // Local vector for node coordinates
222 DMDALocalInfo info; // Local grid information (node-based) from user->da
223 PetscInt xs_gnode_rank, ys_gnode_rank, zs_gnode_rank; // Local starting node indices (incl. ghosts) of rank's DA patch
224 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global; // Global node counts in each direction
225
226 // Variables for surface initialization (Mode 0)
227 PetscBool can_this_rank_service_inlet = PETSC_FALSE;
228
229 PetscFunctionBeginUser;
230
232
233 SimCtx *simCtx = user->simCtx;
234
235 // --- 1. Input Validation and Basic Setup ---
236 if (!user || !rand_logic_i || !rand_logic_j || !rand_logic_k) {
237 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null user or RNG pointer.");
238 }
239 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
240 ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size); CHKERRQ(ierr);
241
242 // Get DMDA information for the node-centered coordinate grid (user->da)
243 ierr = DMGetCoordinatesLocal(user->da, &Coor_local); CHKERRQ(ierr);
244 if (!Coor_local) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "DMGetCoordinatesLocal for user->da returned NULL Coor_local.");
245 ierr = DMDAVecGetArrayRead(user->fda, Coor_local, (void*)&coor_nodes_local_array); CHKERRQ(ierr);
246 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
247 ierr = DMDAGetCorners(user->da, &xs_gnode_rank, &ys_gnode_rank, &zs_gnode_rank, NULL, NULL, NULL); CHKERRQ(ierr);
248 ierr = DMDAGetInfo(user->da, NULL, &IM_nodes_global, &JM_nodes_global, &KM_nodes_global, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); CHKERRQ(ierr);
249
250 // Modification to IM_nodes_global etc. to account for 1-cell halo in each direction.
251 IM_nodes_global -= 1; JM_nodes_global -= 1; KM_nodes_global -= 1;
252
253 const PetscInt IM_cells_global = IM_nodes_global > 0 ? IM_nodes_global - 1 : 0;
254 const PetscInt JM_cells_global = JM_nodes_global > 0 ? JM_nodes_global - 1 : 0;
255 const PetscInt KM_cells_global = KM_nodes_global > 0 ? KM_nodes_global - 1 : 0;
256
257 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Initializing %d particles. Mode: %s.\n",
258 rank, particlesPerProcess, ParticleInitializationToString(simCtx->ParticleInitialization));
259
260 // --- 2. Pre-computation for Surface Initialization (PARTICLE_INIT_SURFACE_RANDOM and PARTICLE_INIT_SURFACE_EDGES) ---
262 simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_EDGES) { // Surface initialization
263 ierr = CanRankServiceInletFace(user, &info, IM_nodes_global, JM_nodes_global, KM_nodes_global, &can_this_rank_service_inlet); CHKERRQ(ierr);
264 if (can_this_rank_service_inlet) {
265 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Will attempt to place particles on inlet face %s.\n", rank, BCFaceToString((BCFace)user->identifiedInletBCFace));
266 } else {
267 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Cannot service inlet face %s. Particles will be at Inlet Center (%.6f,%.6f,%.6f) and rely on migration.\n", rank, BCFaceToString((BCFace)user->identifiedInletBCFace),user->simCtx->CMx_c,user->simCtx->CMy_c,user->simCtx->CMz_c);
268 }
269 }
270
271 // --- 3. Get Access to Swarm Fields ---
272 ierr = DMSwarmGetField(swarm, "position", NULL, NULL, (void**)&positions_field); CHKERRQ(ierr);
273 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
274 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs_petsc); CHKERRQ(ierr);
275 ierr = DMSwarmGetField(swarm, "DMSwarm_location_status",NULL,NULL,(void**)&status_field); CHKERRQ(ierr);
276
277 // --- 4. Determine Starting Global PID for this Rank ---
278 PetscInt particles_per_rank_ideal = simCtx->np / size; // Assumes user->size is PETSC_COMM_WORLD size
279 PetscInt remainder_particles = simCtx->np % size;
280 PetscInt base_pid_for_rank = rank * particles_per_rank_ideal + PetscMin(rank, remainder_particles);
281 // This calculation must match how particlesPerProcess was determined (e.g., in DistributeParticles).
282
283 // --- 5. Loop Over Particles to Initialize ---
284 for (PetscInt p = 0; p < particlesPerProcess; p++) {
285 PetscInt idx = p;
286 PetscInt ci_metric_lnode, cj_metric_lnode, ck_metric_lnode;
287 PetscReal xi_metric_logic, eta_metric_logic, zta_metric_logic;
288 Cmpnts phys_coords = {0.0, 0.0, 0.0};
289 PetscBool particle_placed_by_this_rank = PETSC_FALSE;
290
291 if (simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_RANDOM) { // --- 5.a. Surface Random Initialization ---
292 if (can_this_rank_service_inlet) {
293 ierr = GetRandomCellAndLogicalCoordsOnInletFace(user, &info, xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
294 IM_nodes_global, JM_nodes_global, KM_nodes_global,
295 rand_logic_i, rand_logic_j, rand_logic_k,
296 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
297 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic); CHKERRQ(ierr);
298 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
299 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
300 xi_metric_logic, eta_metric_logic, zta_metric_logic,
301 &phys_coords); CHKERRQ(ierr);
302 particle_placed_by_this_rank = PETSC_TRUE;
303 }else{
304 // Rank cannot service inlet - place at inlet center to be migrated later
305 phys_coords.x = user->simCtx->CMx_c;
306 phys_coords.y = user->simCtx->CMy_c;
307 phys_coords.z = user->simCtx->CMz_c;
308 particle_placed_by_this_rank = PETSC_FALSE; // Relies on migration
309 }
310 }else if(simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_EDGES) { // --- 5.a1. Surface Edges Initialization (deterministic) ---
311 if(can_this_rank_service_inlet) {
312 PetscInt64 particle_global_id = (PetscInt64)(base_pid_for_rank + p);
313 ierr = GetDeterministicFaceGridLocation(user,&info,xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
314 IM_cells_global, JM_cells_global, KM_cells_global,
315 particle_global_id,
316 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
317 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
318 &particle_placed_by_this_rank); CHKERRQ(ierr);
319 if(particle_placed_by_this_rank){
320 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
321 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
322 xi_metric_logic, eta_metric_logic, zta_metric_logic,
323 &phys_coords); CHKERRQ(ierr);
324 }else{
325 // Even if rank can service face, it may not own the portion of the face that a particle is placed in.
326 phys_coords.x = user->simCtx->CMx_c;
327 phys_coords.y = user->simCtx->CMy_c;
328 phys_coords.z = user->simCtx->CMz_c;
329 }
330 }else{
331 // Rank cannot service inlet - place at inlet center to be migrated later
332 phys_coords.x = user->simCtx->CMx_c;
333 phys_coords.y = user->simCtx->CMy_c;
334 phys_coords.z = user->simCtx->CMz_c;
335 particle_placed_by_this_rank = PETSC_FALSE; // Relies on migration
336 }
337 }else if(simCtx->ParticleInitialization == PARTICLE_INIT_VOLUME){ // --- 5.b. Volumetric Initialization ---
338 PetscBool can_place_volumetrically = PETSC_FALSE;
339 ierr = DetermineVolumetricInitializationParameters(user, &info, xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
340 rand_logic_i, rand_logic_j, rand_logic_k,
341 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
342 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
343 &can_place_volumetrically); CHKERRQ(ierr);
344 if(can_place_volumetrically){
345 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
346 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
347 xi_metric_logic, eta_metric_logic, zta_metric_logic,
348 &phys_coords); CHKERRQ(ierr);
349 particle_placed_by_this_rank = PETSC_TRUE;
350 } else {
352 "Rank %d: PID %lld (idx %ld) (Volumetric Mode) - DetermineVolumetric... returned false. Default Phys: (%.2f,%.2f,%.2f).\n",
353 rank, (long long)(base_pid_for_rank + p), (long)p, phys_coords.x, phys_coords.y, phys_coords.z);
354 }
355 }else if(simCtx->ParticleInitialization == PARTICLE_INIT_POINT_SOURCE){ // --- 5.c. Point Source Initialization ---
356 // All particles placed at the user-specified fixed point (psrc_x, psrc_y, psrc_z).
357 // No random number generation or logical-to-physical conversion needed.
358 phys_coords.x = simCtx->psrc_x;
359 phys_coords.y = simCtx->psrc_y;
360 phys_coords.z = simCtx->psrc_z;
361 particle_placed_by_this_rank = PETSC_TRUE;
362 }else {
363 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown ParticleInitialization mode %d.", simCtx->ParticleInitialization);
364 }
365
366 // --- 5.c. Store Particle Properties ---
367 positions_field[3*p+0] = phys_coords.x;
368 positions_field[3*p+1] = phys_coords.y;
369 positions_field[3*p+2] = phys_coords.z;
370
371 particleIDs[p] = (PetscInt64)base_pid_for_rank + p;
372 cellIDs_petsc[3*p+0] = -1; cellIDs_petsc[3*p+1] = -1; cellIDs_petsc[3*p+2] = -1;
373 status_field[p] = UNINITIALIZED;
374
375 // --- 5.d. Logging for this particle ---
376 if (particle_placed_by_this_rank) {
377 LOG_LOOP_ALLOW(LOCAL, LOG_VERBOSE, idx, user->simCtx->LoggingFrequency,//(particlesPerProcess > 20 ? particlesPerProcess/10 : 1),
378 "Rank %d: PID %lld (idx %ld) PLACED. Mode %s. Embedded Cell:(%d,%d,%d). Logical Coords: (%.2e,%.2f,%.2f).\n Final Coords: (%.6f,%.6f,%.6f).\n",
379 rank, (long long)particleIDs[p], (long)p, ParticleInitializationToString(simCtx->ParticleInitialization),
380 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
381 xi_metric_logic, eta_metric_logic, zta_metric_logic,
382 phys_coords.x, phys_coords.y, phys_coords.z);
383
384 } else {
385 LOG_LOOP_ALLOW(LOCAL, LOG_WARNING, idx, user->simCtx->LoggingFrequency, //(particlesPerProcess > 20 ? particlesPerProcess/10 : 1),
386 "Rank %d: PID %lld (idx %ld) Mode %s NOT placed by this rank's logic. Default Coor: (%.2f,%.2f,%.2f). Relies on migration.\n",
387 rank, (long long)particleIDs[p], (long)p, ParticleInitializationToString(simCtx->ParticleInitialization),
388 phys_coords.x, phys_coords.y, phys_coords.z);
389 }
390 }
391
392 // --- 6. Restore Pointers and Cleanup ---
393 ierr = DMSwarmRestoreField(swarm, "position", NULL, NULL, (void**)&positions_field); CHKERRQ(ierr);
394 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
395 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs_petsc); CHKERRQ(ierr);
396 ierr = DMSwarmRestoreField(swarm, "DMSwarm_location_status", NULL, NULL, (void**)&status_field); CHKERRQ(ierr);
397 ierr = DMDAVecRestoreArrayRead(user->fda, Coor_local, (void*)&coor_nodes_local_array); CHKERRQ(ierr);
398
399 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Completed processing for %d particles.\n",
400 rank, particlesPerProcess);
401
403
404 PetscFunctionReturn(0);
405}
406
407#undef __FUNCT__
408#define __FUNCT__ "InitializeSwarmFieldValue"
409/**
410 * @brief Internal helper implementation: `InitializeSwarmFieldValue()`.
411 * @details Local to this translation unit.
412 */
413static PetscErrorCode InitializeSwarmFieldValue(const char *fieldName, PetscInt p, PetscInt fieldDim, PetscReal *fieldData)
414{
415 PetscFunctionBeginUser;
416
418
419 if (strcmp(fieldName, "velocity") == 0) {
420 // For velocity, initialize all components to zero
421 for (PetscInt d = 0; d < fieldDim; d++) {
422 fieldData[fieldDim * p + d] = 0.0;
423 }
424 } else if (strcmp(fieldName, "Diffusivity") == 0) {
425 // For Diffusivity,initialize to a default value (e.g., 1.0)
426 for (PetscInt d = 0; d < fieldDim; d++) {
427 fieldData[fieldDim * p + d] = 1.0;
428 }
429 } else if (strcmp(fieldName, "DiffusivityGradient") == 0) {
430 // For DiffusivityGradient,initialize to a default value (e.g., 1.0)
431 for (PetscInt d = 0; d < fieldDim; d++) {
432 fieldData[fieldDim * p + d] = 1.0;
433 }
434 } else if (strcmp(fieldName, "Psi") == 0) {
435 for (PetscInt d = 0; d < fieldDim; d++) {
436 fieldData[fieldDim * p + d] = 0.0;
437 }
438 } else {
439 // Default: initialize all components to zero
440 for (PetscInt d = 0; d < fieldDim; d++) {
441 fieldData[fieldDim * p + d] = 0.0;
442 }
443 }
444
446 PetscFunctionReturn(0);
447}
448
449
450#undef __FUNCT__
451#define __FUNCT__ "AssignInitialFieldToSwarm"
452/**
453 * @brief Internal helper implementation: `AssignInitialFieldToSwarm()`.
454 * @details Local to this translation unit.
455 */
456static PetscErrorCode AssignInitialFieldToSwarm(UserCtx *user, const char *fieldName, PetscInt fieldDim)
457{
458 PetscErrorCode ierr;
459 DM swarm = user->swarm;
460 PetscReal *fieldData = NULL;
461 PetscInt nLocal;
462
463 PetscFunctionBeginUser;
464
466
467 // Get the number of local particles
468 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
469 LOG_ALLOW(LOCAL,LOG_INFO, "%d local particles found.\n", nLocal);
470
471 // Retrieve the swarm field pointer for the specified fieldName
472 ierr = DMSwarmGetField(swarm, fieldName, NULL, NULL, (void**)&fieldData); CHKERRQ(ierr);
473 LOG_ALLOW(LOCAL,LOG_DEBUG, "Retrieved field '%s'.\n", fieldName);
474
475 // Loop over all particles and update the field using the helper function
476 for (PetscInt p = 0; p < nLocal; p++) {
477 ierr = InitializeSwarmFieldValue(fieldName, p, fieldDim, fieldData); CHKERRQ(ierr);
478 PetscReal disp_data[fieldDim];
479
480 for (PetscInt d = 0; d < fieldDim; d++) {
481 disp_data[d] = fieldData[fieldDim* p + d];
482 }
483 LOG_LOOP_ALLOW(LOCAL,LOG_VERBOSE,p, 100," Particle %d: %s[%d] = [%.6f, ...,%.6f].\n", p,fieldName,fieldDim,disp_data[0],disp_data[fieldDim-1]);
484 }
485
486 // Restore the swarm field pointer
487 ierr = DMSwarmRestoreField(swarm, fieldName, NULL, NULL, (void**)&fieldData); CHKERRQ(ierr);
488 LOG_ALLOW(LOCAL,LOG_INFO, "Initialization of field '%s' complete.\n", fieldName);
489
490
492
493 PetscFunctionReturn(0);
494}
495
496#undef __FUNCT__
497#define __FUNCT__ "AssignInitialPropertiesToSwarm"
498
499/**
500 * @brief Internal helper implementation: `AssignInitialPropertiesToSwarm()`.
501 * @details Local to this translation unit.
502 */
504 PetscInt particlesPerProcess,
505 PetscRandom *rand_phys_x, // RNG from original InitializeRandomGenerators
506 PetscRandom *rand_phys_y, // RNG from original InitializeRandomGenerators
507 PetscRandom *rand_phys_z, // RNG from original InitializeRandomGenerators
508 PetscRandom *rand_logic_i, // RNG from InitializeLogicalSpaceRNGs
509 PetscRandom *rand_logic_j, // RNG from InitializeLogicalSpaceRNGs
510 PetscRandom *rand_logic_k, // RNG from InitializeLogicalSpaceRNGs
511 BoundingBox *bboxlist)
512{
513 PetscErrorCode ierr;
514 PetscFunctionBeginUser;
515
517
518 SimCtx *simCtx = user->simCtx;
519
520 // --- 0. Input Validation ---
521 if (!user || !bboxlist || !rand_logic_i || !rand_logic_j || !rand_logic_k || !rand_phys_x || !rand_phys_y || !rand_phys_z) {
522 // Check all RNGs now as they are passed in
523 LOG_ALLOW(GLOBAL, LOG_ERROR, "Null user, bboxlist, or RNG pointer.\n");
524 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null input detected.");
525 }
526
527 LOG_ALLOW(GLOBAL, LOG_INFO, "Initializing swarm with %d particles per process. Mode: %s.\n",
528 particlesPerProcess, ParticleInitializationToString(simCtx->ParticleInitialization));
529
530 // --- 1. Parse BCS File for Inlet Information (if surface initialization) ---
532 simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_EDGES) { // Surface initialization
533 if(user->inletFaceDefined == PETSC_FALSE){
534 LOG_ALLOW(GLOBAL, LOG_ERROR, "Particle Initialization on inlet surface selected, but no INLET face was identified from bcs.dat. Cannot proceed.\n");
535 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "ParticleInitialization Mode 0 requires an INLET face to be defined in bcs.dat.");
536 }else{
537 LOG_ALLOW(GLOBAL, LOG_INFO, "After Parsing BCS file for Inlet, Inlet face = %s\n", BCFaceToString((BCFace)user->identifiedInletBCFace));
538 }
539 }
540
541 // --- 2. Initialize Basic Particle Properties (Position, PID, Cell IDs placeholder) ---
542 // The rand_logic_i/j/k are now passed directly.
543 // The rand_phys_x/y/z are passed but InitializeParticleBasicProperties (refactored version)
544 // will not use them for setting positions if all its paths use logical-to-physical mapping.
545 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Calling InitializeParticleBasicProperties.\n");
546 ierr = InitializeParticleBasicProperties(user, particlesPerProcess,
547 rand_logic_i, rand_logic_j, rand_logic_k,
548 bboxlist); // bboxlist passed along
549 CHKERRQ(ierr);
550 LOG_ALLOW(GLOBAL, LOG_INFO, "Successfully initialized basic particle properties.\n");
551
552 // Note: The logical RNGs (rand_logic_i/j/k) are NOT destroyed here.
553 // They were created externally (e.g., by InitializeLogicalSpaceRNGs) and
554 // should be destroyed externally (e.g., in FinalizeSwarmSetup).
555 // Same for rand_phys_x/y/z.
556
557 // --- 3. Initialize Other Swarm Fields (Velocity, Weight, Pressure, etc.) ---
558 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'velocity' field.\n");
559 ierr = AssignInitialFieldToSwarm(user, "velocity", 3); CHKERRQ(ierr);
560 LOG_ALLOW(LOCAL, LOG_INFO, "'velocity' field initialization complete.\n");
561
562 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'weight' field.\n");
563 ierr = AssignInitialFieldToSwarm(user, "weight", 3); CHKERRQ(ierr); // Assuming weight is vec3
564 LOG_ALLOW(LOCAL, LOG_INFO, "'weight' field initialization complete.\n");
565
566 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'Diffusivity' field.\n");
567 ierr = AssignInitialFieldToSwarm(user, "Diffusivity", 1); CHKERRQ(ierr);
568 LOG_ALLOW(GLOBAL, LOG_INFO, "'Diffusivity' field initialization complete.\n");
569
570 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'DiffusivityGradient' field.\n");
571 ierr = AssignInitialFieldToSwarm(user, "DiffusivityGradient", 3); CHKERRQ(ierr);
572 LOG_ALLOW(GLOBAL, LOG_INFO, "'DiffusivityGradient' field initialization complete.\n");
573
574 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'Psi' (Scalar) field.\n");
575 ierr = AssignInitialFieldToSwarm(user, "Psi", 1); CHKERRQ(ierr);
576 LOG_ALLOW(GLOBAL, LOG_INFO, "'P' field initialization complete.\n");
577
578 LOG_ALLOW(GLOBAL, LOG_INFO, "Successfully completed all swarm property initialization.\n");
579
580
582
583 PetscFunctionReturn(0);
584}
585
586
587#undef __FUNCT__
588#define __FUNCT__ "DistributeParticles"
589/**
590 * @brief Implementation of \ref DistributeParticles().
591 * @details Full API contract (arguments, ownership, side effects) is documented with
592 * the header declaration in `include/ParticleSwarm.h`.
593 * @see DistributeParticles()
594 */
595PetscErrorCode DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt* particlesPerProcess, PetscInt* remainder) {
596
597 PetscFunctionBeginUser;
598
600 // Calculate the base number of particles per process
601 *particlesPerProcess = numParticles / size;
602 *remainder = numParticles % size;
603
604 // Distribute the remainder particles to the first 'remainder' ranks
605 if (rank < *remainder) {
606 *particlesPerProcess += 1;
607 LOG_ALLOW_SYNC(GLOBAL,LOG_INFO,"Rank %d receives an extra particle. Total: %d\n", rank, *particlesPerProcess);
608 } else {
609 LOG_ALLOW_SYNC(GLOBAL,LOG_INFO, "Rank %d receives %d particles.\n", rank, *particlesPerProcess);
610 }
611
613 PetscFunctionReturn(0);
614}
615
616
617#undef __FUNCT__
618#define __FUNCT__ "FinalizeSwarmSetup"
619/**
620 * @brief Implementation of \ref FinalizeSwarmSetup().
621 * @details Full API contract (arguments, ownership, side effects) is documented with
622 * the header declaration in `include/ParticleSwarm.h`.
623 * @see FinalizeSwarmSetup()
624 */
625PetscErrorCode FinalizeSwarmSetup(PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k) {
626 PetscErrorCode ierr; // Error code for PETSc functions
627 PetscFunctionBeginUser;
629 // Destroy random number generators to free resources
630 // Physical space
631 ierr = PetscRandomDestroy(randx); CHKERRQ(ierr);
632 ierr = PetscRandomDestroy(randy); CHKERRQ(ierr);
633 ierr = PetscRandomDestroy(randz); CHKERRQ(ierr);
634 // Logical space
635 ierr = PetscRandomDestroy(rand_logic_i); CHKERRQ(ierr);
636 ierr = PetscRandomDestroy(rand_logic_j); CHKERRQ(ierr);
637 ierr = PetscRandomDestroy(rand_logic_k); CHKERRQ(ierr);
638
639 LOG_ALLOW(LOCAL,LOG_DEBUG,"Destroyed all random number generators.\n");
640
642 PetscFunctionReturn(0);
643}
644
645#undef __FUNCT__
646#define __FUNCT__ "CreateParticleSwarm"
647/**
648 * @brief Internal helper implementation: `CreateParticleSwarm()`.
649 * @details Local to this translation unit.
650 */
651PetscErrorCode CreateParticleSwarm(UserCtx *user, PetscInt numParticles, PetscInt *particlesPerProcess, BoundingBox *bboxlist) {
652 PetscErrorCode ierr; // PETSc error handling variable
653 (void)bboxlist;
654 PetscMPIInt rank, size; // Variables to store MPI rank and size
655 PetscInt remainder = 0; // Remainder of particles after division
656
657 PetscFunctionBeginUser;
659 // Validate input parameters
660 if (numParticles <= 0) {
661 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Number of particles must be positive. Given: %d\n", numParticles);
662 return PETSC_ERR_ARG_OUTOFRANGE;
663 }
664
665 // Retrieve MPI rank and size
666 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
667 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
668 LOG_ALLOW(GLOBAL,LOG_INFO," Domain dimensions: [%.2f,%.2f],[%.2f,%.2f],[%.2f,%.2f] \n",
669 user->Min_X,user->Max_X,user->Min_Y,user->Max_Y, user->Min_Z,user->Max_Z);
670 LOG_ALLOW_SYNC(GLOBAL,LOG_DEBUG, "[Rank %d] Local Bounding Box: [%.2f,%.2f],[%.2f,%.2f],[%.2f,%.2f] \n",
671 rank,user->bbox.min_coords.x,user->bbox.max_coords.x,
672 user->bbox.min_coords.y,user->bbox.max_coords.y,
673 user->bbox.min_coords.z,user->bbox.max_coords.z);
674 // Distribute particles among MPI processes
675 ierr = DistributeParticles(numParticles, rank, size, particlesPerProcess, &remainder); CHKERRQ(ierr);
676
677 // Initialize the DMSwarm - creates the swarm, sets the type and dimension
678 ierr = InitializeSwarm(user); CHKERRQ(ierr);
679
680 if (user->da) {
681 ierr = DMSwarmSetCellDM(user->swarm, user->da); CHKERRQ(ierr);
682 LOG_ALLOW(LOCAL,LOG_INFO,"Associated DMSwarm with Cell DM (user->da).\n");
683 } else {
684 // If user->da is essential for your simulation logic with particles, this should be a fatal error.
685 LOG_ALLOW(GLOBAL, LOG_WARNING, "user->da (Cell DM for Swarm) is NULL. Cell-based swarm operations might fail.\n");
686 // SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "user->da (Cell DM) is NULL but required.");
687 }
688
689 // Register particle fields (position, velocity, CellID, weight, etc.)
690 ierr = RegisterParticleFields(user->swarm); CHKERRQ(ierr);
691
692 // Set the local number of particles for this rank and additional buffer for particle migration
693 ierr = DMSwarmSetLocalSizes(user->swarm, *particlesPerProcess, numParticles); CHKERRQ(ierr);
694 LOG_ALLOW(GLOBAL,LOG_INFO, "Set local swarm size: %d particles.\n", *particlesPerProcess);
695
696 // Optionally, LOG_ALLOW detailed DM info in debug mode
697 if (get_log_level() == LOG_DEBUG && is_function_allowed(__func__)) {
698 LOG_ALLOW(GLOBAL,LOG_DEBUG,"Viewing DMSwarm:\n");
699 ierr = DMView(user->swarm, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
700 }
701
702 LOG_ALLOW(GLOBAL,LOG_INFO, "Particle swarm creation and initialization complete.\n");
703
705 PetscFunctionReturn(0);
706}
707
708// NOTE: The following two functions are helpers for unpacking and updating particle data
709// between DMSwarm fields and the Particle struct used in simulation logic.
710// While Swarm fields store data in arrays, the Particle struct provides a convenient
711// way to manipulate individual particle properties during simulation steps.
712
713#undef __FUNCT__
714#define __FUNCT__ "UnpackSwarmFields"
715
716/**
717 * @brief Implementation of \ref UnpackSwarmFields().
718 * @details Full API contract (arguments, ownership, side effects) is documented with
719 * the header declaration in `include/ParticleSwarm.h`.
720 * @see UnpackSwarmFields()
721 */
722PetscErrorCode UnpackSwarmFields(PetscInt i, const PetscInt64 *PIDs, const PetscReal *weights,
723 const PetscReal *positions, const PetscInt *cellIndices,
724 PetscReal *velocities,PetscInt *LocStatus,PetscReal *diffusivity, Cmpnts *diffusivitygradient, PetscReal *psi, Particle *particle) {
725 PetscFunctionBeginUser;
726
728
729 PetscMPIInt rank;
730 PetscErrorCode ierr;
731
732 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
733
734 if (particle == NULL) {
735 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Output Particle pointer is NULL. \n");
736 }
737
738 // logging the start of particle initialization
739 LOG_ALLOW(LOCAL,LOG_DEBUG, "[Rank %d]Unpacking Particle [%d] with PID: %ld.\n",rank, i, PIDs[i]);
740
741 // Initialize PID
742 if(PIDs == NULL){
743 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input PIDs pointer is NULL.\n");
744 }
745 particle->PID = PIDs[i];
746 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] PID set to: %ld.\n", rank,i, particle->PID);
747
748 // Initialize weights
749 if(weights == NULL){
750 particle->weights.x = 1.0;
751 particle->weights.y = 1.0;
752 particle->weights.z = 1.0;
753 LOG_ALLOW(LOCAL,LOG_WARNING, "[Rank %d]Particle [%d] weights pointer is NULL. Defaulting weights to (1.0, 1.0, 1.0).\n", rank,i);
754 }else{
755 particle->weights.x = weights[3 * i];
756 particle->weights.y = weights[3 * i + 1];
757 particle->weights.z = weights[3 * i + 2];
758 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] weights set to: (%.6f, %.6f, %.6f).\n",
759 rank,i, particle->weights.x, particle->weights.y, particle->weights.z);
760 }
761 // Initialize locations
762 if(positions == NULL){
763 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input positions pointer is NULL.\n");
764 }
765 particle->loc.x = positions[3 * i];
766 particle->loc.y = positions[3 * i + 1];
767 particle->loc.z = positions[3 * i + 2];
768 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] location set to: (%.6f, %.6f, %.6f).\n",
769 rank,i, particle->loc.x, particle->loc.y, particle->loc.z);
770
771 // Initialize velocities (assuming default zero; modify if necessary)
772 if(velocities == NULL){
773 particle->vel.x = 0.0;
774 particle->vel.y = 0.0;
775 particle->vel.z = 0.0;
776 LOG_ALLOW(LOCAL,LOG_WARNING, "[Rank %d]Particle [%d] velocities pointer is NULL. Defaulting velocities to (0.0, 0.0, 0.0).\n", rank,i);
777 }else{
778 particle->vel.x = velocities[3 * i];
779 particle->vel.y = velocities[3 * i + 1];
780 particle->vel.z = velocities[3 * i + 2];
781 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] velocities unpacked to: [%.6f,%.6f,%.6f].\n",rank, i,particle->vel.x,particle->vel.y,particle->vel.z);
782 }
783
784 // Initialize diffusivity
785 if(diffusivity == NULL){
786 particle->diffusivity = 1.0; // Default diffusivity
787 }else{
788 particle->diffusivity = diffusivity[i];
789 }
790 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] diffusivity set to: %.6f.\n",rank,i, particle->diffusivity);
791
792 // Initialize diffusivity gradient
793 if(diffusivitygradient == NULL){
794 particle->diffusivitygradient.x = 0.0;
795 particle->diffusivitygradient.y = 0.0;
796 particle->diffusivitygradient.z = 0.0;
797 LOG_ALLOW(LOCAL,LOG_WARNING, "[Rank %d]Particle [%d] diffusivity gradient pointer is NULL. Defaulting to (0.0, 0.0, 0.0).\n", rank,i);
798 }else{
799 particle->diffusivitygradient.x = diffusivitygradient[i].x;
800 particle->diffusivitygradient.y = diffusivitygradient[i].y;
801 particle->diffusivitygradient.z = diffusivitygradient[i].z;
802 }
803 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] diffusivity gradient set to: (%.6f, %.6f, %.6f).\n", rank,i,particle->diffusivitygradient.x,particle->diffusivitygradient.y,particle->diffusivitygradient.z);
804
805 // Initialize psi
806 if(psi == NULL){
807 particle->psi = 0.0; // Default psi
808 }else{
809 particle->psi = psi[i];
810 }
811 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] psi set to: %.6f.\n",rank,i, particle->psi);
812
813 // Initialize cell indices
814 if(cellIndices == NULL){
815 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input cellIndices pointer is NULL.\n");
816 }
817 particle->cell[0] = cellIndices[3 * i];
818 particle->cell[1] = cellIndices[3 * i + 1];
819 particle->cell[2] = cellIndices[3 * i + 2];
820 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] cell indices set to: [%d, %d, %d].\n",rank,i, particle->cell[0], particle->cell[1], particle->cell[2]);
821
822 if(LocStatus == NULL){
823 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input LocStatus pointer is NULL.\n");
824 }
825 // Initialize location status
826 particle->location_status = (ParticleLocationStatus)LocStatus[i];
827 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] Status set to: %d.\n",rank, i, particle->location_status);
828
829 // The destination_rank is only set by the location search, not read from the swarm,
830 // so we initialize it to a known invalid state.
831 particle->destination_rank = MPI_PROC_NULL;
832
833 // logging the completion of particle initialization
834 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d]Completed initialization of Particle [%d]. \n", rank,i);
835
836
838
839 PetscFunctionReturn(0);
840}
841
842#undef __FUNCT__
843#define __FUNCT__ "UpdateSwarmFields"
844/**
845 * @brief Internal helper implementation: `UpdateSwarmFields()`.
846 * @details Local to this translation unit.
847 */
848PetscErrorCode UpdateSwarmFields(PetscInt i, const Particle *particle,
849 PetscReal *positions,
850 PetscReal *velocities,
851 PetscReal *weights,
852 PetscInt *cellIndices,
853 PetscInt *status,
854 PetscReal *diffusivity,
855 Cmpnts *diffusivitygradient,
856 PetscReal *psi)
857{
858 PetscFunctionBeginUser;
860
861 if (!particle) {
862 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input Particle pointer is NULL.\n");
863 }
864
865 // --- 1. Position (x, y, z) ---
866 if (positions) {
867 positions[3 * i + 0] = particle->loc.x;
868 positions[3 * i + 1] = particle->loc.y;
869 positions[3 * i + 2] = particle->loc.z;
870 }
871
872 // --- 2. Velocity (u, v, w) ---
873 if (velocities) {
874 velocities[3 * i + 0] = particle->vel.x;
875 velocities[3 * i + 1] = particle->vel.y;
876 velocities[3 * i + 2] = particle->vel.z;
877 }
878
879 // --- 3. Weights (i, j, k) ---
880 if (weights) {
881 weights[3 * i + 0] = particle->weights.x;
882 weights[3 * i + 1] = particle->weights.y;
883 weights[3 * i + 2] = particle->weights.z;
884 }
885
886 // --- 4. Cell Indices (i, j, k) ---
887 if (cellIndices) {
888 cellIndices[3 * i + 0] = particle->cell[0];
889 cellIndices[3 * i + 1] = particle->cell[1];
890 cellIndices[3 * i + 2] = particle->cell[2];
891 }
892
893 // --- 5. Status ---
894 if (status) {
895 status[i] = (PetscInt)particle->location_status;
896 }
897
898 // --- 6. Diffusivity ---
899 if (diffusivity) {
900 diffusivity[i] = particle->diffusivity;
901 }
902
903 if(diffusivitygradient){
904 diffusivitygradient[i].x = particle->diffusivitygradient.x;
905 diffusivitygradient[i].y = particle->diffusivitygradient.y;
906 diffusivitygradient[i].z = particle->diffusivitygradient.z;
907 }
908 // --- 7. Psi ---
909 if (psi) {
910 psi[i] = particle->psi;
911 }
912
913 // LOG_LOOP_ALLOW(LOCAL, LOG_VERBOSE, i, 1000, "Updated fields for Particle [%d].\n", i);
914
916 PetscFunctionReturn(0);
917}
918
919#undef __FUNCT__
920#define __FUNCT__ "IsParticleInsideBoundingBox"
921/**
922 * @brief Internal helper implementation: `IsParticleInsideBoundingBox()`.
923 * @details Local to this translation unit.
924 */
925PetscBool IsParticleInsideBoundingBox(const BoundingBox *bbox, const Particle *particle)
926{
927 PetscFunctionBeginUser;
929
930 // Validate input pointers
931 if (!bbox) {
932 // LOG_ALLOW error message and return PETSC_FALSE
933 LOG_ALLOW(LOCAL,LOG_ERROR, "Error - 'bbox' pointer is NULL.");
935 return PETSC_FALSE;
936 }
937 if (!particle) {
938 LOG_ALLOW(LOCAL,LOG_ERROR,"Error - 'particle' pointer is NULL.");
940 return PETSC_FALSE;
941 }
942
943 // Extract particle location and bounding box coordinates
944 const Cmpnts loc = particle->loc;
945 const Cmpnts min_coords = bbox->min_coords;
946 const Cmpnts max_coords = bbox->max_coords;
947
948 // LOG_ALLOW the particle location and bounding box coordinates for debugging
949 LOG_ALLOW_SYNC(LOCAL, LOG_VERBOSE, "Particle PID %ld location: (%.6f, %.6f, %.6f).\n",particle->PID, loc.x, loc.y, loc.z);
950 LOG_ALLOW_SYNC(LOCAL, LOG_VERBOSE, "BoundingBox min_coords: (%.6f, %.6f, %.6f), max_coords: (%.6f, %.6f, %.6f).\n",
951 min_coords.x, min_coords.y, min_coords.z, max_coords.x, max_coords.y, max_coords.z);
952
953 // Check if the particle's location is within the bounding box
954 if ((loc.x >= min_coords.x && loc.x <= max_coords.x) &&
955 (loc.y >= min_coords.y && loc.y <= max_coords.y) &&
956 (loc.z >= min_coords.z && loc.z <= max_coords.z)) {
957 // Particle is inside the bounding box
958 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "Particle PID %ld is inside the bounding box.\n",particle->PID);
960 return PETSC_TRUE;
961 }
962
963 // Particle is outside the bounding box
964 LOG_ALLOW_SYNC(LOCAL, LOG_VERBOSE,"Particle PID %ld is outside the bounding box.\n",particle->PID);
966 return PETSC_FALSE;
967}
968
969
970#undef __FUNCT__
971#define __FUNCT__ "UpdateParticleWeights"
972/**
973 * @brief Internal helper implementation: `UpdateParticleWeights()`.
974 * @details Local to this translation unit.
975 */
976PetscErrorCode UpdateParticleWeights(PetscReal *d, Particle *particle) {
977
978 PetscFunctionBeginUser;
980
981 // Validate input pointers
982 if (!d || !particle) {
983 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
984 "Null pointer argument (d or particle).");
985 }
986
987
988 // Validate distances
989 for (PetscInt i = LEFT; i < NUM_FACES; i++) {
992 "face distance d[%d] = %f <= %f; "
993 "clamping to 1e-14 to avoid zero/negative.\n",
994 i, (double)d[i], INTERPOLATION_DISTANCE_TOLERANCE);
996 }
997 }
998
999 // LOG_ALLOW the input distances
1001 "Calculating weights with distances: "
1002 "[LEFT=%f, RIGHT=%f, BOTTOM=%f, TOP=%f, FRONT=%f, BACK=%f].\n",
1003 d[LEFT], d[RIGHT], d[BOTTOM], d[TOP], d[FRONT], d[BACK]);
1004
1005 // Compute and update the particle's weights
1006 particle->weights.x = d[LEFT] / (d[LEFT] + d[RIGHT]);
1007 particle->weights.y = d[BOTTOM] / (d[BOTTOM] + d[TOP]);
1008 particle->weights.z = d[BACK] / (d[FRONT] + d[BACK]);
1009
1010 // LOG_ALLOW the updated weights
1012 "Updated particle weights: x=%f, y=%f, z=%f.\n",
1013 particle->weights.x, particle->weights.y, particle->weights.z);
1014
1015
1017 PetscFunctionReturn(0);
1018}
1019
1020/**
1021 * @brief Initializes or loads the particle swarm based on the simulation context.
1022 *
1023 * This function is the central point for setting up the DMSwarm. Its behavior
1024 * depends on the simulation context (simCtx):
1025 *
1026 * 1. **Fresh Start (simCtx->StartStep == 0):** A new particle population is
1027 * generated according to the specified initial conditions.
1028 *
1029 * 2. **Restart (simCtx->StartStep > 0):**
1030 * - If `simCtx->particleRestartMode` is "init", a new particle population
1031 * is generated, just like a fresh start. This allows injecting fresh
1032 * particles into a pre-computed flow field.
1033 * - If `simCtx->particleRestartMode` is "load", the particle state is loaded
1034 * from restart files corresponding to the StartStep.
1035 *
1036 * @param[in,out] simCtx Pointer to the main SimulationContext, which contains all
1037 * configuration and provides access to the UserCtx.
1038 * @return PetscErrorCode Returns 0 on success, non-zero on failure.
1039 */
1040#undef __FUNCT__
1041#define __FUNCT__ "InitializeParticleSwarm"
1042/**
1043 * @brief Implementation of \ref InitializeParticleSwarm().
1044 * @details Full API contract (arguments, ownership, side effects) is documented with
1045 * the header declaration in `include/ParticleSwarm.h`.
1046 * @see InitializeParticleSwarm()
1047 */
1048
1049PetscErrorCode InitializeParticleSwarm(SimCtx *simCtx)
1050{
1051 PetscErrorCode ierr;
1052 PetscInt particlesPerProcess = 0;
1053 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1054
1055 PetscFunctionBeginUser;
1057
1058 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting particle swarm setup for %d particles.\n", simCtx->np);
1059
1060 // --- Phase 1: Create the DMSwarm Object (Always required) ---
1061 // This creates the container and registers the fields. It does not add particles yet.
1062 ierr = CreateParticleSwarm(user, simCtx->np, &particlesPerProcess, simCtx->bboxlist); CHKERRQ(ierr);
1063 LOG_ALLOW(GLOBAL, LOG_INFO, "DMSwarm object and fields created successfully.\n");
1064
1065
1066 // --- Phase 2: Decide whether to Initialize new particles or Load existing ones ---
1067 PetscBool should_initialize_new_particles = PETSC_FALSE;
1068 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1069 should_initialize_new_particles = PETSC_TRUE;
1070 }else{
1071 if (simCtx->StartStep == 0) {
1072 should_initialize_new_particles = PETSC_TRUE; // Standard fresh start
1073 } else {
1074 // It's a restart, so check the user's requested particle mode.
1075 if (strcmp(simCtx->particleRestartMode, "init") == 0) {
1076 should_initialize_new_particles = PETSC_TRUE; // User wants to re-initialize particles in a restarted flow.
1077 }
1078 }
1079 }
1080
1081 // --- Phase 3: Execute the chosen particle setup path ---
1082 if (should_initialize_new_particles) {
1083 // --- PATH A: Generate a fresh population of particles ---
1084 LOG_ALLOW(GLOBAL, LOG_INFO, "Mode: INITIALIZE. Generating new particle population.\n");
1085 PetscRandom randx, randy, randz;
1086 PetscRandom rand_logic_i, rand_logic_j, rand_logic_k;
1087
1088 ierr = InitializeRandomGenerators(user, &randx, &randy, &randz); CHKERRQ(ierr);
1089 ierr = InitializeLogicalSpaceRNGs(&rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1090 ierr = AssignInitialPropertiesToSwarm(user, particlesPerProcess, &randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k, simCtx->bboxlist); CHKERRQ(ierr);
1091 ierr = FinalizeSwarmSetup(&randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1092
1093 } else {
1094 // --- PATH B: Load particle population from restart files ---
1095 // This path is only taken if simCtx->StartStep > 0 AND simCtx->particleRestartMode == "load"
1096 LOG_ALLOW(GLOBAL, LOG_INFO, "Mode: LOAD. Loading particle population from files for step %d.\n", simCtx->StartStep);
1097
1098 ierr = PreCheckAndResizeSwarm(user, simCtx->StartStep, "dat"); CHKERRQ(ierr);
1099
1100 ierr = ReadAllSwarmFields(user, simCtx->StartStep); CHKERRQ(ierr);
1101 // Note: We check for file-open errors inside ReadAllSwarmFields now.
1102
1103 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle data loaded. CellID and status are preserved from file.\n");
1104 }
1105
1106 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "Particle swarm setup complete.\n");
1107
1109 PetscFunctionReturn(0);
1110}
PetscErrorCode GetRandomCellAndLogicalCoordsOnInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out)
Assuming the current rank services the inlet face, this function selects a random cell (owned by this...
Definition Boundaries.c:399
PetscErrorCode CanRankServiceInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscBool *can_service_inlet_out)
Determines if the current MPI rank owns any part of the globally defined inlet face,...
Definition Boundaries.c:11
PetscErrorCode GetDeterministicFaceGridLocation(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_cells_global, PetscInt JM_cells_global, PetscInt KM_cells_global, PetscInt64 particle_global_id, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out, PetscBool *placement_successful_out)
Places particles in a deterministic grid/raster pattern on a specified domain face.
Definition Boundaries.c:212
PetscErrorCode MetricLogicalToPhysical(UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, PetscReal xi, PetscReal eta, PetscReal zta, Cmpnts *Xp)
Public interface for MetricLogicalToPhysical().
Definition Metric.c:77
PetscErrorCode PreCheckAndResizeSwarm(UserCtx *user, PetscInt ti, const char *ext)
Checks particle count in the reference file and resizes the swarm if needed.
PetscErrorCode UpdateParticleWeights(PetscReal *d, Particle *particle)
Internal helper implementation: UpdateParticleWeights().
PetscErrorCode CreateParticleSwarm(UserCtx *user, PetscInt numParticles, PetscInt *particlesPerProcess, BoundingBox *bboxlist)
Internal helper implementation: CreateParticleSwarm().
PetscErrorCode FinalizeSwarmSetup(PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
Implementation of FinalizeSwarmSetup().
PetscErrorCode DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
Implementation of DistributeParticles().
static PetscErrorCode AssignInitialFieldToSwarm(UserCtx *user, const char *fieldName, PetscInt fieldDim)
Internal helper implementation: AssignInitialFieldToSwarm().
#define INTERPOLATION_DISTANCE_TOLERANCE
static PetscErrorCode InitializeSwarmFieldValue(const char *fieldName, PetscInt p, PetscInt fieldDim, PetscReal *fieldData)
Internal helper implementation: InitializeSwarmFieldValue().
PetscBool IsParticleInsideBoundingBox(const BoundingBox *bbox, const Particle *particle)
Internal helper implementation: IsParticleInsideBoundingBox().
static PetscErrorCode InitializeParticleBasicProperties(UserCtx *user, PetscInt particlesPerProcess, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k, BoundingBox *bboxlist)
Internal helper implementation: InitializeParticleBasicProperties().
PetscErrorCode UnpackSwarmFields(PetscInt i, const PetscInt64 *PIDs, const PetscReal *weights, const PetscReal *positions, const PetscInt *cellIndices, PetscReal *velocities, PetscInt *LocStatus, PetscReal *diffusivity, Cmpnts *diffusivitygradient, PetscReal *psi, Particle *particle)
Implementation of UnpackSwarmFields().
PetscErrorCode InitializeSwarm(UserCtx *user)
Implementation of InitializeSwarm().
PetscErrorCode UpdateSwarmFields(PetscInt i, const Particle *particle, PetscReal *positions, PetscReal *velocities, PetscReal *weights, PetscInt *cellIndices, PetscInt *status, PetscReal *diffusivity, Cmpnts *diffusivitygradient, PetscReal *psi)
Internal helper implementation: UpdateSwarmFields().
PetscErrorCode InitializeParticleSwarm(SimCtx *simCtx)
Implementation of InitializeParticleSwarm().
PetscErrorCode RegisterSwarmField(DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
Internal helper implementation: RegisterSwarmField().
static PetscErrorCode DetermineVolumetricInitializationParameters(UserCtx *user, DMDALocalInfo *info, PetscInt xs_gnode, PetscInt ys_gnode, PetscInt zs_gnode, PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out, PetscBool *can_place_in_volume_out)
Internal helper implementation: DetermineVolumetricInitializationParameters().
PetscErrorCode RegisterParticleFields(DM swarm)
Implementation of RegisterParticleFields().
PetscErrorCode AssignInitialPropertiesToSwarm(UserCtx *user, PetscInt particlesPerProcess, PetscRandom *rand_phys_x, PetscRandom *rand_phys_y, PetscRandom *rand_phys_z, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k, BoundingBox *bboxlist)
Internal helper implementation: AssignInitialPropertiesToSwarm().
Header file for Particle Swarm management functions.
PetscErrorCode ReadAllSwarmFields(UserCtx *user, PetscInt ti)
Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.
Definition io.c:1383
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt,...)
Logs a message inside a loop, but only every interval iterations.
Definition logging.h:297
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:183
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:252
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
Definition logging.c:669
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:199
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:779
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:84
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:28
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:33
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:770
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Helper function to convert ParticleInitialization to a string representation.
Definition logging.c:703
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global_out, PetscInt *xm_cell_local_out)
Determines the global starting index and number of CELLS owned by the current processor in a specifie...
Definition setup.c:1883
PetscErrorCode InitializeRandomGenerators(UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
Initializes random number generators for assigning particle properties.
Definition setup.c:2684
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).
Definition setup.c:2725
Cmpnts vel
Definition variables.h:169
UserCtx * user
Definition variables.h:528
PetscBool inletFaceDefined
Definition variables.h:830
BCFace identifiedInletBCFace
Definition variables.h:831
PetscInt cell[3]
Definition variables.h:167
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:814
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:509
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:512
@ PARTICLE_INIT_POINT_SOURCE
All particles at a fixed (psrc_x,psrc_y,psrc_z) — for validation.
Definition variables.h:511
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
Definition variables.h:510
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Definition variables.h:135
@ UNINITIALIZED
Definition variables.h:140
PetscReal CMy_c
Definition variables.h:705
PetscReal Min_X
Definition variables.h:821
UserMG usermg
Definition variables.h:764
PetscReal psrc_x
Definition variables.h:706
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:156
Cmpnts diffusivitygradient
Definition variables.h:174
PetscInt np
Definition variables.h:739
PetscReal Max_Y
Definition variables.h:821
PetscInt StartStep
Definition variables.h:653
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:155
PetscScalar x
Definition variables.h:101
Cmpnts loc
Definition variables.h:168
PetscMPIInt destination_rank
Definition variables.h:172
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
Definition variables.h:706
ParticleLocationStatus location_status
Definition variables.h:171
char particleRestartMode[16]
Definition variables.h:745
BoundingBox * bboxlist
Definition variables.h:742
PetscReal CMz_c
Definition variables.h:705
ParticleInitializationType ParticleInitialization
Definition variables.h:743
PetscScalar z
Definition variables.h:101
PetscInt mglevels
Definition variables.h:535
PetscReal Min_Z
Definition variables.h:821
PetscReal psrc_y
Definition variables.h:706
PetscReal Max_X
Definition variables.h:821
PetscReal Min_Y
Definition variables.h:821
PetscReal diffusivity
Definition variables.h:173
PetscReal psi
Definition variables.h:175
PetscScalar y
Definition variables.h:101
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:617
Cmpnts weights
Definition variables.h:170
@ TOP
Definition variables.h:145
@ FRONT
Definition variables.h:145
@ BOTTOM
Definition variables.h:145
@ BACK
Definition variables.h:145
@ LEFT
Definition variables.h:145
@ NUM_FACES
Definition variables.h:145
@ RIGHT
Definition variables.h:145
MGCtx * mgctx
Definition variables.h:538
ExecutionMode exec_mode
Definition variables.h:662
BoundingBox bbox
Definition variables.h:822
PetscReal Max_Z
Definition variables.h:821
PetscInt64 PID
Definition variables.h:166
PetscInt LoggingFrequency
Definition variables.h:769
PetscReal CMx_c
Definition variables.h:705
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:244
Defines a 3D axis-aligned bounding box.
Definition variables.h:154
A 3D point or vector with PetscScalar components.
Definition variables.h:100
Defines a particle's core properties for Lagrangian tracking.
Definition variables.h:165
The master context for the entire simulation.
Definition variables.h:643
User-defined context containing data specific to a single computational grid level.
Definition variables.h:811