PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
ParticleSwarm.c File Reference
#include "ParticleSwarm.h"
Include dependency graph for ParticleSwarm.c:

Go to the source code of this file.

Macros

#define INTERPOLATION_DISTANCE_TOLERANCE   1.0e-14
 

Functions

PetscErrorCode InitializeSwarm (UserCtx *user)
 Initializes the DMSwarm object within the UserCtx structure.
 
PetscErrorCode RegisterSwarmField (DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
 Registers a swarm field without finalizing registration.
 
PetscErrorCode RegisterParticleFields (DM swarm)
 Registers necessary particle fields within the DMSwarm.
 
PetscErrorCode InitializeRandomGenerators (UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
 Initializes random number generators for assigning particle properties.
 
PetscErrorCode InitializeLogicalSpaceRNGs (PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
 Initializes random number generators for logical space operations [0.0, 1.0).
 
static 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)
 Determines cell selection and intra-cell logical coordinates for volumetric initialization (Mode 1).
 
static PetscErrorCode InitializeParticleBasicProperties (UserCtx *user, PetscInt particlesPerProcess, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k, BoundingBox *bboxlist)
 Initializes basic properties for particles on the local process.
 
static PetscErrorCode UpdateSwarmFieldValue (const char *fieldName, PetscInt p, PetscInt fieldDim, PetscReal *fieldData)
 Helper function to update a given particle’s field value.
 
static PetscErrorCode AssignInitialFieldToSwarm (UserCtx *user, const char *fieldName, PetscInt fieldDim)
 Initializes a generic swarm field with point-level updates.
 
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)
 Initializes all particle properties in the swarm.
 
PetscErrorCode DistributeParticles (PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
 Distributes particles evenly across MPI processes, handling any remainders.
 
PetscErrorCode FinalizeSwarmSetup (PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
 Finalizes the swarm setup by destroying random generators and logging completion.
 
PetscErrorCode CreateParticleSwarm (UserCtx *user, PetscInt numParticles, PetscInt *particlesPerProcess, BoundingBox *bboxlist)
 Creates and initializes a Particle Swarm.
 
PetscErrorCode UnpackSwarmFields (PetscInt i, const PetscInt64 *PIDs, const PetscReal *weights, const PetscReal *positions, const PetscInt *cellIndices, PetscReal *velocities, PetscInt *LocStatus, Particle *particle)
 Initializes a Particle struct with data from DMSwarm fields.
 
PetscErrorCode UpdateSwarmFields (PetscInt i, const Particle *particle, PetscReal *weights, PetscInt *cellIndices, PetscInt *status_field)
 Updates DMSwarm fields with data from a Particle struct.
 
PetscBool IsParticleInsideBoundingBox (const BoundingBox *bbox, const Particle *particle)
 Checks if a particle's location is within a specified bounding box.
 
PetscErrorCode UpdateParticleWeights (PetscReal *d, Particle *particle)
 Updates a particle's interpolation weights based on distances to cell faces.
 
PetscErrorCode PrepareLoadedSwarmForRelocation (UserCtx *user)
 Resets the location-dependent state of a loaded swarm to force relocation.
 
PetscErrorCode InitializeParticleSwarm (SimCtx *simCtx)
 Perform particle swarm initialization, particle-grid interaction, and related operations.
 

Macro Definition Documentation

◆ INTERPOLATION_DISTANCE_TOLERANCE

#define INTERPOLATION_DISTANCE_TOLERANCE   1.0e-14

Definition at line 5 of file ParticleSwarm.c.

Function Documentation

◆ InitializeSwarm()

PetscErrorCode InitializeSwarm ( UserCtx user)

Initializes the DMSwarm object within the UserCtx structure.

This function creates the DMSwarm, sets its type and dimension, and configures basic swarm properties.

Parameters
[in,out]userPointer to the UserCtx structure containing simulation context.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 15 of file ParticleSwarm.c.

15 {
16 PetscErrorCode ierr; // Error code for PETSc functions
17
18 // Create the DMSwarm object for particle management
19 ierr = DMCreate(PETSC_COMM_WORLD, &user->swarm); CHKERRQ(ierr);
20 ierr = DMSetType(user->swarm, DMSWARM); CHKERRQ(ierr);
21 ierr = DMSetDimension(user->swarm, 3); CHKERRQ(ierr);
22 ierr = DMSwarmSetType(user->swarm, DMSWARM_BASIC); CHKERRQ(ierr);
23 LOG_ALLOW(LOCAL,LOG_INFO, "InitializeSwarm - DMSwarm created and configured.\n");
24
25 return 0;
26 }
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#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:207
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:32
Here is the caller graph for this function:

◆ RegisterSwarmField()

PetscErrorCode RegisterSwarmField ( DM  swarm,
const char *  fieldName,
PetscInt  fieldDim,
PetscDataType  dtype 
)

Registers a swarm field without finalizing registration.

This function calls DMSwarmRegisterPetscDatatypeField for the given field, but does not finalize the registration. The finalization is deferred until all fields have been registered.

Parameters
swarm[in] The DMSwarm object.
fieldName[in] Name of the field to register.
fieldDim[in] Dimension of the field (1 for scalar, 3 for vector, etc.).
dtype[in] The datatype of the swarm field being registered.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 41 of file ParticleSwarm.c.

42 {
43 PetscErrorCode ierr;
44 PetscFunctionBeginUser;
45
46 ierr = DMSwarmRegisterPetscDatatypeField(swarm, fieldName, fieldDim, dtype); CHKERRQ(ierr);
47 // PetscDataTypes is an extern char* [] defined in petscsystypes.h that gives string names for PetscDataType enums
48 LOG_ALLOW(LOCAL,LOG_DEBUG,"RegisterSwarmField - Registered field '%s' with dimension=%d, type=%s.\n",
49 fieldName, fieldDim, PetscDataTypes[dtype]);
50
51 PetscFunctionReturn(0);
52 }
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:33
Here is the caller graph for this function:

◆ RegisterParticleFields()

PetscErrorCode RegisterParticleFields ( DM  swarm)

Registers necessary particle fields within the DMSwarm.

This function registers fields such as position, velocity, CellID, and weight for each particle.

Parameters
[in,out]swarmThe DMSwarm object managing the particle swarm.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 64 of file ParticleSwarm.c.

65 {
66 PetscErrorCode ierr;
67 PetscFunctionBeginUser;
68
69 // Register each field using the helper function
70 ierr = RegisterSwarmField(swarm, "position", 3 ,PETSC_REAL); CHKERRQ(ierr);
71 LOG_ALLOW(LOCAL,LOG_DEBUG, "Registered field 'position'.\n");
72
73 ierr = RegisterSwarmField(swarm, "velocity", 3, PETSC_REAL); CHKERRQ(ierr);
74 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'velocity'.\n");
75
76 ierr = RegisterSwarmField(swarm, "DMSwarm_CellID", 3, PETSC_INT); CHKERRQ(ierr);
77 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'DMSwarm_CellID'.\n");
78
79 ierr = RegisterSwarmField(swarm, "weight", 3,PETSC_REAL); CHKERRQ(ierr);
80 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'weight'.\n");
81
82 ierr = RegisterSwarmField(swarm,"Psi", 1,PETSC_REAL); CHKERRQ(ierr);
83 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'Psi' - Scalar.\n");
84
85
86 ierr = RegisterSwarmField(swarm,"pos_phy", 3,PETSC_REAL); CHKERRQ(ierr);
87 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'pos_phy' - Physical Position.\n");
88
89 ierr = RegisterSwarmField(swarm,"DMSwarm_location_status",1,PETSC_INT);CHKERRQ(ierr);
90 LOG_ALLOW(LOCAL,LOG_DEBUG,"Registered field 'DMSwarm_location_status' - Status of Location of Particle(located,lost etc).\n");
91
92 // Finalize the field registration after all fields have been added
93 ierr = DMSwarmFinalizeFieldRegister(swarm); CHKERRQ(ierr);
94 LOG_ALLOW(LOCAL,LOG_INFO,"RegisterParticleFields - Finalized field registration.\n");
95
96 PetscFunctionReturn(0);
97 }
PetscErrorCode RegisterSwarmField(DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
Registers a swarm field without finalizing registration.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitializeRandomGenerators()

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

Initializes random number generators for assigning particle properties.

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

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

Definition at line 112 of file ParticleSwarm.c.

112 {
113 PetscErrorCode ierr; // Error code for PETSc functions
114 PetscMPIInt rank;
115 MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
116
117 // Initialize RNG for x-coordinate
118 ierr = PetscRandomCreate(PETSC_COMM_SELF, randx); CHKERRQ(ierr);
119 ierr = PetscRandomSetType((*randx), PETSCRAND48); CHKERRQ(ierr);
120 ierr = PetscRandomSetInterval(*randx, user->bbox.min_coords.x, user->bbox.max_coords.x); CHKERRQ(ierr);
121 ierr = PetscRandomSetSeed(*randx, rank + 12345); CHKERRQ(ierr); // Unique seed per rank
122 ierr = PetscRandomSeed(*randx); CHKERRQ(ierr);
123 LOG_ALLOW_SYNC(LOCAL,LOG_DEBUG, "InitializeRandomGenerators - Initialized RNG for X-axis.\n");
124
125 // Initialize RNG for y-coordinate
126 ierr = PetscRandomCreate(PETSC_COMM_SELF, randy); CHKERRQ(ierr);
127 ierr = PetscRandomSetType((*randy), PETSCRAND48); CHKERRQ(ierr);
128 ierr = PetscRandomSetInterval(*randy, user->bbox.min_coords.y, user->bbox.max_coords.y); CHKERRQ(ierr);
129 ierr = PetscRandomSetSeed(*randy, rank + 67890); CHKERRQ(ierr); // Unique seed per rank
130 ierr = PetscRandomSeed(*randy); CHKERRQ(ierr);
131 LOG_ALLOW_SYNC(LOCAL,LOG_DEBUG, "InitializeRandomGenerators - Initialized RNG for Y-axis.\n");
132
133 // Initialize RNG for z-coordinate
134 ierr = PetscRandomCreate(PETSC_COMM_SELF, randz); CHKERRQ(ierr);
135 ierr = PetscRandomSetType((*randz), PETSCRAND48); CHKERRQ(ierr);
136 ierr = PetscRandomSetInterval(*randz, user->bbox.min_coords.z, user->bbox.max_coords.z); CHKERRQ(ierr);
137 ierr = PetscRandomSetSeed(*randz, rank + 54321); CHKERRQ(ierr); // Unique seed per rank
138 ierr = PetscRandomSeed(*randz); CHKERRQ(ierr);
139 LOG_ALLOW_SYNC(LOCAL,LOG_DEBUG, "InitializeRandomGenerators - Initialized RNG for Z-axis.\n");
140
141 return 0;
142 }
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
----— DEBUG ---------------------------------------— #define LOG_ALLOW(scope, level,...
Definition logging.h:274
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:155
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:154
PetscScalar x
Definition variables.h:100
PetscScalar z
Definition variables.h:100
PetscScalar y
Definition variables.h:100
BoundingBox bbox
Definition variables.h:641
Here is the caller graph for this function:

◆ InitializeLogicalSpaceRNGs()

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

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

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

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

Definition at line 158 of file ParticleSwarm.c.

158 {
159 PetscErrorCode ierr;
160 PetscMPIInt rank;
161 PetscFunctionBeginUser;
162
163 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
164
165 // --- RNG for i-logical dimension ---
166 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_i); CHKERRQ(ierr);
167 ierr = PetscRandomSetType((*rand_logic_i), PETSCRAND48); CHKERRQ(ierr);
168 ierr = PetscRandomSetInterval(*rand_logic_i, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
169 ierr = PetscRandomSetSeed(*rand_logic_i, rank + 202401); CHKERRQ(ierr); // Unique seed
170 ierr = PetscRandomSeed(*rand_logic_i); CHKERRQ(ierr);
171 LOG_ALLOW(LOCAL,LOG_DEBUG, "InitializeLogicalSpaceRNGs - Initialized RNG for i-logical dimension [0,1).\n");
172
173 // --- RNG for j-logical dimension ---
174 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_j); CHKERRQ(ierr);
175 ierr = PetscRandomSetType((*rand_logic_j), PETSCRAND48); CHKERRQ(ierr);
176 ierr = PetscRandomSetInterval(*rand_logic_j, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
177 ierr = PetscRandomSetSeed(*rand_logic_j, rank + 202402); CHKERRQ(ierr);
178 ierr = PetscRandomSeed(*rand_logic_j); CHKERRQ(ierr);
179 LOG_ALLOW(LOCAL,LOG_DEBUG, "InitializeLogicalSpaceRNGs - Initialized RNG for j-logical dimension [0,1).\n");
180
181 // --- RNG for k-logical dimension ---
182 ierr = PetscRandomCreate(PETSC_COMM_SELF, rand_logic_k); CHKERRQ(ierr);
183 ierr = PetscRandomSetType((*rand_logic_k), PETSCRAND48); CHKERRQ(ierr);
184 ierr = PetscRandomSetInterval(*rand_logic_k, 0.0, 1.0); CHKERRQ(ierr); // Key change: [0,1)
185 ierr = PetscRandomSetSeed(*rand_logic_k, rank + 202403); CHKERRQ(ierr);
186 ierr = PetscRandomSeed(*rand_logic_k); CHKERRQ(ierr);
187 LOG_ALLOW(LOCAL,LOG_DEBUG, "InitializeLogicalSpaceRNGs - Initialized RNG for k-logical dimension [0,1).\n");
188
189 PetscFunctionReturn(0);
190 }
Here is the caller graph for this function:

◆ DetermineVolumetricInitializationParameters()

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

Determines cell selection and intra-cell logical coordinates for volumetric initialization (Mode 1).

This function is called when simCtx->ParticleInitialization == 1. It randomly selects an owned cell on the current MPI rank and then generates random intra-cell logical coordinates [0,1)^3 within that chosen cell.

The process involves:

  1. Checking if the current MPI rank owns any 3D cells.
  2. If it does, it randomly selects an owned cell index in each logical direction (i, j, k) by scaling a [0,1) random number with the number of owned cells in that direction.
  3. These local owned cell indices are then converted to the local node indices (ci/cj/ck_metric_lnode_out) corresponding to the origin of the selected cell, for use with MetricLogicalToPhysical. This conversion uses xs/ys/zs_gnode.
  4. All three intra-cell logical coordinates (xi/eta/zta_metric_logic_out) for MetricLogicalToPhysical are chosen randomly within the [0,1) range.
  5. A flag (can_place_in_volume_out) indicates if a valid placement could be determined.

Important Note on DMDALocalInfo info members (same as for surface init):

  • info->xs, info->ys, info->ks: Global starting indices of owned cells.
  • info->mx, info->my, info->mz: Number of grid points (nodes) in each local dimension on this process. Therefore, the number of owned cells in a dimension is info->mX - 1 (if info->mX > 0).
Parameters
[in]userPointer to UserCtx. (Currently not used in this specific helper, but kept for API consistency).
[in]infoPointer to DMDALocalInfo for the current rank's grid portion.
[in]xs_gnode,ys_gnode,zs_gnodeLocal indices (in the ghosted array) of the first owned node.
[in]rand_logic_i_ptrPointer to the RNG for i-dimension tasks [0,1).
[in]rand_logic_j_ptrPointer to the RNG for j-dimension tasks [0,1).
[in]rand_logic_k_ptrPointer to the RNG for k-dimension tasks [0,1).
[out]ci_metric_lnode_outPointer to store the local i-node index of the selected cell's origin.
[out]cj_metric_lnode_outPointer to store the local j-node index of the selected cell's origin.
[out]ck_metric_lnode_outPointer to store the local k-node index of the selected cell's origin.
[out]xi_metric_logic_outPointer to store the intra-cell logical xi-coordinate [0,1).
[out]eta_metric_logic_outPointer to store the intra-cell logical eta-coordinate [0,1).
[out]zta_metric_logic_outPointer to store the intra-cell logical zeta-coordinate [0,1).
[out]can_place_in_volume_outPETSC_TRUE if placement parameters were successfully determined, PETSC_FALSE otherwise.
Returns
PetscErrorCode 0 on success, or a PETSc error code.

Definition at line 230 of file ParticleSwarm.c.

237 {
238 PetscErrorCode ierr = 0;
239 PetscReal r_val; // Temporary for random numbers from [0,1) RNGs
240 PetscInt local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k;
241 PetscMPIInt rank_for_logging; // For logging if needed
242
243 PetscFunctionBeginUser;
244 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_for_logging); CHKERRQ(ierr);
245
246 *can_place_in_volume_out = PETSC_FALSE; // Default to: cannot place
247
248 // Default intra-cell logicals and cell node indices (e.g. if placement fails)
249 *xi_metric_logic_out = 0.5; *eta_metric_logic_out = 0.5; *zta_metric_logic_out = 0.5;
250 *ci_metric_lnode_out = xs_gnode; *cj_metric_lnode_out = ys_gnode; *ck_metric_lnode_out = zs_gnode;
251
252 // Calculate number of owned cells in each direction from node counts in info
253 // Assumes info->mx, info->my, info->mz are node counts on this process for each dimension.
254 // Number of cells = Number of nodes - 1 (if > 0 nodes).
255 PetscInt num_owned_cells_i = (info->mx > 1) ? info->mx - 1 : 0;
256 PetscInt num_owned_cells_j = (info->my > 1) ? info->my - 1 : 0;
257 PetscInt num_owned_cells_k = (info->mz > 1) ? info->mz - 1 : 0;
258
259 if (num_owned_cells_i > 0 && num_owned_cells_j > 0 && num_owned_cells_k > 0) { // If rank owns any 3D cells
260 *can_place_in_volume_out = PETSC_TRUE;
261
262 // --- 1. Select a Random Owned Cell ---
263 // The selected index will be a 0-based index relative to the start of this rank's owned cells.
264
265 // Select random local owned cell index in I-direction
266 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
267 local_owned_cell_idx_i = (PetscInt)(r_val * num_owned_cells_i);
268 // Clamp to be safe: local_owned_cell_idx_i should be in [0, num_owned_cells_i - 1]
269 local_owned_cell_idx_i = PetscMin(PetscMax(0, local_owned_cell_idx_i), num_owned_cells_i - 1);
270 *ci_metric_lnode_out = xs_gnode + local_owned_cell_idx_i; // Convert to local node index for cell origin
271
272 // Select random local owned cell index in J-direction
273 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
274 local_owned_cell_idx_j = (PetscInt)(r_val * num_owned_cells_j);
275 local_owned_cell_idx_j = PetscMin(PetscMax(0, local_owned_cell_idx_j), num_owned_cells_j - 1);
276 *cj_metric_lnode_out = ys_gnode + local_owned_cell_idx_j;
277
278 // Select random local owned cell index in K-direction
279 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
280 local_owned_cell_idx_k = (PetscInt)(r_val * num_owned_cells_k);
281 local_owned_cell_idx_k = PetscMin(PetscMax(0, local_owned_cell_idx_k), num_owned_cells_k - 1);
282 *ck_metric_lnode_out = zs_gnode + local_owned_cell_idx_k;
283
284 LOG_ALLOW(LOCAL, LOG_DEBUG, "DVP - 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",
285 rank_for_logging, local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k,
286 *ci_metric_lnode_out, *cj_metric_lnode_out, *ck_metric_lnode_out,
287 num_owned_cells_i, num_owned_cells_j, num_owned_cells_k,
288 xs_gnode, ys_gnode, zs_gnode);
289
290
291 // --- 2. Generate Random Intra-Cell Logical Coordinates [0,1) for MetricLogicalToPhysical ---
292 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, xi_metric_logic_out); CHKERRQ(ierr); // Re-use RNGs
293 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, eta_metric_logic_out); CHKERRQ(ierr);
294 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, zta_metric_logic_out); CHKERRQ(ierr);
295
296 // Ensure logical coordinates are strictly within [0,1) for robustness with MetricLogicalToPhysical
297 *xi_metric_logic_out = PetscMin(*xi_metric_logic_out, 1.0 - 1.0e-7);
298 *eta_metric_logic_out = PetscMin(*eta_metric_logic_out, 1.0 - 1.0e-7);
299 *zta_metric_logic_out = PetscMin(*zta_metric_logic_out, 1.0 - 1.0e-7);
300 // Ensure they are not negative either (though [0,1) RNGs shouldn't produce this)
301 *xi_metric_logic_out = PetscMax(*xi_metric_logic_out, 0.0);
302 *eta_metric_logic_out = PetscMax(*eta_metric_logic_out, 0.0);
303 *zta_metric_logic_out = PetscMax(*zta_metric_logic_out, 0.0);
304
305 } else {
306 // This rank does not own any 3D cells (e.g., in a 1D or 2D decomposition,
307 // or if the global domain itself is not 3D in terms of cells).
308 // *can_place_in_volume_out remains PETSC_FALSE.
309 LOG_ALLOW(LOCAL, LOG_WARNING, "DVP - 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",
310 rank_for_logging, num_owned_cells_i, num_owned_cells_j, num_owned_cells_k);
311 }
312 PetscFunctionReturn(0);
313 }
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
Here is the caller graph for this function:

◆ InitializeParticleBasicProperties()

static PetscErrorCode InitializeParticleBasicProperties ( UserCtx user,
PetscInt  particlesPerProcess,
PetscRandom *  rand_logic_i,
PetscRandom *  rand_logic_j,
PetscRandom *  rand_logic_k,
BoundingBox bboxlist 
)
static

Initializes basic properties for particles on the local process.

This function assigns initial physical positions, Particle IDs (PIDs), and placeholder cell IDs to particles. The method of position initialization depends on simCtx->ParticleInitialization:

  • Mode 0 (Surface): Particles are placed on a designated inlet surface if the current rank services that surface. Otherwise, they are placed at (0,0,0) to be migrated to the correct rank later.
  • Mode 1 (Volumetric): Particles are placed randomly within a cell owned by the current rank.

The logical coordinates for placement are generated using provided random number generators. These logical coordinates are then transformed to physical coordinates using MetricLogicalToPhysical.

Parameters
userPointer to the UserCtx structure, containing simulation settings and grid information.
particlesPerProcessThe number of particles to initialize on this MPI rank.
rand_logic_iPointer to a PetscRandom generator for the xi logical coordinate.
rand_logic_jPointer to a PetscRandom generator for the eta logical coordinate.
rand_logic_kPointer to a PetscRandom generator for the zeta logical coordinate.
bboxlist(Unused in this function for placement) Pointer to the bounding box list; provided for API consistency but not used for determining initial positions here. Particle positions are determined by logical-to-physical mapping based on rank's owned cells.
Returns
PetscErrorCode 0 on success, non-zero on failure.

Definition at line 341 of file ParticleSwarm.c.

347 {
348 PetscErrorCode ierr;
349 DM swarm = user->swarm;
350 PetscReal *positions_field = NULL; // Pointer to swarm field for physical positions (x,y,z)
351 PetscReal *pos_phy_field = NULL; // Pointer to swarm field for physical positions (backup/alternative)
352 PetscInt64 *particleIDs = NULL; // Pointer to swarm field for Particle IDs
353 PetscInt *cellIDs_petsc = NULL; // Pointer to swarm field for DMSwarm_CellID (i,j,k of containing cell)
354 PetscInt *status_field = NULL; // Pointer to swarm field for DMSwarm_location_status(NEEDS_LOCATION etc)
355 PetscMPIInt rank,size; // MPI rank of the current process, and total number of ranks.
356 const Cmpnts ***coor_nodes_local_array; // Read-only access to local node coordinates (from user->da)
357 Vec Coor_local; // Local vector for node coordinates
358 DMDALocalInfo info; // Local grid information (node-based) from user->da
359 PetscInt xs_gnode_rank, ys_gnode_rank, zs_gnode_rank; // Local starting node indices (incl. ghosts) of rank's DA patch
360 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global; // Global node counts in each direction
361
362 // Variables for surface initialization (Mode 0)
363 PetscBool can_this_rank_service_inlet = PETSC_FALSE;
364
365 PetscFunctionBeginUser;
366
367 SimCtx *simCtx = user->simCtx;
368
369 // --- 1. Input Validation and Basic Setup ---
370 if (!user || !rand_logic_i || !rand_logic_j || !rand_logic_k) {
371 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "InitializeParticleBasicProperties - Null user or RNG pointer.");
372 }
373 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
374 ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size); CHKERRQ(ierr);
375
376 // Get DMDA information for the node-centered coordinate grid (user->da)
377 ierr = DMGetCoordinatesLocal(user->da, &Coor_local); CHKERRQ(ierr);
378 if (!Coor_local) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "DMGetCoordinatesLocal for user->da returned NULL Coor_local.");
379 ierr = DMDAVecGetArrayRead(user->fda, Coor_local, (void*)&coor_nodes_local_array); CHKERRQ(ierr);
380 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
381 ierr = DMDAGetGhostCorners(user->da, &xs_gnode_rank, &ys_gnode_rank, &zs_gnode_rank, NULL, NULL, NULL); CHKERRQ(ierr);
382 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);
383
384 LOG_ALLOW(LOCAL, LOG_INFO, "InitializeParticleBasicProperties - Rank %d: Initializing %d particles. Mode: %d.\n",
385 rank, particlesPerProcess, simCtx->ParticleInitialization);
386
387 // --- 2. Pre-computation for Surface Initialization (Mode 0) ---
388 if (simCtx->ParticleInitialization == 0) { // Surface initialization
389 ierr = CanRankServiceInletFace(user, &info, IM_nodes_global, JM_nodes_global, KM_nodes_global, &can_this_rank_service_inlet); CHKERRQ(ierr);
390 if (can_this_rank_service_inlet) {
391 LOG_ALLOW(LOCAL, LOG_INFO, "InitProps - Rank %d: Will attempt to place particles on inlet face %d.\n", rank, user->identifiedInletBCFace);
392 } else {
393 LOG_ALLOW(LOCAL, LOG_INFO, "InitProps - Rank %d: Cannot service inlet face %d. Particles will be at default (0,0,0) and rely on migration.\n", rank, user->identifiedInletBCFace);
394 }
395 }
396
397 // --- 3. Get Access to Swarm Fields ---
398 ierr = DMSwarmGetField(swarm, "position", NULL, NULL, (void**)&positions_field); CHKERRQ(ierr);
399 ierr = DMSwarmGetField(swarm, "pos_phy", NULL, NULL, (void**)&pos_phy_field); CHKERRQ(ierr);
400 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
401 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs_petsc); CHKERRQ(ierr);
402 ierr = DMSwarmGetField(swarm, "DMSwarm_location_status",NULL,NULL,(void**)&status_field); CHKERRQ(ierr);
403
404 // --- 4. Determine Starting Global PID for this Rank ---
405 PetscInt particles_per_rank_ideal = simCtx->np / size; // Assumes user->size is PETSC_COMM_WORLD size
406 PetscInt remainder_particles = simCtx->np % size;
407 PetscInt base_pid_for_rank = rank * particles_per_rank_ideal + PetscMin(rank, remainder_particles);
408 // This calculation must match how particlesPerProcess was determined (e.g., in DistributeParticles).
409
410 // --- 5. Loop Over Particles to Initialize ---
411 for (PetscInt p = 0; p < particlesPerProcess; p++) {
412 PetscInt ci_metric_lnode, cj_metric_lnode, ck_metric_lnode;
413 PetscReal xi_metric_logic, eta_metric_logic, zta_metric_logic;
414 Cmpnts phys_coords = {0.0, 0.0, 0.0};
415 PetscBool particle_placed_by_this_rank = PETSC_FALSE;
416
417 if (simCtx->ParticleInitialization == 0) { // --- 5.a. Surface Initialization ---
418 if (can_this_rank_service_inlet) {
419 ierr = GetRandomCellAndLogicOnInletFace(user, &info, xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
420 IM_nodes_global, JM_nodes_global, KM_nodes_global,
421 rand_logic_i, rand_logic_j, rand_logic_k,
422 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
423 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic); CHKERRQ(ierr);
424 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
425 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
426 xi_metric_logic, eta_metric_logic, zta_metric_logic,
427 &phys_coords); CHKERRQ(ierr);
428 particle_placed_by_this_rank = PETSC_TRUE;
429 }
430 } else { // --- 5.b. Volumetric Initialization (simCtx->ParticleInitialization == 1) ---
431 PetscBool can_place_volumetrically;
432 ierr = DetermineVolumetricInitializationParameters(user, &info, xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
433 rand_logic_i, rand_logic_j, rand_logic_k,
434 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
435 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
436 &can_place_volumetrically); CHKERRQ(ierr);
437 if(can_place_volumetrically){
438 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
439 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
440 xi_metric_logic, eta_metric_logic, zta_metric_logic,
441 &phys_coords); CHKERRQ(ierr);
442 particle_placed_by_this_rank = PETSC_TRUE;
443 } else {
445 "InitProps - Rank %d: PID %lld (idx %ld) (Volumetric Mode %d) - DetermineVolumetric... returned false. Default Phys: (%.2f,%.2f,%.2f).\n",
446 rank, (long long)(base_pid_for_rank + p), (long)p, simCtx->ParticleInitialization, phys_coords.x, phys_coords.y, phys_coords.z);
447 }
448 }
449
450 // --- 5.c. Store Particle Properties ---
451 positions_field[3*p+0] = phys_coords.x;
452 positions_field[3*p+1] = phys_coords.y;
453 positions_field[3*p+2] = phys_coords.z;
454 pos_phy_field[3*p+0] = phys_coords.x;
455 pos_phy_field[3*p+1] = phys_coords.y;
456 pos_phy_field[3*p+2] = phys_coords.z;
457 particleIDs[p] = (PetscInt64)base_pid_for_rank + p;
458 cellIDs_petsc[3*p+0] = -1; cellIDs_petsc[3*p+1] = -1; cellIDs_petsc[3*p+2] = -1;
459 status_field[p] = UNINITIALIZED;
460
461 // --- 5.d. Logging for this particle ---
462 if (particle_placed_by_this_rank) {
463 LOG_LOOP_ALLOW(LOCAL, LOG_DEBUG, p, (particlesPerProcess > 20 ? particlesPerProcess/10 : 1),
464 "InitProps - Rank %d: PID %lld (idx %ld) PLACED. Mode %d. CellOriginNode(locDAIdx):(%d,%d,%d). LogicCoords: (%.2e,%.2f,%.2f). PhysCoords: (%.6f,%.6f,%.6f).\n",
465 rank, (long long)particleIDs[p], (long)p, simCtx->ParticleInitialization,
466 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
467 xi_metric_logic, eta_metric_logic, zta_metric_logic,
468 phys_coords.x, phys_coords.y, phys_coords.z);
469 } else {
470 LOG_LOOP_ALLOW(LOCAL, LOG_WARNING, p, (particlesPerProcess > 20 ? particlesPerProcess/10 : 1),
471 "InitProps - Rank %d: PID %lld (idx %ld) Mode %d NOT placed by this rank's logic. Default Phys: (%.2f,%.2f,%.2f). Relies on migration.\n",
472 rank, (long long)particleIDs[p], (long)p, simCtx->ParticleInitialization,
473 phys_coords.x, phys_coords.y, phys_coords.z);
474 }
475 }
476
477 // --- 6. Restore Pointers and Cleanup ---
478 ierr = DMSwarmRestoreField(swarm, "position", NULL, NULL, (void**)&positions_field); CHKERRQ(ierr);
479 ierr = DMSwarmRestoreField(swarm, "pos_phy", NULL, NULL, (void**)&pos_phy_field); CHKERRQ(ierr);
480 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
481 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs_petsc); CHKERRQ(ierr);
482 ierr = DMSwarmRestoreField(swarm, "DMSwarm_location_status", NULL, NULL, (void**)&status_field); CHKERRQ(ierr);
483 ierr = DMDAVecRestoreArrayRead(user->fda, Coor_local, (void*)&coor_nodes_local_array); CHKERRQ(ierr);
484
485 LOG_ALLOW(LOCAL, LOG_INFO, "InitializeParticleBasicProperties - Rank %d: Completed processing for %d particles.\n",
486 rank, particlesPerProcess);
487 PetscFunctionReturn(0);
488 }
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:24
PetscErrorCode GetRandomCellAndLogicOnInletFace(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:225
PetscErrorCode MetricLogicalToPhysical(UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, PetscReal xi, PetscReal eta, PetscReal zta, Cmpnts *Xp)
Public wrapper: map (cell index, ξ,η,ζ) to (x,y,z).
Definition Metric.c:68
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)
Determines cell selection and intra-cell logical coordinates for volumetric initialization (Mode 1).
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt,...)
Logs a message inside a loop, but only every interval iterations.
Definition logging.h:319
BCFace identifiedInletBCFace
Definition variables.h:650
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:633
@ UNINITIALIZED
Definition variables.h:139
PetscInt np
Definition variables.h:585
PetscInt ParticleInitialization
Definition variables.h:589
A 3D point or vector with PetscScalar components.
Definition variables.h:99
The master context for the entire simulation.
Definition variables.h:513
Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdateSwarmFieldValue()

static PetscErrorCode UpdateSwarmFieldValue ( const char *  fieldName,
PetscInt  p,
PetscInt  fieldDim,
PetscReal *  fieldData 
)
static

Helper function to update a given particle’s field value.

This function performs conditional, point-level updates for a swarm field based on its name. For example, you might want to initialize the "velocity" field to 0.0, but the "temperature" field to a nonzero default (e.g., 300.0). This function can be extended for other fields.

Parameters
[in]fieldNameName of the swarm field.
[in]pParticle index.
[in]fieldDimDimension of the field.
[out]fieldDataPointer to the field’s data array.
Returns
PetscErrorCode Returns 0 on success.

Definition at line 504 of file ParticleSwarm.c.

505 {
506 PetscFunctionBeginUser;
507 if (strcmp(fieldName, "velocity") == 0) {
508 // For velocity, initialize all components to zero
509 for (PetscInt d = 0; d < fieldDim; d++) {
510 fieldData[fieldDim * p + d] = 0.0;
511 }
512 } else if (strcmp(fieldName, "temperature") == 0) {
513 // For temperature, for example, initialize to a default value (e.g., 300.0)
514 for (PetscInt d = 0; d < fieldDim; d++) {
515 fieldData[fieldDim * p + d] = 300.0;
516 }
517 } else if (strcmp(fieldName, "Psi") == 0) {
518 // For pressure, initialize to a default value (e.g., 101325.0)
519 for (PetscInt d = 0; d < fieldDim; d++) {
520 fieldData[fieldDim * p + d] = 0.0;
521 }
522 } else {
523 // Default: initialize all components to zero
524 for (PetscInt d = 0; d < fieldDim; d++) {
525 fieldData[fieldDim * p + d] = 0.0;
526 }
527 }
528 PetscFunctionReturn(0);
529 }
Here is the caller graph for this function:

◆ AssignInitialFieldToSwarm()

static PetscErrorCode AssignInitialFieldToSwarm ( UserCtx user,
const char *  fieldName,
PetscInt  fieldDim 
)
static

Initializes a generic swarm field with point-level updates.

This field-agnostic function retrieves the specified swarm field (which may be scalar or multi-component) and initializes each particle's entry using a helper that performs conditional updates based on the field name.

Parameters
[in,out]userPointer to the UserCtx structure containing the swarm.
[in]fieldNameName of the swarm field to initialize.
[in]fieldDimDimension of the field (e.g., 1 for scalar, 3 for vector).
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 544 of file ParticleSwarm.c.

545 {
546 PetscErrorCode ierr;
547 DM swarm = user->swarm;
548 PetscReal *fieldData = NULL;
549 PetscInt nLocal;
550
551 PetscFunctionBeginUser;
552
553 // Get the number of local particles
554 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
555 LOG_ALLOW(LOCAL,LOG_INFO, "AssignInitialFieldToSwarm - %d local particles found.\n", nLocal);
556
557 // Retrieve the swarm field pointer for the specified fieldName
558 ierr = DMSwarmGetField(swarm, fieldName, NULL, NULL, (void**)&fieldData); CHKERRQ(ierr);
559 LOG_ALLOW(LOCAL,LOG_DEBUG, "AssignInitialFieldToSwarm - Retrieved field '%s'.\n", fieldName);
560
561 // Loop over all particles and update the field using the helper function
562 for (PetscInt p = 0; p < nLocal; p++) {
563 ierr = UpdateSwarmFieldValue(fieldName, p, fieldDim, fieldData); CHKERRQ(ierr);
564 PetscReal disp_data[fieldDim];
565
566 for (PetscInt d = 0; d < fieldDim; d++) {
567 disp_data[d] = fieldData[fieldDim* p + d];
568 }
569 LOG_LOOP_ALLOW(LOCAL,LOG_DEBUG,p, 100," Particle %d: %s[%d] = [%.6f, ...,%.6f].\n", p,fieldName,fieldDim,disp_data[0],disp_data[fieldDim-1]);
570 }
571
572 // Restore the swarm field pointer
573 ierr = DMSwarmRestoreField(swarm, fieldName, NULL, NULL, (void**)&fieldData); CHKERRQ(ierr);
574 LOG_ALLOW(LOCAL,LOG_INFO, "AssignInitialFieldToSwarm - Initialization of field '%s' complete.\n", fieldName);
575
576 PetscFunctionReturn(0);
577 }
static PetscErrorCode UpdateSwarmFieldValue(const char *fieldName, PetscInt p, PetscInt fieldDim, PetscReal *fieldData)
Helper function to update a given particle’s field value.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AssignInitialPropertiesToSwarm()

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 
)

Initializes all particle properties in the swarm.

This function orchestrates the initialization of particle properties. It first determines the inlet face if surface initialization (Mode 0) is selected by parsing "bcs.dat". Then, it initializes basic particle properties (physical position, Particle ID, and placeholder Cell IDs) by calling InitializeParticleBasicProperties. This call uses the provided rand_logic_i/j/k RNGs, which must be pre-initialized for [0,1). The rand_phys_x/y/z RNGs (physically bounded) are passed but may not be used by InitializeParticleBasicProperties for position setting if all initialization paths use logical-to-physical mapping. Finally, it calls helper functions to initialize other registered swarm fields like "velocity", "weight", and "Psi" (scalar) to default values.

Parameters
[in,out]userPointer to the UserCtx structure.
[in]particlesPerProcessNumber of particles assigned to this MPI process.
[in]rand_phys_xRNG for physical x-coordinates (from InitializeRandomGenerators).
[in]rand_phys_yRNG for physical y-coordinates (from InitializeRandomGenerators).
[in]rand_phys_zRNG for physical z-coordinates (from InitializeRandomGenerators).
[in]rand_logic_iRNG for i-logical dimension tasks [0,1) (from InitializeLogicalSpaceRNGs).
[in]rand_logic_jRNG for j-logical dimension tasks [0,1) (from InitializeLogicalSpaceRNGs).
[in]rand_logic_kRNG for k-logical dimension tasks [0,1) (from InitializeLogicalSpaceRNGs).
[in]bboxlistArray of BoundingBox structures (potentially unused by IPBP).
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 606 of file ParticleSwarm.c.

615 {
616 PetscErrorCode ierr;
617 PetscFunctionBeginUser;
618
619 SimCtx *simCtx = user->simCtx;
620
621 // --- 0. Input Validation ---
622 if (!user || !bboxlist || !rand_logic_i || !rand_logic_j || !rand_logic_k || !rand_phys_x || !rand_phys_y || !rand_phys_z) {
623 // Check all RNGs now as they are passed in
624 LOG_ALLOW(GLOBAL, LOG_ERROR, "AssignInitialPropertiesToSwarm - Null user, bboxlist, or RNG pointer.\n");
625 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "AssignInitialPropertiesToSwarm - Null input detected.");
626 }
627
628 LOG_ALLOW(GLOBAL, LOG_INFO, "AssignInitialPropertiesToSwarm - Initializing swarm with %d particles per process. Mode: %d.\n",
629 particlesPerProcess, simCtx->ParticleInitialization);
630
631 // --- 1. Parse BCS File for Inlet Information (if Mode 0) ---
632 if (simCtx->ParticleInitialization == 0) {
633 if(user->inletFaceDefined == PETSC_FALSE){
634 LOG_ALLOW(GLOBAL, LOG_ERROR, "AssignInitialPropertiesToSwarm - ParticleInitialization Mode 0 (Surface Init) selected, but no INLET face was identified from bcs.dat. Cannot proceed.\n");
635 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "ParticleInitialization Mode 0 requires an INLET face to be defined in bcs.dat.");
636 }else{
637 LOG_ALLOW(GLOBAL, LOG_INFO, "AssignInitialPropertiesToSwarm - After ParseBCSFileForInlet, identifiedInletBCFace = %d\n", user->identifiedInletBCFace);
638 }
639 }
640
641 // --- 2. Initialize Basic Particle Properties (Position, PID, Cell IDs placeholder) ---
642 // The rand_logic_i/j/k are now passed directly.
643 // The rand_phys_x/y/z are passed but InitializeParticleBasicProperties (refactored version)
644 // will not use them for setting positions if all its paths use logical-to-physical mapping.
645 LOG_ALLOW(LOCAL, LOG_DEBUG, "AssignInitialPropertiesToSwarm - Calling InitializeParticleBasicProperties.\n");
646 ierr = InitializeParticleBasicProperties(user, particlesPerProcess,
647 rand_logic_i, rand_logic_j, rand_logic_k,
648 bboxlist); // bboxlist passed along
649 CHKERRQ(ierr);
650 LOG_ALLOW(LOCAL, LOG_INFO, "AssignInitialPropertiesToSwarm - Successfully initialized basic particle properties.\n");
651
652 // Note: The logical RNGs (rand_logic_i/j/k) are NOT destroyed here.
653 // They were created externally (e.g., by InitializeLogicalSpaceRNGs) and
654 // should be destroyed externally (e.g., in FinalizeSwarmSetup).
655 // Same for rand_phys_x/y/z.
656
657 // --- 3. Initialize Other Swarm Fields (Velocity, Weight, Pressure, etc.) ---
658 LOG_ALLOW(LOCAL, LOG_DEBUG, "AssignInitialPropertiesToSwarm - Initializing 'velocity' field.\n");
659 ierr = AssignInitialFieldToSwarm(user, "velocity", 3); CHKERRQ(ierr);
660 LOG_ALLOW(LOCAL, LOG_INFO, "AssignInitialPropertiesToSwarm - 'velocity' field initialization complete.\n");
661
662 LOG_ALLOW(LOCAL, LOG_DEBUG, "AssignInitialPropertiesToSwarm - Initializing 'weight' field.\n");
663 ierr = AssignInitialFieldToSwarm(user, "weight", 3); CHKERRQ(ierr); // Assuming weight is vec3
664 LOG_ALLOW(LOCAL, LOG_INFO, "AssignInitialPropertiesToSwarm - 'weight' field initialization complete.\n");
665
666 LOG_ALLOW(LOCAL, LOG_DEBUG, "AssignInitialPropertiesToSwarm - Initializing 'P' (Pressure) field.\n");
667 ierr = AssignInitialFieldToSwarm(user, "Psi", 1); CHKERRQ(ierr);
668 LOG_ALLOW(LOCAL, LOG_INFO, "AssignInitialPropertiesToSwarm - 'P' field initialization complete.\n");
669
670 LOG_ALLOW(GLOBAL, LOG_INFO, "AssignInitialPropertiesToSwarm - Successfully completed all swarm property initialization.\n");
671
672 PetscFunctionReturn(0);
673 }
static PetscErrorCode AssignInitialFieldToSwarm(UserCtx *user, const char *fieldName, PetscInt fieldDim)
Initializes a generic swarm field with point-level updates.
static PetscErrorCode InitializeParticleBasicProperties(UserCtx *user, PetscInt particlesPerProcess, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k, BoundingBox *bboxlist)
Initializes basic properties for particles on the local process.
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
PetscBool inletFaceDefined
Definition variables.h:649
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DistributeParticles()

PetscErrorCode DistributeParticles ( PetscInt  numParticles,
PetscMPIInt  rank,
PetscMPIInt  size,
PetscInt *  particlesPerProcess,
PetscInt *  remainder 
)

Distributes particles evenly across MPI processes, handling any remainders.

This function calculates the number of particles each MPI process should handle, distributing the remainder particles to the first few ranks if necessary.

Parameters
[in]numParticlesTotal number of particles to create across all MPI processes.
[in]rankMPI rank of the current process.
[in]sizeTotal number of MPI processes.
[out]particlesPerProcessNumber of particles assigned to the current MPI process.
[out]remainderRemainder particles when dividing numParticles by size.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 689 of file ParticleSwarm.c.

689 {
690
691 // Calculate the base number of particles per process
692 *particlesPerProcess = numParticles / size;
693 *remainder = numParticles % size;
694
695 // Distribute the remainder particles to the first 'remainder' ranks
696 if (rank < *remainder) {
697 *particlesPerProcess += 1;
698 LOG_ALLOW_SYNC(GLOBAL,LOG_INFO,"DistributeParticles - Rank %d receives an extra particle. Total: %d\n", rank, *particlesPerProcess);
699 } else {
700 LOG_ALLOW_SYNC(GLOBAL,LOG_INFO, "DistributeParticles - Rank %d receives %d particles.\n", rank, *particlesPerProcess);
701 }
702
703 return 0;
704 }
Here is the caller graph for this function:

◆ FinalizeSwarmSetup()

PetscErrorCode FinalizeSwarmSetup ( PetscRandom *  randx,
PetscRandom *  randy,
PetscRandom *  randz,
PetscRandom *  rand_logic_i,
PetscRandom *  rand_logic_j,
PetscRandom *  rand_logic_k 
)

Finalizes the swarm setup by destroying random generators and logging completion.

This function cleans up resources by destroying random number generators and LOG_ALLOWs the completion of swarm setup.

Parameters
[in]randxRandom number generator for the x-coordinate.
[in]randyRandom number generator for the y-coordinate.
[in]randzRandom number generator for the z-coordinate.
[in]rand_logic_iRandom number generator for the xi-coordinate.
[in]rand_logic_jRandom number generator for the eta-coordinate.
[in]rand_logic_kRandom number generator for the zeta-coordinate.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 720 of file ParticleSwarm.c.

720 {
721 PetscErrorCode ierr; // Error code for PETSc functions
722 PetscInt ParticleInitialization;
723
724 ierr = PetscOptionsGetInt(NULL, NULL, "-pinit", &ParticleInitialization, NULL); CHKERRQ(ierr);
725
726 // Destroy random number generators to free resources
727 // Physical space
728 ierr = PetscRandomDestroy(randx); CHKERRQ(ierr);
729 ierr = PetscRandomDestroy(randy); CHKERRQ(ierr);
730 ierr = PetscRandomDestroy(randz); CHKERRQ(ierr);
731
732 // Logical space
733 ierr = PetscRandomDestroy(rand_logic_i); CHKERRQ(ierr);
734 ierr = PetscRandomDestroy(rand_logic_j); CHKERRQ(ierr);
735 ierr = PetscRandomDestroy(rand_logic_k); CHKERRQ(ierr);
736
737 LOG_ALLOW(LOCAL,LOG_DEBUG,"FinalizeSwarmSetup - Destroyed all random number generators.\n");
738
739 return 0;
740 }
Here is the caller graph for this function:

◆ CreateParticleSwarm()

PetscErrorCode CreateParticleSwarm ( UserCtx user,
PetscInt  numParticles,
PetscInt *  particlesPerProcess,
BoundingBox bboxlist 
)

Creates and initializes a Particle Swarm.

This function sets up a DMSwarm within the provided UserCtx structure, initializes particle fields, and distributes particles across MPI processes. It ensures that the number of particles is evenly divided among the available MPI ranks. If the total number of particles isn't divisible by the number of processes, the remainder is distributed to the first few ranks.

Parameters
[in,out]userPointer to the UserCtx structure containing the simulation context.
[in]numParticlesTotal number of particles to create across all MPI processes.
[in]bboxlistPointer to an array of BoundingBox structures, one per rank.
[in]particlesPerProcess
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.
Note
  • Ensure that numParticles is a positive integer.
  • The control.dat file should contain necessary PETSc options.
  • The bboxlist array should be properly populated before calling this function.

Definition at line 764 of file ParticleSwarm.c.

764 {
765 PetscErrorCode ierr; // PETSc error handling variable
766 PetscMPIInt rank, size; // Variables to store MPI rank and size
767 PetscInt remainder = 0; // Remainder of particles after division
768
769 // Validate input parameters
770 if (numParticles <= 0) {
771 LOG_ALLOW(GLOBAL,LOG_DEBUG, "CreateParticleSwarm - Number of particles must be positive. Given: %d\n", numParticles);
772 return PETSC_ERR_ARG_OUTOFRANGE;
773 }
774
775 // Insert PETSc options from "control.dat" into the PETSc options database
776 // ierr = PetscOptionsInsertFile(PETSC_COMM_WORLD, NULL, "control.dat", PETSC_TRUE); CHKERRQ(ierr);
777 // LOG_ALLOW(LOCAL,LOG_DEBUG,"CreateParticleSwarm - Inserted options from control.dat\n");
778
779 LOG_ALLOW_SYNC(GLOBAL,LOG_DEBUG, "CreateParticleSwarm - Domain dimensions: Min_X=%.2f, Max_X=%.2f,Min_Y=%.2f, Max_Y=%.2f,Min_Z=%.2f, Max_Z=%.2f \n",
780 user->Min_X,user->Max_X,user->Min_Y,user->Max_Y, user->Min_Z,user->Max_Z);
781
782 // Retrieve MPI rank and size
783 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
784 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
785 LOG_ALLOW(GLOBAL,LOG_INFO, "CreateParticleSwarm - Rank %d out of %d processes.\n", rank, size);
786
787 // Distribute particles among MPI processes
788 ierr = DistributeParticles(numParticles, rank, size, particlesPerProcess, &remainder); CHKERRQ(ierr);
789
790 // Initialize the DMSwarm - creates the swarm, sets the type and dimension
791 ierr = InitializeSwarm(user); CHKERRQ(ierr);
792
793 if (user->da) {
794 ierr = DMSwarmSetCellDM(user->swarm, user->da); CHKERRQ(ierr);
795 LOG_ALLOW(LOCAL,LOG_INFO,"CreateParticleSwarm - Associated DMSwarm with Cell DM (user->da).\n");
796 } else {
797 // If user->da is essential for your simulation logic with particles, this should be a fatal error.
798 LOG_ALLOW(GLOBAL, LOG_WARNING, "CreateParticleSwarm - user->da (Cell DM for Swarm) is NULL. Cell-based swarm operations might fail.\n");
799 // SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "CreateParticleSwarm - user->da (Cell DM) is NULL but required.");
800 }
801
802 // Register particle fields (position, velocity, CellID, weight, etc.)
803 ierr = RegisterParticleFields(user->swarm); CHKERRQ(ierr);
804
805 // Set the local number of particles for this rank and additional buffer for particle migration
806 ierr = DMSwarmSetLocalSizes(user->swarm, *particlesPerProcess, numParticles); CHKERRQ(ierr);
807 LOG_ALLOW(GLOBAL,LOG_INFO, "CreateParticleSwarm - Set local swarm size: %d particles.\n", *particlesPerProcess);
808
809 // Optionally, LOG_ALLOW detailed DM info in debug mode
810 if (get_log_level() == LOG_DEBUG && is_function_allowed(__func__)) {
811 LOG_ALLOW(LOCAL,LOG_DEBUG,"CreateParticleSwarm - Viewing DMSwarm:\n");
812 ierr = DMView(user->swarm, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
813 }
814
815 LOG_ALLOW(LOCAL,LOG_INFO, "CreateParticleSwarm - Particle swarm creation and initialization complete.\n");
816
817 return 0;
818 }
PetscErrorCode DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
Distributes particles evenly across MPI processes, handling any remainders.
PetscErrorCode InitializeSwarm(UserCtx *user)
Initializes the DMSwarm object within the UserCtx structure.
PetscErrorCode RegisterParticleFields(DM swarm)
Registers necessary particle fields within the DMSwarm.
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:159
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:49
PetscReal Min_X
Definition variables.h:640
PetscReal Max_Y
Definition variables.h:640
PetscReal Min_Z
Definition variables.h:640
PetscReal Max_X
Definition variables.h:640
PetscReal Min_Y
Definition variables.h:640
PetscReal Max_Z
Definition variables.h:640
Here is the call graph for this function:
Here is the caller graph for this function:

◆ UnpackSwarmFields()

PetscErrorCode UnpackSwarmFields ( PetscInt  i,
const PetscInt64 *  PIDs,
const PetscReal *  weights,
const PetscReal *  positions,
const PetscInt *  cellIndices,
PetscReal *  velocities,
PetscInt *  LocStatus,
Particle particle 
)

Initializes a Particle struct with data from DMSwarm fields.

This helper function populates a Particle structure using data retrieved from DMSwarm fields.

Parameters
[in]iIndex of the particle in the DMSwarm.
[in]PIDsPointer to the array of particle IDs.
[in]weightsPointer to the array of particle weights.
[in]positionsPointer to the array of particle positions.
[in]cellIndicesPointer to the array of particle cell indices.
[in]velocitiesPointer to the array of particle velocities.
[in]LocStatusPointer to the array of cell location status indicators.
[out]particlePointer to the Particle struct to initialize.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 837 of file ParticleSwarm.c.

839 {
840 PetscFunctionBeginUser;
841 PetscMPIInt rank;
842 PetscErrorCode ierr;
843
844 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
845
846 if (particle == NULL) {
847 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Output Particle pointer is NULL. \n");
848 }
849
850 // logging the start of particle initialization
851 LOG_ALLOW(LOCAL,LOG_INFO, "[Rank %d]Unpacking Particle [%d] with PID: %ld.\n",rank, i, PIDs[i]);
852
853 // Initialize PID
854 particle->PID = PIDs[i];
855 LOG_ALLOW(LOCAL,LOG_DEBUG, "[Rank %d]Particle [%d] PID set to: %ld.\n", rank,i, particle->PID);
856
857 // Initialize weights
858 particle->weights.x = weights[3 * i];
859 particle->weights.y = weights[3 * i + 1];
860 particle->weights.z = weights[3 * i + 2];
861 LOG_ALLOW(LOCAL,LOG_DEBUG, "[Rank %d]Particle [%d] weights set to: (%.6f, %.6f, %.6f).\n",
862 rank,i, particle->weights.x, particle->weights.y, particle->weights.z);
863
864 // Initialize locations
865 particle->loc.x = positions[3 * i];
866 particle->loc.y = positions[3 * i + 1];
867 particle->loc.z = positions[3 * i + 2];
868 LOG_ALLOW(LOCAL,LOG_DEBUG, "[Rank %d]Particle [%d] location set to: (%.6f, %.6f, %.6f).\n",
869 rank,i, particle->loc.x, particle->loc.y, particle->loc.z);
870
871 // Initialize velocities (assuming default zero; modify if necessary)
872 particle->vel.x = velocities[3 * i];
873 particle->vel.y = velocities[3 * i + 1];
874 particle->vel.z = velocities[3 * i + 2];
875 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d]Particle [%d] velocities unpacked to: [%.6f,%.6f,%.6f].\n",rank, i,particle->vel.x,particle->vel.y,particle->vel.z);
876
877 // Initialize cell indices
878 particle->cell[0] = cellIndices[3 * i];
879 particle->cell[1] = cellIndices[3 * i + 1];
880 particle->cell[2] = cellIndices[3 * i + 2];
881 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d]Particle [%d] cell indices set to: [%d, %d, %d].\n",rank,i, particle->cell[0], particle->cell[1], particle->cell[2]);
882
883 particle->location_status = (ParticleLocationStatus)LocStatus[i];
884 LOG_ALLOW(LOCAL,LOG_DEBUG, "[Rank %d]Particle [%d] Status set to: %d.\n",rank, i, particle->location_status);
885
886 // The destination_rank is only set by the location search, not read from the swarm,
887 // so we initialize it to a known invalid state.
888 particle->destination_rank = MPI_PROC_NULL;
889
890 // logging the completion of particle initialization
891 LOG_ALLOW(LOCAL,LOG_INFO,"[Rank %d]Completed initialization of Particle [%d]. \n", rank,i);
892
893 PetscFunctionReturn(0);
894 }
Cmpnts vel
Definition variables.h:168
PetscInt cell[3]
Definition variables.h:166
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Definition variables.h:134
Cmpnts loc
Definition variables.h:167
PetscMPIInt destination_rank
Definition variables.h:171
ParticleLocationStatus location_status
Definition variables.h:170
Cmpnts weights
Definition variables.h:169
PetscInt64 PID
Definition variables.h:165
Here is the caller graph for this function:

◆ UpdateSwarmFields()

PetscErrorCode UpdateSwarmFields ( PetscInt  i,
const Particle particle,
PetscReal *  weights,
PetscInt *  cellIndices,
PetscInt *  status_field 
)

Updates DMSwarm fields with data from a Particle struct.

This helper function writes back the modified Particle data to the corresponding DMSwarm fields.

Parameters
[in]iIndex of the particle in the DMSwarm.
[in]particlePointer to the Particle struct containing updated data.
[in,out]weightsPointer to the array of particle weights.
[in,out]cellIndicesPointer to the array of particle cell indices.
[in,out]LocStatusPointer to the array of cell location status indicators.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 909 of file ParticleSwarm.c.

910 {
911 PetscFunctionBeginUser;
912
913 if (particle == NULL) {
914 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input Particle pointer is NULL.\n");
915 }
916
917 // logging the start of swarm fields update
918 LOG_ALLOW(LOCAL,LOG_INFO,"Updating DMSwarm fields for Particle [%d].\n", i);
919
920 // Update weights
921 weights[3 * i] = particle->weights.x;
922 weights[3 * i + 1] = particle->weights.y;
923 weights[3 * i + 2] = particle->weights.z;
924 LOG_ALLOW(LOCAL,LOG_DEBUG,"Updated weights for Particle [%d]: (%.6f, %.6f, %.6f).\n",
925 i, weights[3 * i], weights[3 * i + 1], weights[3 * i + 2]);
926
927 // Update cell indices
928 cellIndices[3 * i] = particle->cell[0];
929 cellIndices[3 * i + 1] = particle->cell[1];
930 cellIndices[3 * i + 2] = particle->cell[2];
931 LOG_ALLOW(LOCAL,LOG_DEBUG, "Updated cell indices for Particle [%d]: [%d, %d, %d].\n",
932 i, cellIndices[3 * i], cellIndices[3 * i + 1], cellIndices[3 * i + 2]);
933
934 status_field[i] = particle->location_status;
935 LOG_ALLOW(LOCAL,LOG_DEBUG, "Updated location status for Particle [%d]: [%d].\n",
936 i, status_field[i]);
937
938 // logging the completion of swarm fields update
939 LOG_ALLOW(LOCAL,LOG_INFO,"Completed updating DMSwarm fields for Particle [%d].\n", i);
940
941 PetscFunctionReturn(0);
942 }
Here is the caller graph for this function:

◆ IsParticleInsideBoundingBox()

PetscBool IsParticleInsideBoundingBox ( const BoundingBox bbox,
const Particle particle 
)

Checks if a particle's location is within a specified bounding box.

This function determines whether the given particle's location lies inside the provided bounding box. It performs an axis-aligned bounding box (AABB) check by comparing the particle's coordinates to the minimum and maximum coordinates of the bounding box in each dimension (x, y, z).

logging statements are included to provide detailed information about the function's execution.

Parameters
[in]bboxPointer to the BoundingBox structure containing minimum and maximum coordinates.
[in]particlePointer to the Particle structure containing the particle's location and identifier.
Returns
PetscBool Returns PETSC_TRUE if the particle is inside the bounding box, PETSC_FALSE otherwise.
Note
  • The function assumes that the bbox and particle pointers are valid and non-NULL.
  • The function includes logging statements that start with the function name.
  • The LOG_ALLOW_SCOPE variable is used to distinguish between GLOBAL and LOCAL LOG_ALLOW outputs.
  • Be cautious when logging in performance-critical code sections, especially if the function is called frequently.

Definition at line 964 of file ParticleSwarm.c.

965 {
966 // Function name for logging purposes
967 const char *funcName = "IsParticleInsideBoundingBox";
968
969 // Validate input pointers
970 if (!bbox) {
971 // LOG_ALLOW error message and return PETSC_FALSE
972 LOG_ALLOW(LOCAL,LOG_ERROR, "%s: Error - 'bbox' pointer is NULL.", funcName);
973 return PETSC_FALSE;
974 }
975 if (!particle) {
976 LOG_ALLOW(LOCAL,LOG_ERROR,"%s: Error - 'particle' pointer is NULL.", funcName);
977 return PETSC_FALSE;
978 }
979
980 // Extract particle location and bounding box coordinates
981 const Cmpnts loc = particle->loc;
982 const Cmpnts min_coords = bbox->min_coords;
983 const Cmpnts max_coords = bbox->max_coords;
984
985 // LOG_ALLOW the particle location and bounding box coordinates for debugging
986 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "%s: Particle PID %ld location: (%.6f, %.6f, %.6f).\n", funcName, particle->PID, loc.x, loc.y, loc.z);
987 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "%s: BoundingBox min_coords: (%.6f, %.6f, %.6f), max_coords: (%.6f, %.6f, %.6f).\n",
988 funcName, min_coords.x, min_coords.y, min_coords.z, max_coords.x, max_coords.y, max_coords.z);
989
990 // Check if the particle's location is within the bounding box
991 if ((loc.x >= min_coords.x && loc.x <= max_coords.x) &&
992 (loc.y >= min_coords.y && loc.y <= max_coords.y) &&
993 (loc.z >= min_coords.z && loc.z <= max_coords.z)) {
994 // Particle is inside the bounding box
995 LOG_ALLOW_SYNC(LOCAL,LOG_DEBUG, "%s: Particle PID %ld is inside the bounding box.\n", funcName, particle->PID);
996 return PETSC_TRUE;
997 }
998
999 // Particle is outside the bounding box
1000 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG,"%s: Particle PID %ld is outside the bounding box.\n", funcName, particle->PID);
1001 return PETSC_FALSE;
1002 }

◆ UpdateParticleWeights()

PetscErrorCode UpdateParticleWeights ( PetscReal *  d,
Particle particle 
)

Updates a particle's interpolation weights based on distances to cell faces.

This function computes interpolation weights using distances to the six cell faces (d) and updates the weight field of the provided particle.

Parameters
[in]dPointer to an array of distances to the six cell faces.
[out]particlePointer to the Particle structure whose weights are to be updated.
Returns
PetscErrorCode Returns 0 on success, or a non-zero error code on failure.

Definition at line 1015 of file ParticleSwarm.c.

1015 {
1016
1017 // Validate input pointers
1018 if (!d || !particle) {
1019 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
1020 "UpdateParticleWeights - Null pointer argument (d or particle).");
1021 }
1022
1023
1024 // Validate distances
1025 for (PetscInt i = LEFT; i < NUM_FACES; i++) {
1028 "UpdateParticleWeights - face distance d[%d] = %f <= %f; "
1029 "clamping to 1e-14 to avoid zero/negative.\n",
1030 i, (double)d[i], INTERPOLATION_DISTANCE_TOLERANCE);
1032 }
1033 }
1034
1035 // LOG_ALLOW the input distances
1037 "UpdateParticleWeights - Calculating weights with distances: "
1038 "[LEFT=%f, RIGHT=%f, BOTTOM=%f, TOP=%f, FRONT=%f, BACK=%f].\n",
1039 d[LEFT], d[RIGHT], d[BOTTOM], d[TOP], d[FRONT], d[BACK]);
1040
1041 // Compute and update the particle's weights
1042 particle->weights.x = d[LEFT] / (d[LEFT] + d[RIGHT]);
1043 particle->weights.y = d[BOTTOM] / (d[BOTTOM] + d[TOP]);
1044 particle->weights.z = d[BACK] / (d[FRONT] + d[BACK]);
1045
1046 // LOG_ALLOW the updated weights
1048 "UpdateParticleWeights - Updated particle weights: x=%f, y=%f, z=%f.\n",
1049 particle->weights.x, particle->weights.y, particle->weights.z);
1050
1051 return 0;
1052 }
#define INTERPOLATION_DISTANCE_TOLERANCE
@ TOP
Definition variables.h:144
@ FRONT
Definition variables.h:144
@ BOTTOM
Definition variables.h:144
@ BACK
Definition variables.h:144
@ LEFT
Definition variables.h:144
@ NUM_FACES
Definition variables.h:144
@ RIGHT
Definition variables.h:144
Here is the caller graph for this function:

◆ PrepareLoadedSwarmForRelocation()

PetscErrorCode PrepareLoadedSwarmForRelocation ( UserCtx user)

Resets the location-dependent state of a loaded swarm to force relocation.

This function is a critical part of the simulation restart procedure. It must be called immediately after ReadAllSwarmFields has populated a swarm from restart files. Its purpose is to invalidate the "location" state of the loaded particles, ensuring that the LocateAllParticlesInGrid_TEST orchestrator performs a fresh, comprehensive search for every particle based on its loaded position.

It does this by performing two actions on every locally-owned particle:

  1. It resets the DMSwarm_CellID field to a sentinel value of (-1, -1, -1). This invalidates any cell index that might have been loaded or defaulted to 0.
  2. It sets the DMSwarm_location_status field to NEEDS_LOCATION.

This guarantees that the location logic will not mistakenly use a stale cell index from a previous run and will instead use the robust "Guess -> Verify" strategy appropriate for particles with unknown locations.

Parameters
[in,out]userPointer to the UserCtx structure which contains the DMSwarm object that has just been loaded with data from restart files.
Returns
PetscErrorCode 0 on success, or a non-zero PETSc error code if field access fails.

Definition at line 1078 of file ParticleSwarm.c.

1079 {
1080 PetscErrorCode ierr;
1081 DM swarm;
1082 PetscInt n_local;
1083 PetscInt *cell_p; // Pointer to the raw data for the CellID field
1084 PetscInt *status_p; // Pointer to the raw data for the location_status field
1085 PetscInt64 *PIDs; // Pointer to the raw data for the Particle ID field.
1086 PetscMPIInt rank,size;
1087
1088 PetscFunctionBeginUser;
1089
1090 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
1091 ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size); CHKERRQ(ierr);
1092
1093 SimCtx *simCtx = user->simCtx;
1094
1095 // --- 1. Input Validation and Setup ---
1096 if (!user || !user->swarm) {
1097 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx or its DMSwarm is NULL in PrepareLoadedSwarmForRelocation.");
1098 }
1099 swarm = user->swarm;
1100
1101 // Get the number of particles on this MPI rank.
1102 ierr = DMSwarmGetLocalSize(swarm, &n_local); CHKERRQ(ierr);
1103
1104 // If there are no local particles, there is nothing to do.
1105 if (n_local == 0) {
1106 PetscFunctionReturn(0);
1107 }
1108
1109
1110 LOG_ALLOW(GLOBAL, LOG_INFO, "Preparing %d loaded particles for relocation by resetting their CellID and Status.\n", n_local);
1111
1112 // --- 2. Get Writable Access to Swarm Fields ---
1113 // This provides direct pointers to the underlying data arrays for the fields.
1114 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cell_p); CHKERRQ(ierr);
1115 ierr = DMSwarmGetField(swarm, "DMSwarm_location_status", NULL, NULL, (void**)&status_p); CHKERRQ(ierr);
1116 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&PIDs); CHKERRQ(ierr); CHKERRQ(ierr);
1117
1118 // --- 3. Determine Starting Global PID for this Rank ---
1119 PetscInt particles_per_rank_ideal = simCtx->np / size; // Assumes user->size is PETSC_COMM_WORLD size
1120 PetscInt remainder_particles = simCtx->np % size;
1121 PetscInt base_pid_for_rank = rank * particles_per_rank_ideal + PetscMin(rank, remainder_particles);
1122 // This calculation must match how particlesPerProcess was determined (e.g., in DistributeParticles).
1123
1124 // --- 4. Loop Through All Local Particles and Reset State ---
1125 for (PetscInt p = 0; p < n_local; ++p) {
1126
1127
1128 // Reset the 3 components of the cell index vector.
1129 cell_p[3*p + 0] = -1;
1130 cell_p[3*p + 1] = -1;
1131 cell_p[3*p + 2] = -1;
1132
1133 // Reset the status to ensure it will be processed by the location algorithm.
1135
1136 //set the PID for each particle
1137 PIDs[p] = (PetscInt64)base_pid_for_rank + p;
1138 }
1139
1140 // --- 4. Restore Fields ---
1141 // This returns control of the data arrays back to the DMSwarm. It is a mandatory
1142 // step to ensure data consistency and prevent memory issues.
1143 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cell_p); CHKERRQ(ierr);
1144 ierr = DMSwarmRestoreField(swarm, "DMSwarm_location_status", NULL, NULL, (void**)&status_p); CHKERRQ(ierr);
1145 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&PIDs); CHKERRQ(ierr); CHKERRQ(ierr);
1146
1147 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Successfully reset location state for all loaded particles.\n");
1148
1149 PetscFunctionReturn(0);
1150 }
Here is the caller graph for this function:

◆ InitializeParticleSwarm()

PetscErrorCode InitializeParticleSwarm ( SimCtx simCtx)

Perform particle swarm initialization, particle-grid interaction, and related operations.

This function handles the following tasks:

  1. Initializes the particle swarm using the provided bounding box list (bboxlist) to determine initial placement if ParticleInitialization is 0.
  2. Locates particles within the computational grid.
  3. Updates particle positions based on grid interactions (if such logic exists elsewhere in the code).
  4. Interpolates particle velocities from grid points using trilinear interpolation.
Parameters
[in,out]userPointer to the UserCtx structure containing grid and particle swarm information.
[in]npNumber of particles to initialize in the swarm.
[in]bboxlistPointer to an array of BoundingBox structures, one per MPI rank.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.
Note
  • Ensure that np (number of particles) is positive.
  • The bboxlist array must be correctly computed and passed in before calling this function.
  • If ParticleInitialization == 0, particles will be placed at the midpoint of the local bounding box.

Definition at line 1174 of file ParticleSwarm.c.

1175 {
1176
1177 PetscErrorCode ierr;
1178 PetscInt particlesPerProcess = 0; // Number of particles assigned to the local MPI process.
1179 PetscRandom randx,randy,randz; // Random number generators[x,y,z]. (used if ParticleInitialization==1).
1180 PetscRandom rand_logic_i, rand_logic_j,rand_logic_k; // RNGs for Logical space.
1181 PetscInt start_step = simCtx->StartStep;
1182 PetscInt np = simCtx->np;
1183 BoundingBox *bboxlist = simCtx->bboxlist;
1184 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1185
1186 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting particle swarm Initialization with %d particles.\n", np);
1187
1188 // Step 1: Create and initialize the particle swarm
1189 // Here we pass in the bboxlist, which will be used by CreateParticleSwarm() and subsequently
1190 // by AssignInitialProperties() to position particles if ParticleInitialization == 0.
1191 LOG_ALLOW(GLOBAL, LOG_INFO, "Creating particle swarm.\n");
1192 ierr = CreateParticleSwarm(user, np, &particlesPerProcess,bboxlist); CHKERRQ(ierr);
1193 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle swarm created successfully.\n");
1194
1195 ierr = PetscOptionsGetInt(NULL, NULL, "-rstart", &start_step, NULL); CHKERRQ(ierr);
1196
1197 if(start_step == 0){
1198
1199 // Create the RNGs
1200 LOG_ALLOW(LOCAL, LOG_DEBUG, "Initializing physical space RNGs.\n");
1201 ierr = InitializeRandomGenerators(user, &randx, &randy, &randz); CHKERRQ(ierr);
1202
1203 LOG_ALLOW(LOCAL, LOG_DEBUG, "Initializing logical space RNGs [0,1).\n");
1204 ierr = InitializeLogicalSpaceRNGs(&rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1205 // Assign initial properties to particles
1206 // The bboxlist array is passed here so that if ParticleInitialization == 0,
1207 // particles can be placed at the midpoint of the local bounding box corresponding to this rank.
1208 ierr = AssignInitialPropertiesToSwarm(user, particlesPerProcess, &randx, &randy, &randz, &rand_logic_i,&rand_logic_j,&rand_logic_k,bboxlist); CHKERRQ(ierr);
1209 // Finalize swarm setup by destroying RNGs if ParticleInitialization == 1
1210 ierr = FinalizeSwarmSetup(&randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1211
1212 // Ensure all ranks complete before proceeding
1213 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, " Particles generated & initialized.\n");
1214 }
1215
1216 else if (start_step > 0){
1217
1218 LOG_ALLOW(LOCAL,LOG_DEBUG," Particle Swarm status being set at restart [Step %d].\n",start_step);
1219
1220 ierr = PreCheckAndResizeSwarm(user,start_step,"dat");
1221
1222 // --- Read Particle Data (EVERY timestep) ---
1223 // ReadAllSwarmFields should read position and velocity for timestep 'ti'
1224
1225 ierr = ReadAllSwarmFields(user, start_step);
1226 if (ierr) {
1227 // Check if the error was specifically a file open error (missing file)
1228 if (ierr == PETSC_ERR_FILE_OPEN) {
1229 LOG_ALLOW(GLOBAL, LOG_WARNING, "Missing particle data file(s) for timestep %d. Skipping VTK output for this step.\n",(PetscInt)user->simCtx->step );
1230 } else {
1231 LOG_ALLOW(GLOBAL, LOG_ERROR, "Failed to read swarm fields for timestep %d (Error code: %d). Skipping VTK output for this step.\n",(PetscInt)user->simCtx->step , ierr);
1232 }
1233 }
1234
1235 // Ensure all the swarm fields not read from file are initialized.
1237
1238 // Ensure all ranks complete before proceeding
1239 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, " Particles generated & initialized.\n");
1240
1241
1242 }
1243 return 0;
1244 }
PetscErrorCode PreCheckAndResizeSwarm(UserCtx *user, PetscInt ti, const char *ext)
Checks particle count in the reference file and resizes the swarm if needed.
PetscErrorCode CreateParticleSwarm(UserCtx *user, PetscInt numParticles, PetscInt *particlesPerProcess, BoundingBox *bboxlist)
Creates and initializes a Particle Swarm.
PetscErrorCode FinalizeSwarmSetup(PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
Finalizes the swarm setup by destroying random generators and logging completion.
PetscErrorCode InitializeRandomGenerators(UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
Initializes random number generators for assigning particle properties.
PetscErrorCode PrepareLoadedSwarmForRelocation(UserCtx *user)
Resets the location-dependent state of a loaded swarm to force relocation.
PetscErrorCode InitializeLogicalSpaceRNGs(PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
Initializes random number generators for logical space operations [0.0, 1.0).
PetscErrorCode 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)
Initializes all particle properties in the swarm.
PetscErrorCode ReadAllSwarmFields(UserCtx *user, PetscInt ti)
Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.
Definition io.c:1100
UserCtx * user
Definition variables.h:418
UserMG usermg
Definition variables.h:599
PetscInt StartStep
Definition variables.h:523
BoundingBox * bboxlist
Definition variables.h:588
PetscInt mglevels
Definition variables.h:425
PetscInt step
Definition variables.h:521
MGCtx * mgctx
Definition variables.h:428
Defines a 3D axis-aligned bounding box.
Definition variables.h:153
User-defined context containing data specific to a single computational grid level.
Definition variables.h:630
Here is the call graph for this function:
Here is the caller graph for this function: