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