5#define INTERPOLATION_DISTANCE_TOLERANCE 1.0e-14
8#define __FUNCT__ "InitializeSwarm"
18 PetscFunctionBeginUser;
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);
28 PetscFunctionReturn(0);
32#define __FUNCT__ "RegisterSwarmField"
38PetscErrorCode
RegisterSwarmField(DM swarm,
const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
41 PetscFunctionBeginUser;
43 ierr = DMSwarmRegisterPetscDatatypeField(swarm, fieldName, fieldDim, dtype); CHKERRQ(ierr);
46 fieldName, fieldDim, PetscDataTypes[dtype]);
48 PetscFunctionReturn(0);
52#define __FUNCT__ "RegisterParticleFields"
64 PetscFunctionBeginUser;
77 ierr = DMSwarmFinalizeFieldRegister(swarm); CHKERRQ(ierr);
80 PetscFunctionReturn(0);
84#define __FUNCT__ "DetermineVolumetricInitializationParameters"
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,
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)
96 PetscErrorCode ierr = 0;
99 PetscInt local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k;
100 PetscMPIInt rank_for_logging;
102 PetscFunctionBeginUser;
106 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_for_logging); CHKERRQ(ierr);
108 *can_place_in_volume_out = PETSC_FALSE;
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;
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;
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);
124 if (num_owned_cells_on_rank_i > 0 && num_owned_cells_on_rank_j > 0 && num_owned_cells_on_rank_k > 0) {
125 *can_place_in_volume_out = PETSC_TRUE;
131 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, &r_val); CHKERRQ(ierr);
132 local_owned_cell_idx_i = (PetscInt)(r_val * num_owned_cells_on_rank_i);
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;
138 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, &r_val); CHKERRQ(ierr);
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;
144 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, &r_val); CHKERRQ(ierr);
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;
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);
157 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, xi_metric_logic_out); CHKERRQ(ierr);
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);
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);
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);
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);
179 PetscFunctionReturn(0);
183#define __FUNCT__ "InitializeParticleBasicProperties"
189 PetscInt particlesPerProcess,
190 PetscRandom *rand_logic_i,
191 PetscRandom *rand_logic_j,
192 PetscRandom *rand_logic_k,
197 DM swarm = user->
swarm;
198 PetscReal *positions_field = NULL;
199 PetscInt64 *particleIDs = NULL;
200 PetscInt *cellIDs_petsc = NULL;
201 PetscInt *status_field = NULL;
202 PetscMPIInt rank,size;
203 const Cmpnts ***coor_nodes_local_array;
206 PetscInt xs_gnode_rank, ys_gnode_rank, zs_gnode_rank;
207 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global;
210 PetscBool can_this_rank_service_inlet = PETSC_FALSE;
212 PetscFunctionBeginUser;
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.");
222 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
223 ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size); CHKERRQ(ierr);
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);
234 IM_nodes_global -= 1; JM_nodes_global -= 1; KM_nodes_global -= 1;
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;
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) {
264 PetscInt base_pid_for_rank = 0;
266 PetscInt local_count = particlesPerProcess;
267 ierr = MPI_Exscan(&local_count, &base_pid_for_rank, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
268 if (rank == 0) base_pid_for_rank = 0;
272 for (PetscInt p = 0; p < particlesPerProcess; p++) {
274 PetscInt ci_metric_lnode, cj_metric_lnode, ck_metric_lnode;
275 PetscReal xi_metric_logic, eta_metric_logic, zta_metric_logic;
276 Cmpnts phys_coords = {0.0, 0.0, 0.0};
277 PetscBool particle_placed_by_this_rank = PETSC_FALSE;
280 if (can_this_rank_service_inlet) {
282 IM_nodes_global, JM_nodes_global, KM_nodes_global,
283 rand_logic_i, rand_logic_j, rand_logic_k,
284 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
285 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic); CHKERRQ(ierr);
287 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
288 xi_metric_logic, eta_metric_logic, zta_metric_logic,
289 &phys_coords); CHKERRQ(ierr);
290 particle_placed_by_this_rank = PETSC_TRUE;
296 particle_placed_by_this_rank = PETSC_FALSE;
299 if(can_this_rank_service_inlet) {
300 PetscInt64 particle_global_id = (PetscInt64)(base_pid_for_rank + p);
302 IM_cells_global, JM_cells_global, KM_cells_global,
304 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
305 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
306 &particle_placed_by_this_rank); CHKERRQ(ierr);
307 if(particle_placed_by_this_rank){
309 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
310 xi_metric_logic, eta_metric_logic, zta_metric_logic,
311 &phys_coords); CHKERRQ(ierr);
323 particle_placed_by_this_rank = PETSC_FALSE;
326 PetscBool can_place_volumetrically = PETSC_FALSE;
328 rand_logic_i, rand_logic_j, rand_logic_k,
329 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
330 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
331 &can_place_volumetrically); CHKERRQ(ierr);
332 if(can_place_volumetrically){
334 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
335 xi_metric_logic, eta_metric_logic, zta_metric_logic,
336 &phys_coords); CHKERRQ(ierr);
337 particle_placed_by_this_rank = PETSC_TRUE;
340 "Rank %d: PID %lld (idx %ld) (Volumetric Mode) - DetermineVolumetric... returned false. Default Phys: (%.2f,%.2f,%.2f).\n",
341 rank, (
long long)(base_pid_for_rank + p), (
long)p, phys_coords.
x, phys_coords.
y, phys_coords.
z);
346 phys_coords.
x = simCtx->
psrc_x;
347 phys_coords.
y = simCtx->
psrc_y;
348 phys_coords.
z = simCtx->
psrc_z;
349 particle_placed_by_this_rank = PETSC_TRUE;
351 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
"Unknown ParticleInitialization mode %d.", simCtx->
ParticleInitialization);
355 positions_field[3*p+0] = phys_coords.
x;
356 positions_field[3*p+1] = phys_coords.
y;
357 positions_field[3*p+2] = phys_coords.
z;
359 particleIDs[p] = (PetscInt64)base_pid_for_rank + p;
360 cellIDs_petsc[3*p+0] = -1; cellIDs_petsc[3*p+1] = -1; cellIDs_petsc[3*p+2] = -1;
364 if (particle_placed_by_this_rank) {
366 "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",
368 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
369 xi_metric_logic, eta_metric_logic, zta_metric_logic,
370 phys_coords.
x, phys_coords.
y, phys_coords.
z);
374 "Rank %d: PID %lld (idx %ld) Mode %s NOT placed by this rank's logic. Default Coor: (%.2f,%.2f,%.2f). Relies on migration.\n",
376 phys_coords.
x, phys_coords.
y, phys_coords.
z);
385 ierr = DMDAVecRestoreArrayRead(user->
fda, Coor_local, (
void*)&coor_nodes_local_array); CHKERRQ(ierr);
388 rank, particlesPerProcess);
392 PetscFunctionReturn(0);
396#define __FUNCT__ "InitializeSwarmFieldValue"
401 PetscInt p, PetscReal *fieldData)
403 PetscFunctionBeginUser;
407 PetscCheck(descriptor != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
408 "Particle field descriptor cannot be NULL during initialization.");
409 PetscCheck(fieldData != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
410 "Particle field data cannot be NULL during initialization.");
411 PetscCheck(descriptor->
data_type == PETSC_REAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
412 "Default initialization currently supports only PETSC_REAL particle fields; '%s' uses %s.",
415 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
416 "Particle field '%s' does not use catalog-default initialization.",
419 for (PetscInt d = 0; d < descriptor->
components; ++d) {
424 PetscFunctionReturn(0);
429#define __FUNCT__ "AssignInitialFieldToSwarm"
436 DM swarm = user->
swarm;
437 PetscReal *fieldData = NULL;
440 const char *fieldName = NULL;
442 PetscFunctionBeginUser;
450 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
454 ierr = DMSwarmGetField(swarm, fieldName, NULL, NULL, (
void**)&fieldData); CHKERRQ(ierr);
458 for (PetscInt p = 0; p < nLocal; p++) {
462 for (PetscInt d = 0; d < descriptor->
components; d++) {
463 disp_data[d] = fieldData[descriptor->
components * p + d];
465 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]);
469 ierr = DMSwarmRestoreField(swarm, fieldName, NULL, NULL, (
void**)&fieldData); CHKERRQ(ierr);
475 PetscFunctionReturn(0);
479#define __FUNCT__ "AssignInitialPropertiesToSwarm"
486 PetscInt particlesPerProcess,
487 PetscRandom *rand_phys_x,
488 PetscRandom *rand_phys_y,
489 PetscRandom *rand_phys_z,
490 PetscRandom *rand_logic_i,
491 PetscRandom *rand_logic_j,
492 PetscRandom *rand_logic_k,
496 PetscFunctionBeginUser;
503 if (!user || !bboxlist || !rand_logic_i || !rand_logic_j || !rand_logic_k || !rand_phys_x || !rand_phys_y || !rand_phys_z) {
506 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Null input detected.");
516 LOG_ALLOW(
GLOBAL,
LOG_ERROR,
"Particle Initialization on inlet surface selected, but no INLET face was identified from bcs.dat. Cannot proceed.\n");
517 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
"ParticleInitialization Mode 0 requires an INLET face to be defined in bcs.dat.");
529 rand_logic_i, rand_logic_j, rand_logic_k,
565 PetscFunctionReturn(0);
570#define __FUNCT__ "DistributeParticles"
577PetscErrorCode
DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt* particlesPerProcess, PetscInt* remainder) {
579 PetscFunctionBeginUser;
583 *particlesPerProcess = numParticles / size;
584 *remainder = numParticles % size;
587 if (rank < *remainder) {
588 *particlesPerProcess += 1;
595 PetscFunctionReturn(0);
600#define __FUNCT__ "FinalizeSwarmSetup"
607PetscErrorCode
FinalizeSwarmSetup(PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k) {
609 PetscFunctionBeginUser;
613 ierr = PetscRandomDestroy(randx); CHKERRQ(ierr);
614 ierr = PetscRandomDestroy(randy); CHKERRQ(ierr);
615 ierr = PetscRandomDestroy(randz); CHKERRQ(ierr);
617 ierr = PetscRandomDestroy(rand_logic_i); CHKERRQ(ierr);
618 ierr = PetscRandomDestroy(rand_logic_j); CHKERRQ(ierr);
619 ierr = PetscRandomDestroy(rand_logic_k); CHKERRQ(ierr);
624 PetscFunctionReturn(0);
628#define __FUNCT__ "DistributeParticlesByOwnedCells"
642 PetscMPIInt rank, size;
643 PetscInt start, ni, nj, nk, owned, total = 0, assigned = 0;
644 PetscInt *cells = NULL, *count = NULL;
645 PetscReal *frac = NULL;
647 PetscFunctionBeginUser;
648 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
649 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
653 owned = ni * nj * nk;
654 PetscCall(PetscMalloc3(size, &cells, size, &count, size, &frac));
655 PetscCallMPI(MPI_Allgather(&owned, 1, MPIU_INT, cells, 1, MPIU_INT, PETSC_COMM_WORLD));
656 for (PetscMPIInt r = 0; r < size; ++r) total += cells[r];
657 PetscCheck(total > 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
658 "Volumetric particle seeding found no owned cells on any rank.");
659 for (PetscMPIInt r = 0; r < size; ++r) {
660 const PetscReal share = (PetscReal)numParticles * (PetscReal)cells[r] / (PetscReal)total;
661 count[r] = (PetscInt)PetscFloorReal(share);
662 frac[r] = share - (PetscReal)count[r];
663 assigned += count[r];
665 for (PetscInt extra = numParticles - assigned; extra > 0; --extra) {
666 PetscMPIInt best = 0;
667 for (PetscMPIInt r = 1; r < size; ++r)
if (frac[r] > frac[best]) best = r;
671 *localCount = count[rank];
672 PetscCall(PetscFree3(cells, count, frac));
673 PetscFunctionReturn(0);
677#define __FUNCT__ "CreateParticleSwarm"
685 PetscMPIInt rank, size;
686 PetscInt remainder = 0;
688 PetscFunctionBeginUser;
691 if (numParticles <= 0) {
694 return PETSC_ERR_ARG_OUTOFRANGE;
698 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
699 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
710 ierr =
DistributeParticles(numParticles, rank, size, particlesPerProcess, &remainder); CHKERRQ(ierr);
717 ierr = DMSwarmSetCellDM(user->
swarm, user->
da); CHKERRQ(ierr);
729 ierr = DMSwarmSetLocalSizes(user->
swarm, *particlesPerProcess, numParticles); CHKERRQ(ierr);
735 ierr = DMView(user->
swarm, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
741 PetscFunctionReturn(0);
750#define __FUNCT__ "UnpackSwarmFields"
759 const PetscReal *positions,
const PetscInt *cellIndices,
760 PetscReal *velocities,PetscInt *LocStatus,PetscReal *diffusivity,
Cmpnts *diffusivitygradient, PetscReal *psi,
Particle *particle) {
761 PetscFunctionBeginUser;
768 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
770 if (particle == NULL) {
771 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Output Particle pointer is NULL. \n");
779 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input PIDs pointer is NULL.\n");
781 particle->
PID = PIDs[i];
789 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);
791 particle->
weights.
x = weights[3 * i];
792 particle->
weights.
y = weights[3 * i + 1];
793 particle->
weights.
z = weights[3 * i + 2];
798 if(positions == NULL){
799 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input positions pointer is NULL.\n");
801 particle->
loc.
x = positions[3 * i];
802 particle->
loc.
y = positions[3 * i + 1];
803 particle->
loc.
z = positions[3 * i + 2];
805 rank,i, particle->
loc.
x, particle->
loc.
y, particle->
loc.
z);
808 if(velocities == NULL){
809 particle->
vel.
x = 0.0;
810 particle->
vel.
y = 0.0;
811 particle->
vel.
z = 0.0;
812 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);
814 particle->
vel.
x = velocities[3 * i];
815 particle->
vel.
y = velocities[3 * i + 1];
816 particle->
vel.
z = velocities[3 * i + 2];
821 if(diffusivity == NULL){
829 if(diffusivitygradient == NULL){
833 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);
845 particle->
psi = psi[i];
850 if(cellIndices == NULL){
851 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input cellIndices pointer is NULL.\n");
853 particle->
cell[0] = cellIndices[3 * i];
854 particle->
cell[1] = cellIndices[3 * i + 1];
855 particle->
cell[2] = cellIndices[3 * i + 2];
858 if(LocStatus == NULL){
859 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input LocStatus pointer is NULL.\n");
875 PetscFunctionReturn(0);
879#define __FUNCT__ "UpdateSwarmFields"
885 PetscReal *positions,
886 PetscReal *velocities,
888 PetscInt *cellIndices,
890 PetscReal *diffusivity,
891 Cmpnts *diffusivitygradient,
894 PetscFunctionBeginUser;
898 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input Particle pointer is NULL.\n");
903 positions[3 * i + 0] = particle->
loc.
x;
904 positions[3 * i + 1] = particle->
loc.
y;
905 positions[3 * i + 2] = particle->
loc.
z;
910 velocities[3 * i + 0] = particle->
vel.
x;
911 velocities[3 * i + 1] = particle->
vel.
y;
912 velocities[3 * i + 2] = particle->
vel.
z;
917 weights[3 * i + 0] = particle->
weights.
x;
918 weights[3 * i + 1] = particle->
weights.
y;
919 weights[3 * i + 2] = particle->
weights.
z;
924 cellIndices[3 * i + 0] = particle->
cell[0];
925 cellIndices[3 * i + 1] = particle->
cell[1];
926 cellIndices[3 * i + 2] = particle->
cell[2];
939 if(diffusivitygradient){
946 psi[i] = particle->
psi;
952 PetscFunctionReturn(0);
956#define __FUNCT__ "IsParticleInsideBoundingBox"
963 PetscFunctionBeginUser;
987 min_coords.
x, min_coords.
y, min_coords.
z, max_coords.
x, max_coords.
y, max_coords.
z);
990 if ((loc.
x >= min_coords.
x && loc.
x <= max_coords.
x) &&
991 (loc.
y >= min_coords.
y && loc.
y <= max_coords.
y) &&
992 (loc.
z >= min_coords.
z && loc.
z <= max_coords.
z)) {
1007#define __FUNCT__ "UpdateParticleWeights"
1014 PetscFunctionBeginUser;
1018 if (!d || !particle) {
1019 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
1020 "Null pointer argument (d or particle).");
1028 "face distance d[%d] = %f <= %f; "
1029 "clamping to 1e-14 to avoid zero/negative.\n",
1037 "Calculating weights with distances: "
1038 "[LEFT=%f, RIGHT=%f, BOTTOM=%f, TOP=%f, FRONT=%f, BACK=%f].\n",
1048 "Updated particle weights: x=%f, y=%f, z=%f.\n",
1053 PetscFunctionReturn(0);
1077#define __FUNCT__ "InitializeParticleSwarm"
1087 PetscErrorCode ierr;
1088 PetscInt particlesPerProcess = 0;
1091 PetscFunctionBeginUser;
1103 PetscBool should_initialize_new_particles = PETSC_FALSE;
1105 should_initialize_new_particles = PETSC_TRUE;
1108 should_initialize_new_particles = PETSC_TRUE;
1112 should_initialize_new_particles = PETSC_TRUE;
1118 if (should_initialize_new_particles) {
1121 PetscRandom randx, randy, randz;
1122 PetscRandom rand_logic_i, rand_logic_j, rand_logic_k;
1127 ierr =
FinalizeSwarmSetup(&randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1145 PetscFunctionReturn(0);
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...
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,...
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.
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.
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 DistributeParticlesByOwnedCells(UserCtx *user, PetscInt numParticles, PetscInt *localCount)
Split particles across ranks in proportion to the cells each rank owns.
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.
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt,...)
Logs a message inside a loop, but only every interval iterations.
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
#define LOCAL
Logging scope definitions for controlling message output.
#define GLOBAL
Scope for global logging across all processes.
const char * BCFaceToString(BCFace face)
Returns the canonical log token for a boundary-face enum value.
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
@ LOG_ERROR
Critical errors that may halt the program.
@ LOG_INFO
Informational messages about program execution.
@ LOG_WARNING
Non-critical issues that warrant attention.
@ LOG_DEBUG
Detailed debugging information.
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Returns the canonical log token for a particle-initialization mode.
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_CELL_ID
@ PARTICLE_FIELD_ID_DIFFUSIVITY_GRADIENT
@ PARTICLE_FIELD_ID_COUNT
@ PARTICLE_FIELD_ID_DIFFUSIVITY
@ PARTICLE_FIELD_ID_VELOCITY
PetscReal default_real_value
unsigned int capabilities
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.
const char * canonical_name
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...
PetscErrorCode InitializeRandomGenerators(UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
Initializes random number generators for assigning particle properties.
PetscErrorCode InitializeLogicalSpaceRNGs(PetscInt base_seed, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
Initializes random number generators for logical space operations [0.0, 1.0).
PetscBool inletFaceDefined
BCFace identifiedInletBCFace
SimCtx * simCtx
Back-pointer to the master simulation context.
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
@ PARTICLE_INIT_POINT_SOURCE
All particles at a fixed (psrc_x,psrc_y,psrc_z) — for validation.
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Cmpnts diffusivitygradient
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
PetscMPIInt destination_rank
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
ParticleLocationStatus location_status
char particleRestartMode[16]
ParticleInitializationType ParticleInitialization
PetscInt particleRandomSeed
Base seed for every particle RNG stream (-particle_random_seed).
@ EXEC_MODE_POSTPROCESSOR
PetscInt LoggingFrequency
BCFace
Identifies the six logical faces of a structured computational block.
Defines a 3D axis-aligned bounding box.
A 3D point or vector with PetscScalar components.
Defines a particle's core properties for Lagrangian tracking.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.