5#define INTERPOLATION_DISTANCE_TOLERANCE 1.0e-14
8#define __FUNCT__ "InitializeSwarm"
21 PetscFunctionBeginUser;
24 ierr = DMCreate(PETSC_COMM_WORLD, &user->
swarm); CHKERRQ(ierr);
25 ierr = DMSetType(user->
swarm, DMSWARM); CHKERRQ(ierr);
26 ierr = DMSetDimension(user->
swarm, 3); CHKERRQ(ierr);
27 ierr = DMSwarmSetType(user->
swarm, DMSWARM_BASIC); CHKERRQ(ierr);
31 PetscFunctionReturn(0);
35#define __FUNCT__ "RegisterSwarmField"
50PetscErrorCode
RegisterSwarmField(DM swarm,
const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
53 PetscFunctionBeginUser;
55 ierr = DMSwarmRegisterPetscDatatypeField(swarm, fieldName, fieldDim, dtype); CHKERRQ(ierr);
58 fieldName, fieldDim, PetscDataTypes[dtype]);
60 PetscFunctionReturn(0);
64#define __FUNCT__ "RegisterParticleFields"
79 PetscFunctionBeginUser;
104 LOG_ALLOW(
LOCAL,
LOG_DEBUG,
"Registered field 'DMSwarm_location_status' - Status of Location of Particle(located,lost etc).\n");
107 ierr = DMSwarmFinalizeFieldRegister(swarm); CHKERRQ(ierr);
110 PetscFunctionReturn(0);
114#define __FUNCT__ "DetermineVolumetricInitializationParameters"
154 UserCtx *user, DMDALocalInfo *info,
155 PetscInt xs_gnode, PetscInt ys_gnode, PetscInt zs_gnode,
156 PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr,
157 PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out,
158 PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out,
159 PetscBool *can_place_in_volume_out)
161 PetscErrorCode ierr = 0;
163 PetscInt local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k;
164 PetscMPIInt rank_for_logging;
166 PetscFunctionBeginUser;
170 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_for_logging); CHKERRQ(ierr);
172 *can_place_in_volume_out = PETSC_FALSE;
175 *xi_metric_logic_out = 0.5; *eta_metric_logic_out = 0.5; *zta_metric_logic_out = 0.5;
176 *ci_metric_lnode_out = xs_gnode; *cj_metric_lnode_out = ys_gnode; *ck_metric_lnode_out = zs_gnode;
180 PetscInt owned_start_cell_i, num_owned_cells_on_rank_i;
181 PetscInt owned_start_cell_j, num_owned_cells_on_rank_j;
182 PetscInt owned_start_cell_k, num_owned_cells_on_rank_k;
184 ierr =
GetOwnedCellRange(info, 0, &owned_start_cell_i, &num_owned_cells_on_rank_i); CHKERRQ(ierr);
185 ierr =
GetOwnedCellRange(info, 1, &owned_start_cell_j, &num_owned_cells_on_rank_j); CHKERRQ(ierr);
186 ierr =
GetOwnedCellRange(info, 2, &owned_start_cell_k, &num_owned_cells_on_rank_k); CHKERRQ(ierr);
188 if (num_owned_cells_on_rank_i > 0 && num_owned_cells_on_rank_j > 0 && num_owned_cells_on_rank_k > 0) {
189 *can_place_in_volume_out = PETSC_TRUE;
195 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, &r_val); CHKERRQ(ierr);
196 local_owned_cell_idx_i = (PetscInt)(r_val * num_owned_cells_on_rank_i);
198 local_owned_cell_idx_i = PetscMin(PetscMax(0, local_owned_cell_idx_i), num_owned_cells_on_rank_i - 1);
199 *ci_metric_lnode_out = xs_gnode + local_owned_cell_idx_i;
202 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, &r_val); CHKERRQ(ierr);
203 local_owned_cell_idx_j = (PetscInt)(r_val * num_owned_cells_on_rank_j);
204 local_owned_cell_idx_j = PetscMin(PetscMax(0, local_owned_cell_idx_j), num_owned_cells_on_rank_j - 1);
205 *cj_metric_lnode_out = ys_gnode + local_owned_cell_idx_j;
208 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, &r_val); CHKERRQ(ierr);
209 local_owned_cell_idx_k = (PetscInt)(r_val * num_owned_cells_on_rank_k);
210 local_owned_cell_idx_k = PetscMin(PetscMax(0, local_owned_cell_idx_k), num_owned_cells_on_rank_k - 1);
211 *ck_metric_lnode_out = zs_gnode + local_owned_cell_idx_k;
213 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",
214 rank_for_logging, local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k,
215 *ci_metric_lnode_out, *cj_metric_lnode_out, *ck_metric_lnode_out,
216 num_owned_cells_on_rank_i, num_owned_cells_on_rank_j, num_owned_cells_on_rank_k,
217 xs_gnode, ys_gnode, zs_gnode);
221 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, xi_metric_logic_out); CHKERRQ(ierr);
222 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, eta_metric_logic_out); CHKERRQ(ierr);
223 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, zta_metric_logic_out); CHKERRQ(ierr);
226 *xi_metric_logic_out = PetscMin(*xi_metric_logic_out, 1.0 - 1.0e-7);
227 *eta_metric_logic_out = PetscMin(*eta_metric_logic_out, 1.0 - 1.0e-7);
228 *zta_metric_logic_out = PetscMin(*zta_metric_logic_out, 1.0 - 1.0e-7);
230 *xi_metric_logic_out = PetscMax(*xi_metric_logic_out, 0.0);
231 *eta_metric_logic_out = PetscMax(*eta_metric_logic_out, 0.0);
232 *zta_metric_logic_out = PetscMax(*zta_metric_logic_out, 0.0);
238 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",
239 rank_for_logging, num_owned_cells_on_rank_i, num_owned_cells_on_rank_j, num_owned_cells_on_rank_k);
243 PetscFunctionReturn(0);
247#define __FUNCT__ "InitializeParticleBasicProperties"
276 PetscInt particlesPerProcess,
277 PetscRandom *rand_logic_i,
278 PetscRandom *rand_logic_j,
279 PetscRandom *rand_logic_k,
283 DM swarm = user->
swarm;
284 PetscReal *positions_field = NULL;
285 PetscInt64 *particleIDs = NULL;
286 PetscInt *cellIDs_petsc = NULL;
287 PetscInt *status_field = NULL;
288 PetscMPIInt rank,size;
289 const Cmpnts ***coor_nodes_local_array;
292 PetscInt xs_gnode_rank, ys_gnode_rank, zs_gnode_rank;
293 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global;
296 PetscBool can_this_rank_service_inlet = PETSC_FALSE;
298 PetscFunctionBeginUser;
305 if (!user || !rand_logic_i || !rand_logic_j || !rand_logic_k) {
306 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Null user or RNG pointer.");
308 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
309 ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size); CHKERRQ(ierr);
312 ierr = DMGetCoordinatesLocal(user->
da, &Coor_local); CHKERRQ(ierr);
313 if (!Coor_local) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB,
"DMGetCoordinatesLocal for user->da returned NULL Coor_local.");
314 ierr = DMDAVecGetArrayRead(user->
fda, Coor_local, (
void*)&coor_nodes_local_array); CHKERRQ(ierr);
315 ierr = DMDAGetLocalInfo(user->
da, &info); CHKERRQ(ierr);
316 ierr = DMDAGetCorners(user->
da, &xs_gnode_rank, &ys_gnode_rank, &zs_gnode_rank, NULL, NULL, NULL); CHKERRQ(ierr);
317 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);
320 IM_nodes_global -= 1; JM_nodes_global -= 1; KM_nodes_global -= 1;
322 const PetscInt IM_cells_global = IM_nodes_global > 0 ? IM_nodes_global - 1 : 0;
323 const PetscInt JM_cells_global = JM_nodes_global > 0 ? JM_nodes_global - 1 : 0;
324 const PetscInt KM_cells_global = KM_nodes_global > 0 ? KM_nodes_global - 1 : 0;
332 ierr =
CanRankServiceInletFace(user, &info, IM_nodes_global, JM_nodes_global, KM_nodes_global, &can_this_rank_service_inlet); CHKERRQ(ierr);
333 if (can_this_rank_service_inlet) {
341 ierr = DMSwarmGetField(swarm,
"position", NULL, NULL, (
void**)&positions_field); CHKERRQ(ierr);
342 ierr = DMSwarmGetField(swarm,
"DMSwarm_pid", NULL, NULL, (
void**)&particleIDs); CHKERRQ(ierr);
343 ierr = DMSwarmGetField(swarm,
"DMSwarm_CellID", NULL, NULL, (
void**)&cellIDs_petsc); CHKERRQ(ierr);
344 ierr = DMSwarmGetField(swarm,
"DMSwarm_location_status",NULL,NULL,(
void**)&status_field); CHKERRQ(ierr);
347 PetscInt particles_per_rank_ideal = simCtx->
np / size;
348 PetscInt remainder_particles = simCtx->
np % size;
349 PetscInt base_pid_for_rank = rank * particles_per_rank_ideal + PetscMin(rank, remainder_particles);
353 for (PetscInt p = 0; p < particlesPerProcess; p++) {
355 PetscInt ci_metric_lnode, cj_metric_lnode, ck_metric_lnode;
356 PetscReal xi_metric_logic, eta_metric_logic, zta_metric_logic;
357 Cmpnts phys_coords = {0.0, 0.0, 0.0};
358 PetscBool particle_placed_by_this_rank = PETSC_FALSE;
361 if (can_this_rank_service_inlet) {
363 IM_nodes_global, JM_nodes_global, KM_nodes_global,
364 rand_logic_i, rand_logic_j, rand_logic_k,
365 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
366 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic); CHKERRQ(ierr);
368 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
369 xi_metric_logic, eta_metric_logic, zta_metric_logic,
370 &phys_coords); CHKERRQ(ierr);
371 particle_placed_by_this_rank = PETSC_TRUE;
377 particle_placed_by_this_rank = PETSC_FALSE;
380 if(can_this_rank_service_inlet) {
381 PetscInt64 particle_global_id = (PetscInt64)(base_pid_for_rank + p);
383 IM_cells_global, JM_cells_global, KM_cells_global,
385 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
386 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
387 &particle_placed_by_this_rank); CHKERRQ(ierr);
388 if(particle_placed_by_this_rank){
390 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
391 xi_metric_logic, eta_metric_logic, zta_metric_logic,
392 &phys_coords); CHKERRQ(ierr);
404 particle_placed_by_this_rank = PETSC_FALSE;
407 PetscBool can_place_volumetrically;
409 rand_logic_i, rand_logic_j, rand_logic_k,
410 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
411 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
412 &can_place_volumetrically); CHKERRQ(ierr);
413 if(can_place_volumetrically){
415 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
416 xi_metric_logic, eta_metric_logic, zta_metric_logic,
417 &phys_coords); CHKERRQ(ierr);
418 particle_placed_by_this_rank = PETSC_TRUE;
421 "Rank %d: PID %lld (idx %ld) (Volumetric Mode) - DetermineVolumetric... returned false. Default Phys: (%.2f,%.2f,%.2f).\n",
422 rank, (
long long)(base_pid_for_rank + p), (
long)p, phys_coords.
x, phys_coords.
y, phys_coords.
z);
427 phys_coords.
x = simCtx->
psrc_x;
428 phys_coords.
y = simCtx->
psrc_y;
429 phys_coords.
z = simCtx->
psrc_z;
430 particle_placed_by_this_rank = PETSC_TRUE;
432 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
"Unknown ParticleInitialization mode %d.", simCtx->
ParticleInitialization);
436 positions_field[3*p+0] = phys_coords.
x;
437 positions_field[3*p+1] = phys_coords.
y;
438 positions_field[3*p+2] = phys_coords.
z;
440 particleIDs[p] = (PetscInt64)base_pid_for_rank + p;
441 cellIDs_petsc[3*p+0] = -1; cellIDs_petsc[3*p+1] = -1; cellIDs_petsc[3*p+2] = -1;
445 if (particle_placed_by_this_rank) {
447 "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",
449 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
450 xi_metric_logic, eta_metric_logic, zta_metric_logic,
451 phys_coords.
x, phys_coords.
y, phys_coords.
z);
455 "Rank %d: PID %lld (idx %ld) Mode %s NOT placed by this rank's logic. Default Coor: (%.2f,%.2f,%.2f). Relies on migration.\n",
457 phys_coords.
x, phys_coords.
y, phys_coords.
z);
462 ierr = DMSwarmRestoreField(swarm,
"position", NULL, NULL, (
void**)&positions_field); CHKERRQ(ierr);
463 ierr = DMSwarmRestoreField(swarm,
"DMSwarm_pid", NULL, NULL, (
void**)&particleIDs); CHKERRQ(ierr);
464 ierr = DMSwarmRestoreField(swarm,
"DMSwarm_CellID", NULL, NULL, (
void**)&cellIDs_petsc); CHKERRQ(ierr);
465 ierr = DMSwarmRestoreField(swarm,
"DMSwarm_location_status", NULL, NULL, (
void**)&status_field); CHKERRQ(ierr);
466 ierr = DMDAVecRestoreArrayRead(user->
fda, Coor_local, (
void*)&coor_nodes_local_array); CHKERRQ(ierr);
469 rank, particlesPerProcess);
473 PetscFunctionReturn(0);
477#define __FUNCT__ "InitializeSwarmFieldValue"
494 PetscFunctionBeginUser;
498 if (strcmp(fieldName,
"velocity") == 0) {
500 for (PetscInt d = 0; d < fieldDim; d++) {
501 fieldData[fieldDim * p + d] = 0.0;
503 }
else if (strcmp(fieldName,
"Diffusivity") == 0) {
505 for (PetscInt d = 0; d < fieldDim; d++) {
506 fieldData[fieldDim * p + d] = 1.0;
508 }
else if (strcmp(fieldName,
"DiffusivityGradient") == 0) {
510 for (PetscInt d = 0; d < fieldDim; d++) {
511 fieldData[fieldDim * p + d] = 1.0;
513 }
else if (strcmp(fieldName,
"Psi") == 0) {
514 for (PetscInt d = 0; d < fieldDim; d++) {
515 fieldData[fieldDim * p + d] = 0.0;
519 for (PetscInt d = 0; d < fieldDim; d++) {
520 fieldData[fieldDim * p + d] = 0.0;
525 PetscFunctionReturn(0);
530#define __FUNCT__ "AssignInitialFieldToSwarm"
547 DM swarm = user->
swarm;
548 PetscReal *fieldData = NULL;
551 PetscFunctionBeginUser;
556 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
560 ierr = DMSwarmGetField(swarm, fieldName, NULL, NULL, (
void**)&fieldData); CHKERRQ(ierr);
564 for (PetscInt p = 0; p < nLocal; p++) {
566 PetscReal disp_data[fieldDim];
568 for (PetscInt d = 0; d < fieldDim; d++) {
569 disp_data[d] = fieldData[fieldDim* p + d];
571 LOG_LOOP_ALLOW(
LOCAL,
LOG_VERBOSE,p, 100,
" Particle %d: %s[%d] = [%.6f, ...,%.6f].\n", p,fieldName,fieldDim,disp_data[0],disp_data[fieldDim-1]);
575 ierr = DMSwarmRestoreField(swarm, fieldName, NULL, NULL, (
void**)&fieldData); CHKERRQ(ierr);
581 PetscFunctionReturn(0);
585#define __FUNCT__ "AssignInitialPropertiesToSwarm"
615 PetscInt particlesPerProcess,
616 PetscRandom *rand_phys_x,
617 PetscRandom *rand_phys_y,
618 PetscRandom *rand_phys_z,
619 PetscRandom *rand_logic_i,
620 PetscRandom *rand_logic_j,
621 PetscRandom *rand_logic_k,
625 PetscFunctionBeginUser;
632 if (!user || !bboxlist || !rand_logic_i || !rand_logic_j || !rand_logic_k || !rand_phys_x || !rand_phys_y || !rand_phys_z) {
635 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Null input detected.");
645 LOG_ALLOW(
GLOBAL,
LOG_ERROR,
"Particle Initialization on inlet surface selected, but no INLET face was identified from bcs.dat. Cannot proceed.\n");
646 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
"ParticleInitialization Mode 0 requires an INLET face to be defined in bcs.dat.");
658 rand_logic_i, rand_logic_j, rand_logic_k,
694 PetscFunctionReturn(0);
699#define __FUNCT__ "DistributeParticles"
714PetscErrorCode
DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt* particlesPerProcess, PetscInt* remainder) {
716 PetscFunctionBeginUser;
720 *particlesPerProcess = numParticles / size;
721 *remainder = numParticles % size;
724 if (rank < *remainder) {
725 *particlesPerProcess += 1;
732 PetscFunctionReturn(0);
737#define __FUNCT__ "FinalizeSwarmSetup"
752PetscErrorCode
FinalizeSwarmSetup(PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k) {
754 PetscFunctionBeginUser;
758 ierr = PetscRandomDestroy(randx); CHKERRQ(ierr);
759 ierr = PetscRandomDestroy(randy); CHKERRQ(ierr);
760 ierr = PetscRandomDestroy(randz); CHKERRQ(ierr);
762 ierr = PetscRandomDestroy(rand_logic_i); CHKERRQ(ierr);
763 ierr = PetscRandomDestroy(rand_logic_j); CHKERRQ(ierr);
764 ierr = PetscRandomDestroy(rand_logic_k); CHKERRQ(ierr);
769 PetscFunctionReturn(0);
773#define __FUNCT__ "CreateParticleSwarm"
798 PetscMPIInt rank, size;
799 PetscInt remainder = 0;
801 PetscFunctionBeginUser;
804 if (numParticles <= 0) {
806 return PETSC_ERR_ARG_OUTOFRANGE;
810 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
811 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
819 ierr =
DistributeParticles(numParticles, rank, size, particlesPerProcess, &remainder); CHKERRQ(ierr);
825 ierr = DMSwarmSetCellDM(user->
swarm, user->
da); CHKERRQ(ierr);
837 ierr = DMSwarmSetLocalSizes(user->
swarm, *particlesPerProcess, numParticles); CHKERRQ(ierr);
843 ierr = DMView(user->
swarm, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
849 PetscFunctionReturn(0);
858#define __FUNCT__ "UnpackSwarmFields"
880 const PetscReal *positions,
const PetscInt *cellIndices,
881 PetscReal *velocities,PetscInt *LocStatus,PetscReal *diffusivity,
Cmpnts *diffusivitygradient, PetscReal *psi,
Particle *particle) {
882 PetscFunctionBeginUser;
889 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
891 if (particle == NULL) {
892 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Output Particle pointer is NULL. \n");
900 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input PIDs pointer is NULL.\n");
902 particle->
PID = PIDs[i];
910 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);
912 particle->
weights.
x = weights[3 * i];
913 particle->
weights.
y = weights[3 * i + 1];
914 particle->
weights.
z = weights[3 * i + 2];
919 if(positions == NULL){
920 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input positions pointer is NULL.\n");
922 particle->
loc.
x = positions[3 * i];
923 particle->
loc.
y = positions[3 * i + 1];
924 particle->
loc.
z = positions[3 * i + 2];
926 rank,i, particle->
loc.
x, particle->
loc.
y, particle->
loc.
z);
929 if(velocities == NULL){
930 particle->
vel.
x = 0.0;
931 particle->
vel.
y = 0.0;
932 particle->
vel.
z = 0.0;
933 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);
935 particle->
vel.
x = velocities[3 * i];
936 particle->
vel.
y = velocities[3 * i + 1];
937 particle->
vel.
z = velocities[3 * i + 2];
942 if(diffusivity == NULL){
950 if(diffusivitygradient == NULL){
954 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);
966 particle->
psi = psi[i];
971 if(cellIndices == NULL){
972 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input cellIndices pointer is NULL.\n");
974 particle->
cell[0] = cellIndices[3 * i];
975 particle->
cell[1] = cellIndices[3 * i + 1];
976 particle->
cell[2] = cellIndices[3 * i + 2];
979 if(LocStatus == NULL){
980 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input LocStatus pointer is NULL.\n");
996 PetscFunctionReturn(0);
1000#define __FUNCT__ "UpdateSwarmFields"
1022 PetscReal *positions,
1023 PetscReal *velocities,
1025 PetscInt *cellIndices,
1027 PetscReal *diffusivity,
1028 Cmpnts *diffusivitygradient,
1031 PetscFunctionBeginUser;
1035 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Input Particle pointer is NULL.\n");
1040 positions[3 * i + 0] = particle->
loc.
x;
1041 positions[3 * i + 1] = particle->
loc.
y;
1042 positions[3 * i + 2] = particle->
loc.
z;
1047 velocities[3 * i + 0] = particle->
vel.
x;
1048 velocities[3 * i + 1] = particle->
vel.
y;
1049 velocities[3 * i + 2] = particle->
vel.
z;
1054 weights[3 * i + 0] = particle->
weights.
x;
1055 weights[3 * i + 1] = particle->
weights.
y;
1056 weights[3 * i + 2] = particle->
weights.
z;
1061 cellIndices[3 * i + 0] = particle->
cell[0];
1062 cellIndices[3 * i + 1] = particle->
cell[1];
1063 cellIndices[3 * i + 2] = particle->
cell[2];
1076 if(diffusivitygradient){
1083 psi[i] = particle->
psi;
1089 PetscFunctionReturn(0);
1093#define __FUNCT__ "IsParticleInsideBoundingBox"
1116 PetscFunctionBeginUser;
1140 min_coords.
x, min_coords.
y, min_coords.
z, max_coords.
x, max_coords.
y, max_coords.
z);
1143 if ((loc.
x >= min_coords.
x && loc.
x <= max_coords.
x) &&
1144 (loc.
y >= min_coords.
y && loc.
y <= max_coords.
y) &&
1145 (loc.
z >= min_coords.
z && loc.
z <= max_coords.
z)) {
1160#define __FUNCT__ "UpdateParticleWeights"
1174 PetscFunctionBeginUser;
1178 if (!d || !particle) {
1179 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
1180 "Null pointer argument (d or particle).");
1188 "face distance d[%d] = %f <= %f; "
1189 "clamping to 1e-14 to avoid zero/negative.\n",
1197 "Calculating weights with distances: "
1198 "[LEFT=%f, RIGHT=%f, BOTTOM=%f, TOP=%f, FRONT=%f, BACK=%f].\n",
1208 "Updated particle weights: x=%f, y=%f, z=%f.\n",
1213 PetscFunctionReturn(0);
1237#define __FUNCT__ "InitializeParticleSwarm"
1240 PetscErrorCode ierr;
1241 PetscInt particlesPerProcess = 0;
1244 PetscFunctionBeginUser;
1256 PetscBool should_initialize_new_particles = PETSC_FALSE;
1258 should_initialize_new_particles = PETSC_TRUE;
1261 should_initialize_new_particles = PETSC_TRUE;
1265 should_initialize_new_particles = PETSC_TRUE;
1271 if (should_initialize_new_particles) {
1274 PetscRandom randx, randy, randz;
1275 PetscRandom rand_logic_i, rand_logic_j, rand_logic_k;
1280 ierr =
FinalizeSwarmSetup(&randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1298 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)
Public wrapper: map (cell index, ξ,η,ζ) to (x,y,z).
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)
Updates a particle's interpolation weights based on distances to cell faces.
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 DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
Distributes particles evenly across MPI processes, handling any remainders.
static PetscErrorCode AssignInitialFieldToSwarm(UserCtx *user, const char *fieldName, PetscInt fieldDim)
Initializes a generic swarm field with point-level updates.
#define INTERPOLATION_DISTANCE_TOLERANCE
static PetscErrorCode InitializeSwarmFieldValue(const char *fieldName, PetscInt p, PetscInt fieldDim, PetscReal *fieldData)
Helper function to Initialize a given particle’s field value.
PetscBool IsParticleInsideBoundingBox(const BoundingBox *bbox, const Particle *particle)
Checks if a particle's location is within a specified bounding box.
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.
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)
Initializes a Particle struct with data from DMSwarm fields.
PetscErrorCode InitializeSwarm(UserCtx *user)
Initializes the DMSwarm object within the UserCtx structure.
PetscErrorCode UpdateSwarmFields(PetscInt i, const Particle *particle, PetscReal *positions, PetscReal *velocities, PetscReal *weights, PetscInt *cellIndices, PetscInt *status, PetscReal *diffusivity, Cmpnts *diffusivitygradient, PetscReal *psi)
Updates DMSwarm data arrays from a Particle struct.
PetscErrorCode InitializeParticleSwarm(SimCtx *simCtx)
Perform particle swarm initialization, particle-grid interaction, and related operations.
PetscErrorCode RegisterSwarmField(DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
Registers a swarm field without finalizing registration.
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).
PetscErrorCode RegisterParticleFields(DM swarm)
Registers necessary particle fields within the DMSwarm.
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.
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,...)
----— DEBUG ---------------------------------------— #define LOG_ALLOW(scope, level,...
#define LOCAL
Logging scope definitions for controlling message output.
#define GLOBAL
Scope for global logging across all processes.
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
#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)
Helper function to convert ParticleInitialization to a string representation.
PetscErrorCode InitializeRandomGenerators(UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
Initializes random number generators for assigning particle properties.
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global, PetscInt *xm_cell_local)
Determines the global starting index and number of CELLS owned by the current processor in a specifie...
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).
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
@ 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.