PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Macros | Functions
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
 
#define __FUNCT__   "InitializeSwarm"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "RegisterSwarmField"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "RegisterParticleFields"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "DetermineVolumetricInitializationParameters"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "InitializeParticleBasicProperties"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "InitializeSwarmFieldValue"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "AssignInitialFieldToSwarm"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "AssignInitialPropertiesToSwarm"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "DistributeParticles"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "FinalizeSwarmSetup"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "CreateParticleSwarm"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "UnpackSwarmFields"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "UpdateSwarmFields"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "IsParticleInsideBoundingBox"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "UpdateParticleWeights"
 Initializes or loads the particle swarm based on the simulation context.
 
#define __FUNCT__   "InitializeParticleSwarm"
 Initializes or loads the particle swarm based on the simulation context.
 

Functions

PetscErrorCode InitializeSwarm (UserCtx *user)
 Implementation of InitializeSwarm().
 
PetscErrorCode RegisterSwarmField (DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
 Internal helper implementation: RegisterSwarmField().
 
PetscErrorCode RegisterParticleFields (DM swarm)
 Implementation of RegisterParticleFields().
 
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.
 
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.
 
static PetscErrorCode InitializeSwarmFieldValue (const ParticleFieldDescriptor *descriptor, PetscInt p, PetscReal *fieldData)
 Assign one configured initial value to a swarm field entry.
 
static PetscErrorCode AssignInitialFieldToSwarm (UserCtx *user, ParticleFieldId field_id)
 Apply a configured initial field specification across the local swarm.
 
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().
 
PetscErrorCode DistributeParticles (PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
 Implementation of DistributeParticles().
 
PetscErrorCode FinalizeSwarmSetup (PetscRandom *randx, PetscRandom *randy, PetscRandom *randz, PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
 Implementation of FinalizeSwarmSetup().
 
PetscErrorCode CreateParticleSwarm (UserCtx *user, PetscInt numParticles, PetscInt *particlesPerProcess, BoundingBox *bboxlist)
 Internal helper implementation: CreateParticleSwarm().
 
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 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().
 
PetscBool IsParticleInsideBoundingBox (const BoundingBox *bbox, const Particle *particle)
 Internal helper implementation: IsParticleInsideBoundingBox().
 
PetscErrorCode UpdateParticleWeights (PetscReal *d, Particle *particle)
 Internal helper implementation: UpdateParticleWeights().
 
PetscErrorCode InitializeParticleSwarm (SimCtx *simCtx)
 Implementation of InitializeParticleSwarm().
 

Macro Definition Documentation

◆ INTERPOLATION_DISTANCE_TOLERANCE

#define INTERPOLATION_DISTANCE_TOLERANCE   1.0e-14

Definition at line 5 of file ParticleSwarm.c.

◆ __FUNCT__ [1/16]

#define __FUNCT__   "InitializeSwarm"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [2/16]

#define __FUNCT__   "RegisterSwarmField"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [3/16]

#define __FUNCT__   "RegisterParticleFields"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [4/16]

#define __FUNCT__   "DetermineVolumetricInitializationParameters"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [5/16]

#define __FUNCT__   "InitializeParticleBasicProperties"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [6/16]

#define __FUNCT__   "InitializeSwarmFieldValue"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [7/16]

#define __FUNCT__   "AssignInitialFieldToSwarm"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [8/16]

#define __FUNCT__   "AssignInitialPropertiesToSwarm"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [9/16]

#define __FUNCT__   "DistributeParticles"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [10/16]

#define __FUNCT__   "FinalizeSwarmSetup"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [11/16]

#define __FUNCT__   "CreateParticleSwarm"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [12/16]

#define __FUNCT__   "UnpackSwarmFields"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [13/16]

#define __FUNCT__   "UpdateSwarmFields"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [14/16]

#define __FUNCT__   "IsParticleInsideBoundingBox"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [15/16]

#define __FUNCT__   "UpdateParticleWeights"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

◆ __FUNCT__ [16/16]

#define __FUNCT__   "InitializeParticleSwarm"

Initializes or loads the particle swarm based on the simulation context.

This function is the central point for setting up the DMSwarm. Its behavior depends on the simulation context (simCtx):

  1. Fresh Start (simCtx->StartStep == 0): A new particle population is generated according to the specified initial conditions.
  2. Restart (simCtx->StartStep > 0):
    • If simCtx->particleRestartMode is "init", a new particle population is generated, just like a fresh start. This allows injecting fresh particles into a pre-computed flow field.
    • If simCtx->particleRestartMode is "load", the particle state is loaded from restart files corresponding to the StartStep.
Parameters
[in,out]simCtxPointer to the main SimulationContext, which contains all configuration and provides access to the UserCtx.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 8 of file ParticleSwarm.c.

Function Documentation

◆ InitializeSwarm()

PetscErrorCode InitializeSwarm ( UserCtx user)

Implementation of InitializeSwarm().

Initializes the DMSwarm object within the UserCtx structure.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/ParticleSwarm.h.

See also
InitializeSwarm()

Definition at line 15 of file ParticleSwarm.c.

15 {
16 PetscErrorCode ierr; // Error code for PETSc functions
17
18 PetscFunctionBeginUser;
20 // Create the DMSwarm object for particle management
21 ierr = DMCreate(PETSC_COMM_WORLD, &user->swarm); CHKERRQ(ierr);
22 ierr = DMSetType(user->swarm, DMSWARM); CHKERRQ(ierr);
23 ierr = DMSetDimension(user->swarm, 3); CHKERRQ(ierr);
24 ierr = DMSwarmSetType(user->swarm, DMSWARM_BASIC); CHKERRQ(ierr);
25 LOG_ALLOW(LOCAL,LOG_INFO, "DMSwarm created and configured.\n");
26
28 PetscFunctionReturn(0);
29}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:859
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:850
Here is the caller graph for this function:

◆ RegisterSwarmField()

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

Internal helper implementation: RegisterSwarmField().

Registers a swarm field without finalizing registration.

Local to this translation unit.

Definition at line 38 of file ParticleSwarm.c.

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

◆ RegisterParticleFields()

PetscErrorCode RegisterParticleFields ( DM  swarm)

Implementation of RegisterParticleFields().

Registers necessary particle fields within the DMSwarm.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/ParticleSwarm.h.

See also
RegisterParticleFields()

Definition at line 61 of file ParticleSwarm.c.

62{
63 PetscErrorCode ierr;
64 PetscFunctionBeginUser;
65
66 for (PetscInt raw_id = 0; raw_id < PARTICLE_FIELD_ID_COUNT; ++raw_id) {
67 const ParticleFieldDescriptor *descriptor = NULL;
68
69 ierr = ParticleFieldGetDescriptor((ParticleFieldId)raw_id, &descriptor); CHKERRQ(ierr);
70 if (descriptor->registration == PARTICLE_FIELD_REGISTRATION_PETSC) continue;
71
72 ierr = RegisterSwarmField(swarm, descriptor->canonical_name,
73 descriptor->components, descriptor->data_type); CHKERRQ(ierr);
74 }
75
76 // Finalize the field registration after all fields have been added
77 ierr = DMSwarmFinalizeFieldRegister(swarm); CHKERRQ(ierr);
78 LOG_ALLOW(LOCAL,LOG_INFO,"RegisterParticleFields - Finalized field registration.\n");
79
80 PetscFunctionReturn(0);
81}
PetscErrorCode RegisterSwarmField(DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
Internal helper implementation: RegisterSwarmField().
ParticleFieldId
Compile-time identity for a persistent solver-particle field.
@ PARTICLE_FIELD_ID_COUNT
ParticleFieldRegistration registration
@ PARTICLE_FIELD_REGISTRATION_PETSC
PetscErrorCode ParticleFieldGetDescriptor(ParticleFieldId field_id, const ParticleFieldDescriptor **descriptor)
Return immutable metadata for a valid particle field ID.
Immutable metadata for one persistent particle field.
Here is the call graph for this function:
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

Derive particle counts and spacing for volumetric swarm initialization.

Definition at line 88 of file ParticleSwarm.c.

95{
96 PetscErrorCode ierr = 0;
97 (void)user;
98 PetscReal r_val; // Temporary for random numbers from [0,1) RNGs
99 PetscInt local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k;
100 PetscMPIInt rank_for_logging; // For logging if needed
101
102 PetscFunctionBeginUser;
103
105
106 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_for_logging); CHKERRQ(ierr);
107
108 *can_place_in_volume_out = PETSC_FALSE; // Default to: cannot place
109
110 // Default intra-cell logicals and cell node indices (e.g. if placement fails)
111 *xi_metric_logic_out = 0.5; *eta_metric_logic_out = 0.5; *zta_metric_logic_out = 0.5;
112 *ci_metric_lnode_out = xs_gnode; *cj_metric_lnode_out = ys_gnode; *ck_metric_lnode_out = zs_gnode;
113
114 // Calculate number of owned cells in each direction from node counts in info
115 // Get number of cells this rank owns in each dimension (tangential to the face mainly)
116 PetscInt owned_start_cell_i, num_owned_cells_on_rank_i;
117 PetscInt owned_start_cell_j, num_owned_cells_on_rank_j;
118 PetscInt owned_start_cell_k, num_owned_cells_on_rank_k;
119
120 ierr = GetOwnedCellRange(info, 0, &owned_start_cell_i, &num_owned_cells_on_rank_i); CHKERRQ(ierr);
121 ierr = GetOwnedCellRange(info, 1, &owned_start_cell_j, &num_owned_cells_on_rank_j); CHKERRQ(ierr);
122 ierr = GetOwnedCellRange(info, 2, &owned_start_cell_k, &num_owned_cells_on_rank_k); CHKERRQ(ierr);
123
124 if (num_owned_cells_on_rank_i > 0 && num_owned_cells_on_rank_j > 0 && num_owned_cells_on_rank_k > 0) { // If rank owns any 3D cells
125 *can_place_in_volume_out = PETSC_TRUE;
126
127 // --- 1. Select a Random Owned Cell ---
128 // The selected index will be a 0-based index relative to the start of this rank's owned cells.
129
130 // Select random local owned cell index in I-direction
131 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
132 local_owned_cell_idx_i = (PetscInt)(r_val * num_owned_cells_on_rank_i);
133 // Clamp to be safe: local_owned_cell_idx_i should be in [0, num_owned_cells_on_rank_i - 1]
134 local_owned_cell_idx_i = PetscMin(PetscMax(0, local_owned_cell_idx_i), num_owned_cells_on_rank_i - 1);
135 *ci_metric_lnode_out = xs_gnode + local_owned_cell_idx_i; // Convert to local node index for cell origin
136
137 // Select random local owned cell index in J-direction
138 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
139 local_owned_cell_idx_j = (PetscInt)(r_val * num_owned_cells_on_rank_j);
140 local_owned_cell_idx_j = PetscMin(PetscMax(0, local_owned_cell_idx_j), num_owned_cells_on_rank_j - 1);
141 *cj_metric_lnode_out = ys_gnode + local_owned_cell_idx_j;
142
143 // Select random local owned cell index in K-direction
144 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, &r_val); CHKERRQ(ierr); // Dereference RNG pointer
145 local_owned_cell_idx_k = (PetscInt)(r_val * num_owned_cells_on_rank_k);
146 local_owned_cell_idx_k = PetscMin(PetscMax(0, local_owned_cell_idx_k), num_owned_cells_on_rank_k - 1);
147 *ck_metric_lnode_out = zs_gnode + local_owned_cell_idx_k;
148
149 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Selected Cell (Owned Idx: %d,%d,%d -> LNodeStart: %d,%d,%d). OwnedCells(i,j,k): (%d,%d,%d). GhostNodeStarts(xs,ys,zs): (%d,%d,%d) \n",
150 rank_for_logging, local_owned_cell_idx_i, local_owned_cell_idx_j, local_owned_cell_idx_k,
151 *ci_metric_lnode_out, *cj_metric_lnode_out, *ck_metric_lnode_out,
152 num_owned_cells_on_rank_i, num_owned_cells_on_rank_j, num_owned_cells_on_rank_k,
153 xs_gnode, ys_gnode, zs_gnode);
154
155
156 // --- 2. Generate Random Intra-Cell Logical Coordinates [0,1) for MetricLogicalToPhysical ---
157 ierr = PetscRandomGetValueReal(*rand_logic_i_ptr, xi_metric_logic_out); CHKERRQ(ierr); // Re-use RNGs
158 ierr = PetscRandomGetValueReal(*rand_logic_j_ptr, eta_metric_logic_out); CHKERRQ(ierr);
159 ierr = PetscRandomGetValueReal(*rand_logic_k_ptr, zta_metric_logic_out); CHKERRQ(ierr);
160
161 // Ensure logical coordinates are strictly within [0,1) for robustness with MetricLogicalToPhysical
162 *xi_metric_logic_out = PetscMin(*xi_metric_logic_out, 1.0 - 1.0e-7);
163 *eta_metric_logic_out = PetscMin(*eta_metric_logic_out, 1.0 - 1.0e-7);
164 *zta_metric_logic_out = PetscMin(*zta_metric_logic_out, 1.0 - 1.0e-7);
165 // Ensure they are not negative either (though [0,1) RNGs shouldn't produce this)
166 *xi_metric_logic_out = PetscMax(*xi_metric_logic_out, 0.0);
167 *eta_metric_logic_out = PetscMax(*eta_metric_logic_out, 0.0);
168 *zta_metric_logic_out = PetscMax(*zta_metric_logic_out, 0.0);
169
170 } else {
171 // This rank does not own any 3D cells (e.g., in a 1D or 2D decomposition,
172 // or if the global domain itself is not 3D in terms of cells).
173 // *can_place_in_volume_out remains PETSC_FALSE.
174 LOG_ALLOW(LOCAL, LOG_WARNING, "Rank %d: Cannot place particle volumetrically. Rank has zero owned cells in at least one dimension (owned cells i,j,k: %d,%d,%d).\n",
175 rank_for_logging, num_owned_cells_on_rank_i, num_owned_cells_on_rank_j, num_owned_cells_on_rank_k);
176 }
177
179 PetscFunctionReturn(0);
180}
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global_out, PetscInt *xm_cell_local_out)
Determines the global starting index and number of CELLS owned by the current processor in a specifie...
Definition setup.c:2285
Here is the call graph for this function:
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

Initialize position-independent particle fields after a particle is created.

Definition at line 188 of file ParticleSwarm.c.

194{
195 PetscErrorCode ierr;
196 (void)bboxlist;
197 DM swarm = user->swarm;
198 PetscReal *positions_field = NULL; // Pointer to swarm field for physical positions (x,y,z)
199 PetscInt64 *particleIDs = NULL; // Pointer to swarm field for Particle IDs
200 PetscInt *cellIDs_petsc = NULL; // Pointer to swarm field for DMSwarm_CellID (i,j,k of containing cell)
201 PetscInt *status_field = NULL; // Pointer to swarm field for DMSwarm_location_status(NEEDS_LOCATION etc)
202 PetscMPIInt rank,size; // MPI rank of the current process, and total number of ranks.
203 const Cmpnts ***coor_nodes_local_array; // Read-only access to local node coordinates (from user->da)
204 Vec Coor_local; // Local vector for node coordinates
205 DMDALocalInfo info; // Local grid information (node-based) from user->da
206 PetscInt xs_gnode_rank, ys_gnode_rank, zs_gnode_rank; // Local starting node indices (incl. ghosts) of rank's DA patch
207 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global; // Global node counts in each direction
208
209 // Variables for surface initialization (Mode 0)
210 PetscBool can_this_rank_service_inlet = PETSC_FALSE;
211
212 PetscFunctionBeginUser;
213
215
216 SimCtx *simCtx = user->simCtx;
217
218 // --- 1. Input Validation and Basic Setup ---
219 if (!user || !rand_logic_i || !rand_logic_j || !rand_logic_k) {
220 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null user or RNG pointer.");
221 }
222 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
223 ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size); CHKERRQ(ierr);
224
225 // Get DMDA information for the node-centered coordinate grid (user->da)
226 ierr = DMGetCoordinatesLocal(user->da, &Coor_local); CHKERRQ(ierr);
227 if (!Coor_local) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "DMGetCoordinatesLocal for user->da returned NULL Coor_local.");
228 ierr = DMDAVecGetArrayRead(user->fda, Coor_local, (void*)&coor_nodes_local_array); CHKERRQ(ierr);
229 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
230 ierr = DMDAGetCorners(user->da, &xs_gnode_rank, &ys_gnode_rank, &zs_gnode_rank, NULL, NULL, NULL); CHKERRQ(ierr);
231 ierr = DMDAGetInfo(user->da, NULL, &IM_nodes_global, &JM_nodes_global, &KM_nodes_global, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); CHKERRQ(ierr);
232
233 // Modification to IM_nodes_global etc. to account for 1-cell halo in each direction.
234 IM_nodes_global -= 1; JM_nodes_global -= 1; KM_nodes_global -= 1;
235
236 const PetscInt IM_cells_global = IM_nodes_global > 0 ? IM_nodes_global - 1 : 0;
237 const PetscInt JM_cells_global = JM_nodes_global > 0 ? JM_nodes_global - 1 : 0;
238 const PetscInt KM_cells_global = KM_nodes_global > 0 ? KM_nodes_global - 1 : 0;
239
240 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Initializing %d particles. Mode: %s.\n",
241 rank, particlesPerProcess, ParticleInitializationToString(simCtx->ParticleInitialization));
242
243 // --- 2. Pre-computation for Surface Initialization (PARTICLE_INIT_SURFACE_RANDOM and PARTICLE_INIT_SURFACE_EDGES) ---
245 simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_EDGES) { // Surface initialization
246 ierr = CanRankServiceInletFace(user, &info, IM_nodes_global, JM_nodes_global, KM_nodes_global, &can_this_rank_service_inlet); CHKERRQ(ierr);
247 if (can_this_rank_service_inlet) {
248 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Will attempt to place particles on inlet face %s.\n", rank, BCFaceToString((BCFace)user->identifiedInletBCFace));
249 } else {
250 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Cannot service inlet face %s. Particles will be at Inlet Center (%.6f,%.6f,%.6f) and rely on migration.\n", rank, BCFaceToString((BCFace)user->identifiedInletBCFace),user->simCtx->CMx_c,user->simCtx->CMy_c,user->simCtx->CMz_c);
251 }
252 }
253
254 // --- 3. Get Access to Swarm Fields ---
255 ierr = DMSwarmGetField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&positions_field); CHKERRQ(ierr);
256 ierr = DMSwarmGetField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_PID), NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
257 ierr = DMSwarmGetField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_CELL_ID), NULL, NULL, (void**)&cellIDs_petsc); CHKERRQ(ierr);
258 ierr = DMSwarmGetField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_LOCATION_STATUS),NULL,NULL,(void**)&status_field); CHKERRQ(ierr);
259
260 // --- 4. Determine Starting Global PID for this Rank ---
261 PetscInt particles_per_rank_ideal = simCtx->np / size; // Assumes user->size is PETSC_COMM_WORLD size
262 PetscInt remainder_particles = simCtx->np % size;
263 PetscInt base_pid_for_rank = rank * particles_per_rank_ideal + PetscMin(rank, remainder_particles);
264 // This calculation must match how particlesPerProcess was determined (e.g., in DistributeParticles).
265
266 // --- 5. Loop Over Particles to Initialize ---
267 for (PetscInt p = 0; p < particlesPerProcess; p++) {
268 PetscInt idx = p;
269 PetscInt ci_metric_lnode, cj_metric_lnode, ck_metric_lnode;
270 PetscReal xi_metric_logic, eta_metric_logic, zta_metric_logic;
271 Cmpnts phys_coords = {0.0, 0.0, 0.0};
272 PetscBool particle_placed_by_this_rank = PETSC_FALSE;
273
274 if (simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_RANDOM) { // --- 5.a. Surface Random Initialization ---
275 if (can_this_rank_service_inlet) {
276 ierr = GetRandomCellAndLogicalCoordsOnInletFace(user, &info, xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
277 IM_nodes_global, JM_nodes_global, KM_nodes_global,
278 rand_logic_i, rand_logic_j, rand_logic_k,
279 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
280 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic); CHKERRQ(ierr);
281 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
282 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
283 xi_metric_logic, eta_metric_logic, zta_metric_logic,
284 &phys_coords); CHKERRQ(ierr);
285 particle_placed_by_this_rank = PETSC_TRUE;
286 }else{
287 // Rank cannot service inlet - place at inlet center to be migrated later
288 phys_coords.x = user->simCtx->CMx_c;
289 phys_coords.y = user->simCtx->CMy_c;
290 phys_coords.z = user->simCtx->CMz_c;
291 particle_placed_by_this_rank = PETSC_FALSE; // Relies on migration
292 }
293 }else if(simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_EDGES) { // --- 5.a1. Surface Edges Initialization (deterministic) ---
294 if(can_this_rank_service_inlet) {
295 PetscInt64 particle_global_id = (PetscInt64)(base_pid_for_rank + p);
296 ierr = GetDeterministicFaceGridLocation(user,&info,xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
297 IM_cells_global, JM_cells_global, KM_cells_global,
298 particle_global_id,
299 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
300 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
301 &particle_placed_by_this_rank); CHKERRQ(ierr);
302 if(particle_placed_by_this_rank){
303 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
304 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
305 xi_metric_logic, eta_metric_logic, zta_metric_logic,
306 &phys_coords); CHKERRQ(ierr);
307 }else{
308 // Even if rank can service face, it may not own the portion of the face that a particle is placed in.
309 phys_coords.x = user->simCtx->CMx_c;
310 phys_coords.y = user->simCtx->CMy_c;
311 phys_coords.z = user->simCtx->CMz_c;
312 }
313 }else{
314 // Rank cannot service inlet - place at inlet center to be migrated later
315 phys_coords.x = user->simCtx->CMx_c;
316 phys_coords.y = user->simCtx->CMy_c;
317 phys_coords.z = user->simCtx->CMz_c;
318 particle_placed_by_this_rank = PETSC_FALSE; // Relies on migration
319 }
320 }else if(simCtx->ParticleInitialization == PARTICLE_INIT_VOLUME){ // --- 5.b. Volumetric Initialization ---
321 PetscBool can_place_volumetrically = PETSC_FALSE;
322 ierr = DetermineVolumetricInitializationParameters(user, &info, xs_gnode_rank, ys_gnode_rank, zs_gnode_rank,
323 rand_logic_i, rand_logic_j, rand_logic_k,
324 &ci_metric_lnode, &cj_metric_lnode, &ck_metric_lnode,
325 &xi_metric_logic, &eta_metric_logic, &zta_metric_logic,
326 &can_place_volumetrically); CHKERRQ(ierr);
327 if(can_place_volumetrically){
328 ierr = MetricLogicalToPhysical(user, coor_nodes_local_array,
329 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
330 xi_metric_logic, eta_metric_logic, zta_metric_logic,
331 &phys_coords); CHKERRQ(ierr);
332 particle_placed_by_this_rank = PETSC_TRUE;
333 } else {
335 "Rank %d: PID %lld (idx %ld) (Volumetric Mode) - DetermineVolumetric... returned false. Default Phys: (%.2f,%.2f,%.2f).\n",
336 rank, (long long)(base_pid_for_rank + p), (long)p, phys_coords.x, phys_coords.y, phys_coords.z);
337 }
338 }else if(simCtx->ParticleInitialization == PARTICLE_INIT_POINT_SOURCE){ // --- 5.c. Point Source Initialization ---
339 // All particles placed at the user-specified fixed point (psrc_x, psrc_y, psrc_z).
340 // No random number generation or logical-to-physical conversion needed.
341 phys_coords.x = simCtx->psrc_x;
342 phys_coords.y = simCtx->psrc_y;
343 phys_coords.z = simCtx->psrc_z;
344 particle_placed_by_this_rank = PETSC_TRUE;
345 }else {
346 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown ParticleInitialization mode %d.", simCtx->ParticleInitialization);
347 }
348
349 // --- 5.c. Store Particle Properties ---
350 positions_field[3*p+0] = phys_coords.x;
351 positions_field[3*p+1] = phys_coords.y;
352 positions_field[3*p+2] = phys_coords.z;
353
354 particleIDs[p] = (PetscInt64)base_pid_for_rank + p;
355 cellIDs_petsc[3*p+0] = -1; cellIDs_petsc[3*p+1] = -1; cellIDs_petsc[3*p+2] = -1;
356 status_field[p] = UNINITIALIZED;
357
358 // --- 5.d. Logging for this particle ---
359 if (particle_placed_by_this_rank) {
360 LOG_LOOP_ALLOW(LOCAL, LOG_VERBOSE, idx, user->simCtx->LoggingFrequency,//(particlesPerProcess > 20 ? particlesPerProcess/10 : 1),
361 "Rank %d: PID %lld (idx %ld) PLACED. Mode %s. Embedded Cell:(%d,%d,%d). Logical Coords: (%.2e,%.2f,%.2f).\n Final Coords: (%.6f,%.6f,%.6f).\n",
362 rank, (long long)particleIDs[p], (long)p, ParticleInitializationToString(simCtx->ParticleInitialization),
363 ci_metric_lnode, cj_metric_lnode, ck_metric_lnode,
364 xi_metric_logic, eta_metric_logic, zta_metric_logic,
365 phys_coords.x, phys_coords.y, phys_coords.z);
366
367 } else {
368 LOG_LOOP_ALLOW(LOCAL, LOG_WARNING, idx, user->simCtx->LoggingFrequency, //(particlesPerProcess > 20 ? particlesPerProcess/10 : 1),
369 "Rank %d: PID %lld (idx %ld) Mode %s NOT placed by this rank's logic. Default Coor: (%.2f,%.2f,%.2f). Relies on migration.\n",
370 rank, (long long)particleIDs[p], (long)p, ParticleInitializationToString(simCtx->ParticleInitialization),
371 phys_coords.x, phys_coords.y, phys_coords.z);
372 }
373 }
374
375 // --- 6. Restore Pointers and Cleanup ---
376 ierr = DMSwarmRestoreField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&positions_field); CHKERRQ(ierr);
377 ierr = DMSwarmRestoreField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_PID), NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
378 ierr = DMSwarmRestoreField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_CELL_ID), NULL, NULL, (void**)&cellIDs_petsc); CHKERRQ(ierr);
379 ierr = DMSwarmRestoreField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_LOCATION_STATUS), NULL, NULL, (void**)&status_field); CHKERRQ(ierr);
380 ierr = DMDAVecRestoreArrayRead(user->fda, Coor_local, (void*)&coor_nodes_local_array); CHKERRQ(ierr);
381
382 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Completed processing for %d particles.\n",
383 rank, particlesPerProcess);
384
386
387 PetscFunctionReturn(0);
388}
PetscErrorCode GetRandomCellAndLogicalCoordsOnInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out)
Assuming the current rank services the inlet face, this function selects a random cell (owned by this...
Definition Boundaries.c:400
PetscErrorCode CanRankServiceInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscBool *can_service_inlet_out)
Determines if the current MPI rank owns any part of the globally defined inlet face,...
Definition Boundaries.c:11
PetscErrorCode GetDeterministicFaceGridLocation(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_cells_global, PetscInt JM_cells_global, PetscInt KM_cells_global, PetscInt64 particle_global_id, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out, PetscBool *placement_successful_out)
Places particles in a deterministic grid/raster pattern on a specified domain face.
Definition Boundaries.c:213
PetscErrorCode MetricLogicalToPhysical(UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, PetscReal xi, PetscReal eta, PetscReal zta, Cmpnts *Xp)
Maps a logical point inside one hexahedral cell to physical space.
Definition Metric.c:76
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.
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt,...)
Logs a message inside a loop, but only every interval iterations.
Definition logging.h:298
const char * BCFaceToString(BCFace face)
Returns the canonical log token for a boundary-face enum value.
Definition logging.c:671
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Returns the canonical log token for a particle-initialization mode.
Definition logging.c:724
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_LOCATION_STATUS
@ PARTICLE_FIELD_ID_POSITION
@ PARTICLE_FIELD_ID_PID
@ PARTICLE_FIELD_ID_CELL_ID
BCFace identifiedInletBCFace
Definition variables.h:933
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:552
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:555
@ PARTICLE_INIT_POINT_SOURCE
All particles at a fixed (psrc_x,psrc_y,psrc_z) — for validation.
Definition variables.h:554
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
Definition variables.h:553
@ UNINITIALIZED
Definition variables.h:142
PetscReal CMy_c
Definition variables.h:783
PetscReal psrc_x
Definition variables.h:784
PetscInt np
Definition variables.h:827
PetscScalar x
Definition variables.h:103
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
Definition variables.h:784
PetscReal CMz_c
Definition variables.h:783
ParticleInitializationType ParticleInitialization
Definition variables.h:831
PetscScalar z
Definition variables.h:103
PetscReal psrc_y
Definition variables.h:784
PetscScalar y
Definition variables.h:103
PetscInt LoggingFrequency
Definition variables.h:857
PetscReal CMx_c
Definition variables.h:783
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:261
A 3D point or vector with PetscScalar components.
Definition variables.h:102
The master context for the entire simulation.
Definition variables.h:695
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitializeSwarmFieldValue()

static PetscErrorCode InitializeSwarmFieldValue ( const ParticleFieldDescriptor descriptor,
PetscInt  p,
PetscReal *  fieldData 
)
static

Assign one configured initial value to a swarm field entry.

Definition at line 395 of file ParticleSwarm.c.

397{
398 PetscFunctionBeginUser;
399
401
402 PetscCheck(descriptor != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
403 "Particle field descriptor cannot be NULL during initialization.");
404 PetscCheck(fieldData != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
405 "Particle field data cannot be NULL during initialization.");
406 PetscCheck(descriptor->data_type == PETSC_REAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
407 "Default initialization currently supports only PETSC_REAL particle fields; '%s' uses %s.",
408 descriptor->canonical_name, PetscDataTypes[descriptor->data_type]);
409 PetscCheck((descriptor->capabilities & PARTICLE_FIELD_CAPABILITY_DEFAULT_INITIALIZE) != 0,
410 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
411 "Particle field '%s' does not use catalog-default initialization.",
412 descriptor->canonical_name);
413
414 for (PetscInt d = 0; d < descriptor->components; ++d) {
415 fieldData[descriptor->components * p + d] = descriptor->default_real_value;
416 }
417
419 PetscFunctionReturn(0);
420}
@ PARTICLE_FIELD_CAPABILITY_DEFAULT_INITIALIZE
Here is the caller graph for this function:

◆ AssignInitialFieldToSwarm()

static PetscErrorCode AssignInitialFieldToSwarm ( UserCtx user,
ParticleFieldId  field_id 
)
static

Apply a configured initial field specification across the local swarm.

Definition at line 428 of file ParticleSwarm.c.

429{
430 PetscErrorCode ierr;
431 DM swarm = user->swarm;
432 PetscReal *fieldData = NULL;
433 PetscInt nLocal;
434 const ParticleFieldDescriptor *descriptor = NULL;
435 const char *fieldName = NULL;
436
437 PetscFunctionBeginUser;
438
440
441 ierr = ParticleFieldGetDescriptor(field_id, &descriptor); CHKERRQ(ierr);
442 fieldName = descriptor->canonical_name;
443
444 // Get the number of local particles
445 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
446 LOG_ALLOW(LOCAL,LOG_INFO, "%d local particles found.\n", nLocal);
447
448 // Retrieve the swarm field pointer for the specified fieldName
449 ierr = DMSwarmGetField(swarm, fieldName, NULL, NULL, (void**)&fieldData); CHKERRQ(ierr);
450 LOG_ALLOW(LOCAL,LOG_DEBUG, "Retrieved field '%s'.\n", fieldName);
451
452 // Loop over all particles and update the field using the helper function
453 for (PetscInt p = 0; p < nLocal; p++) {
454 ierr = InitializeSwarmFieldValue(descriptor, p, fieldData); CHKERRQ(ierr);
455 PetscReal disp_data[descriptor->components];
456
457 for (PetscInt d = 0; d < descriptor->components; d++) {
458 disp_data[d] = fieldData[descriptor->components * p + d];
459 }
460 LOG_LOOP_ALLOW(LOCAL,LOG_VERBOSE,p, 100," Particle %d: %s[%d] = [%.6f, ...,%.6f].\n", p,fieldName,descriptor->components,disp_data[0],disp_data[descriptor->components-1]);
461 }
462
463 // Restore the swarm field pointer
464 ierr = DMSwarmRestoreField(swarm, fieldName, NULL, NULL, (void**)&fieldData); CHKERRQ(ierr);
465 LOG_ALLOW(LOCAL,LOG_INFO, "Initialization of field '%s' complete.\n", fieldName);
466
467
469
470 PetscFunctionReturn(0);
471}
static PetscErrorCode InitializeSwarmFieldValue(const ParticleFieldDescriptor *descriptor, PetscInt p, PetscReal *fieldData)
Assign one configured initial value to a swarm field entry.
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 
)

Internal helper implementation: AssignInitialPropertiesToSwarm().

Initializes all particle properties in the swarm.

Local to this translation unit.

Definition at line 480 of file ParticleSwarm.c.

489{
490 PetscErrorCode ierr;
491 PetscFunctionBeginUser;
492
494
495 SimCtx *simCtx = user->simCtx;
496
497 // --- 0. Input Validation ---
498 if (!user || !bboxlist || !rand_logic_i || !rand_logic_j || !rand_logic_k || !rand_phys_x || !rand_phys_y || !rand_phys_z) {
499 // Check all RNGs now as they are passed in
500 LOG_ALLOW(GLOBAL, LOG_ERROR, "Null user, bboxlist, or RNG pointer.\n");
501 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null input detected.");
502 }
503
504 LOG_ALLOW(GLOBAL, LOG_INFO, "Initializing swarm with %d particles per process. Mode: %s.\n",
505 particlesPerProcess, ParticleInitializationToString(simCtx->ParticleInitialization));
506
507 // --- 1. Parse BCS File for Inlet Information (if surface initialization) ---
509 simCtx->ParticleInitialization == PARTICLE_INIT_SURFACE_EDGES) { // Surface initialization
510 if(user->inletFaceDefined == PETSC_FALSE){
511 LOG_ALLOW(GLOBAL, LOG_ERROR, "Particle Initialization on inlet surface selected, but no INLET face was identified from bcs.dat. Cannot proceed.\n");
512 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "ParticleInitialization Mode 0 requires an INLET face to be defined in bcs.dat.");
513 }else{
514 LOG_ALLOW(GLOBAL, LOG_INFO, "After Parsing BCS file for Inlet, Inlet face = %s\n", BCFaceToString((BCFace)user->identifiedInletBCFace));
515 }
516 }
517
518 // --- 2. Initialize Basic Particle Properties (Position, PID, Cell IDs placeholder) ---
519 // The rand_logic_i/j/k are now passed directly.
520 // The rand_phys_x/y/z are passed but InitializeParticleBasicProperties (refactored version)
521 // will not use them for setting positions if all its paths use logical-to-physical mapping.
522 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Calling InitializeParticleBasicProperties.\n");
523 ierr = InitializeParticleBasicProperties(user, particlesPerProcess,
524 rand_logic_i, rand_logic_j, rand_logic_k,
525 bboxlist); // bboxlist passed along
526 CHKERRQ(ierr);
527 LOG_ALLOW(GLOBAL, LOG_INFO, "Successfully initialized basic particle properties.\n");
528
529 // Note: The logical RNGs (rand_logic_i/j/k) are NOT destroyed here.
530 // They were created externally (e.g., by InitializeLogicalSpaceRNGs) and
531 // should be destroyed externally (e.g., in FinalizeSwarmSetup).
532 // Same for rand_phys_x/y/z.
533
534 // --- 3. Initialize Other Swarm Fields (Velocity, Weight, Pressure, etc.) ---
535 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'velocity' field.\n");
536 ierr = AssignInitialFieldToSwarm(user, PARTICLE_FIELD_ID_VELOCITY); CHKERRQ(ierr);
537 LOG_ALLOW(LOCAL, LOG_INFO, "'velocity' field initialization complete.\n");
538
539 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'weight' field.\n");
540 ierr = AssignInitialFieldToSwarm(user, PARTICLE_FIELD_ID_WEIGHT); CHKERRQ(ierr); // Weight is a three-component field.
541 LOG_ALLOW(LOCAL, LOG_INFO, "'weight' field initialization complete.\n");
542
543 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'Diffusivity' field.\n");
544 ierr = AssignInitialFieldToSwarm(user, PARTICLE_FIELD_ID_DIFFUSIVITY); CHKERRQ(ierr);
545 LOG_ALLOW(GLOBAL, LOG_INFO, "'Diffusivity' field initialization complete.\n");
546
547 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'DiffusivityGradient' field.\n");
549 LOG_ALLOW(GLOBAL, LOG_INFO, "'DiffusivityGradient' field initialization complete.\n");
550
551 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Initializing 'Psi' (Scalar) field.\n");
552 ierr = AssignInitialFieldToSwarm(user, PARTICLE_FIELD_ID_PSI); CHKERRQ(ierr);
553 LOG_ALLOW(GLOBAL, LOG_INFO, "'P' field initialization complete.\n");
554
555 LOG_ALLOW(GLOBAL, LOG_INFO, "Successfully completed all swarm property initialization.\n");
556
557
559
560 PetscFunctionReturn(0);
561}
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.
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
@ PARTICLE_FIELD_ID_WEIGHT
@ PARTICLE_FIELD_ID_PSI
@ PARTICLE_FIELD_ID_DIFFUSIVITY_GRADIENT
@ PARTICLE_FIELD_ID_DIFFUSIVITY
@ PARTICLE_FIELD_ID_VELOCITY
PetscBool inletFaceDefined
Definition variables.h:932
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 
)

Implementation of DistributeParticles().

Distributes particles evenly across MPI processes, handling any remainders.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/ParticleSwarm.h.

See also
DistributeParticles()

Definition at line 572 of file ParticleSwarm.c.

572 {
573
574 PetscFunctionBeginUser;
575
577 // Calculate the base number of particles per process
578 *particlesPerProcess = numParticles / size;
579 *remainder = numParticles % size;
580
581 // Distribute the remainder particles to the first 'remainder' ranks
582 if (rank < *remainder) {
583 *particlesPerProcess += 1;
584 LOG_ALLOW_SYNC(GLOBAL,LOG_INFO,"Rank %d receives an extra particle. Total: %d\n", rank, *particlesPerProcess);
585 } else {
586 LOG_ALLOW_SYNC(GLOBAL,LOG_INFO, "Rank %d receives %d particles.\n", rank, *particlesPerProcess);
587 }
588
590 PetscFunctionReturn(0);
591}
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:253
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 
)

Implementation of FinalizeSwarmSetup().

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

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/ParticleSwarm.h.

See also
FinalizeSwarmSetup()

Definition at line 602 of file ParticleSwarm.c.

602 {
603 PetscErrorCode ierr; // Error code for PETSc functions
604 PetscFunctionBeginUser;
606 // Destroy random number generators to free resources
607 // Physical space
608 ierr = PetscRandomDestroy(randx); CHKERRQ(ierr);
609 ierr = PetscRandomDestroy(randy); CHKERRQ(ierr);
610 ierr = PetscRandomDestroy(randz); CHKERRQ(ierr);
611 // Logical space
612 ierr = PetscRandomDestroy(rand_logic_i); CHKERRQ(ierr);
613 ierr = PetscRandomDestroy(rand_logic_j); CHKERRQ(ierr);
614 ierr = PetscRandomDestroy(rand_logic_k); CHKERRQ(ierr);
615
616 LOG_ALLOW(LOCAL,LOG_DEBUG,"Destroyed all random number generators.\n");
617
619 PetscFunctionReturn(0);
620}
Here is the caller graph for this function:

◆ CreateParticleSwarm()

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

Internal helper implementation: CreateParticleSwarm().

Creates and initializes a Particle Swarm.

Local to this translation unit.

Definition at line 628 of file ParticleSwarm.c.

628 {
629 PetscErrorCode ierr; // PETSc error handling variable
630 (void)bboxlist;
631 PetscMPIInt rank, size; // Variables to store MPI rank and size
632 PetscInt remainder = 0; // Remainder of particles after division
633
634 PetscFunctionBeginUser;
636 // Validate input parameters
637 if (numParticles <= 0) {
638 LOG_ALLOW(GLOBAL,LOG_DEBUG, "Number of particles must be positive. Given: %d\n", numParticles);
640 return PETSC_ERR_ARG_OUTOFRANGE;
641 }
642
643 // Retrieve MPI rank and size
644 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
645 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
646 LOG_ALLOW(GLOBAL,LOG_INFO," Domain dimensions: [%.2f,%.2f],[%.2f,%.2f],[%.2f,%.2f] \n",
647 user->Min_X,user->Max_X,user->Min_Y,user->Max_Y, user->Min_Z,user->Max_Z);
648 LOG_ALLOW_SYNC(GLOBAL,LOG_DEBUG, "[Rank %d] Local Bounding Box: [%.2f,%.2f],[%.2f,%.2f],[%.2f,%.2f] \n",
649 rank,user->bbox.min_coords.x,user->bbox.max_coords.x,
650 user->bbox.min_coords.y,user->bbox.max_coords.y,
651 user->bbox.min_coords.z,user->bbox.max_coords.z);
652 // Distribute particles among MPI processes
653 ierr = DistributeParticles(numParticles, rank, size, particlesPerProcess, &remainder); CHKERRQ(ierr);
654
655 // Initialize the DMSwarm - creates the swarm, sets the type and dimension
656 ierr = InitializeSwarm(user); CHKERRQ(ierr);
657
658 if (user->da) {
659 ierr = DMSwarmSetCellDM(user->swarm, user->da); CHKERRQ(ierr);
660 LOG_ALLOW(LOCAL,LOG_INFO,"Associated DMSwarm with Cell DM (user->da).\n");
661 } else {
662 // If user->da is essential for your simulation logic with particles, this should be a fatal error.
663 LOG_ALLOW(GLOBAL, LOG_WARNING, "user->da (Cell DM for Swarm) is NULL. Cell-based swarm operations might fail.\n");
664 // SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "user->da (Cell DM) is NULL but required.");
665 }
666
667 // Register particle fields (position, velocity, CellID, weight, etc.)
668 ierr = RegisterParticleFields(user->swarm); CHKERRQ(ierr);
669
670 // Set the local number of particles for this rank and additional buffer for particle migration
671 ierr = DMSwarmSetLocalSizes(user->swarm, *particlesPerProcess, numParticles); CHKERRQ(ierr);
672 LOG_ALLOW(GLOBAL,LOG_INFO, "Set local swarm size: %d particles.\n", *particlesPerProcess);
673
674 // Optionally, LOG_ALLOW detailed DM info in debug mode
675 if (get_log_level() == LOG_DEBUG && is_function_allowed(__func__)) {
676 LOG_ALLOW(GLOBAL,LOG_DEBUG,"Viewing DMSwarm:\n");
677 ierr = DMView(user->swarm, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
678 }
679
680 LOG_ALLOW(GLOBAL,LOG_INFO, "Particle swarm creation and initialization complete.\n");
681
683 PetscFunctionReturn(0);
684}
PetscErrorCode DistributeParticles(PetscInt numParticles, PetscMPIInt rank, PetscMPIInt size, PetscInt *particlesPerProcess, PetscInt *remainder)
Implementation of DistributeParticles().
PetscErrorCode InitializeSwarm(UserCtx *user)
Implementation of InitializeSwarm().
PetscErrorCode RegisterParticleFields(DM swarm)
Implementation of RegisterParticleFields().
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:186
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:87
PetscReal Min_X
Definition variables.h:921
Cmpnts max_coords
Maximum x, y, z coordinates of the bounding box.
Definition variables.h:173
PetscReal Max_Y
Definition variables.h:921
Cmpnts min_coords
Minimum x, y, z coordinates of the bounding box.
Definition variables.h:172
PetscReal Min_Z
Definition variables.h:921
PetscReal Max_X
Definition variables.h:921
PetscReal Min_Y
Definition variables.h:921
BoundingBox bbox
Definition variables.h:922
PetscReal Max_Z
Definition variables.h:921
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,
PetscReal *  diffusivity,
Cmpnts diffusivitygradient,
PetscReal *  psi,
Particle particle 
)

Implementation of UnpackSwarmFields().

Initializes a Particle struct with data from DMSwarm fields.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/ParticleSwarm.h.

See also
UnpackSwarmFields()

Definition at line 700 of file ParticleSwarm.c.

702 {
703 PetscFunctionBeginUser;
704
706
707 PetscMPIInt rank;
708 PetscErrorCode ierr;
709
710 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
711
712 if (particle == NULL) {
713 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Output Particle pointer is NULL. \n");
714 }
715
716 // logging the start of particle initialization
717 LOG_ALLOW(LOCAL,LOG_DEBUG, "[Rank %d]Unpacking Particle [%d] with PID: %ld.\n",rank, i, PIDs[i]);
718
719 // Initialize PID
720 if(PIDs == NULL){
721 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input PIDs pointer is NULL.\n");
722 }
723 particle->PID = PIDs[i];
724 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] PID set to: %ld.\n", rank,i, particle->PID);
725
726 // Initialize weights
727 if(weights == NULL){
728 particle->weights.x = 1.0;
729 particle->weights.y = 1.0;
730 particle->weights.z = 1.0;
731 LOG_ALLOW(LOCAL,LOG_WARNING, "[Rank %d]Particle [%d] weights pointer is NULL. Defaulting weights to (1.0, 1.0, 1.0).\n", rank,i);
732 }else{
733 particle->weights.x = weights[3 * i];
734 particle->weights.y = weights[3 * i + 1];
735 particle->weights.z = weights[3 * i + 2];
736 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] weights set to: (%.6f, %.6f, %.6f).\n",
737 rank,i, particle->weights.x, particle->weights.y, particle->weights.z);
738 }
739 // Initialize locations
740 if(positions == NULL){
741 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input positions pointer is NULL.\n");
742 }
743 particle->loc.x = positions[3 * i];
744 particle->loc.y = positions[3 * i + 1];
745 particle->loc.z = positions[3 * i + 2];
746 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] location set to: (%.6f, %.6f, %.6f).\n",
747 rank,i, particle->loc.x, particle->loc.y, particle->loc.z);
748
749 // Initialize velocities (assuming default zero; modify if necessary)
750 if(velocities == NULL){
751 particle->vel.x = 0.0;
752 particle->vel.y = 0.0;
753 particle->vel.z = 0.0;
754 LOG_ALLOW(LOCAL,LOG_WARNING, "[Rank %d]Particle [%d] velocities pointer is NULL. Defaulting velocities to (0.0, 0.0, 0.0).\n", rank,i);
755 }else{
756 particle->vel.x = velocities[3 * i];
757 particle->vel.y = velocities[3 * i + 1];
758 particle->vel.z = velocities[3 * i + 2];
759 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] velocities unpacked to: [%.6f,%.6f,%.6f].\n",rank, i,particle->vel.x,particle->vel.y,particle->vel.z);
760 }
761
762 // Initialize diffusivity
763 if(diffusivity == NULL){
764 particle->diffusivity = 1.0; // Default diffusivity
765 }else{
766 particle->diffusivity = diffusivity[i];
767 }
768 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] diffusivity set to: %.6f.\n",rank,i, particle->diffusivity);
769
770 // Initialize diffusivity gradient
771 if(diffusivitygradient == NULL){
772 particle->diffusivitygradient.x = 0.0;
773 particle->diffusivitygradient.y = 0.0;
774 particle->diffusivitygradient.z = 0.0;
775 LOG_ALLOW(LOCAL,LOG_WARNING, "[Rank %d]Particle [%d] diffusivity gradient pointer is NULL. Defaulting to (0.0, 0.0, 0.0).\n", rank,i);
776 }else{
777 particle->diffusivitygradient.x = diffusivitygradient[i].x;
778 particle->diffusivitygradient.y = diffusivitygradient[i].y;
779 particle->diffusivitygradient.z = diffusivitygradient[i].z;
780 }
781 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] diffusivity gradient set to: (%.6f, %.6f, %.6f).\n", rank,i,particle->diffusivitygradient.x,particle->diffusivitygradient.y,particle->diffusivitygradient.z);
782
783 // Initialize psi
784 if(psi == NULL){
785 particle->psi = 0.0; // Default psi
786 }else{
787 particle->psi = psi[i];
788 }
789 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] psi set to: %.6f.\n",rank,i, particle->psi);
790
791 // Initialize cell indices
792 if(cellIndices == NULL){
793 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input cellIndices pointer is NULL.\n");
794 }
795 particle->cell[0] = cellIndices[3 * i];
796 particle->cell[1] = cellIndices[3 * i + 1];
797 particle->cell[2] = cellIndices[3 * i + 2];
798 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d]Particle [%d] cell indices set to: [%d, %d, %d].\n",rank,i, particle->cell[0], particle->cell[1], particle->cell[2]);
799
800 if(LocStatus == NULL){
801 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input LocStatus pointer is NULL.\n");
802 }
803 // Initialize location status
804 particle->location_status = (ParticleLocationStatus)LocStatus[i];
805 LOG_ALLOW(LOCAL,LOG_VERBOSE, "[Rank %d]Particle [%d] Status set to: %d.\n",rank, i, particle->location_status);
806
807 // The destination_rank is only set by the location search, not read from the swarm,
808 // so we initialize it to a known invalid state.
809 particle->destination_rank = MPI_PROC_NULL;
810
811 // logging the completion of particle initialization
812 LOG_ALLOW(LOCAL,LOG_DEBUG,"[Rank %d]Completed initialization of Particle [%d]. \n", rank,i);
813
814
816
817 PetscFunctionReturn(0);
818}
Cmpnts vel
Definition variables.h:186
PetscInt cell[3]
Definition variables.h:184
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Definition variables.h:137
Cmpnts diffusivitygradient
Definition variables.h:191
Cmpnts loc
Definition variables.h:185
PetscMPIInt destination_rank
Definition variables.h:189
ParticleLocationStatus location_status
Definition variables.h:188
PetscReal diffusivity
Definition variables.h:190
PetscReal psi
Definition variables.h:192
Cmpnts weights
Definition variables.h:187
PetscInt64 PID
Definition variables.h:183
Here is the caller graph for this function:

◆ UpdateSwarmFields()

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().

Updates DMSwarm data arrays from a Particle struct.

Local to this translation unit.

Definition at line 826 of file ParticleSwarm.c.

835{
836 PetscFunctionBeginUser;
838
839 if (!particle) {
840 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input Particle pointer is NULL.\n");
841 }
842
843 // --- 1. Position (x, y, z) ---
844 if (positions) {
845 positions[3 * i + 0] = particle->loc.x;
846 positions[3 * i + 1] = particle->loc.y;
847 positions[3 * i + 2] = particle->loc.z;
848 }
849
850 // --- 2. Velocity (u, v, w) ---
851 if (velocities) {
852 velocities[3 * i + 0] = particle->vel.x;
853 velocities[3 * i + 1] = particle->vel.y;
854 velocities[3 * i + 2] = particle->vel.z;
855 }
856
857 // --- 3. Weights (i, j, k) ---
858 if (weights) {
859 weights[3 * i + 0] = particle->weights.x;
860 weights[3 * i + 1] = particle->weights.y;
861 weights[3 * i + 2] = particle->weights.z;
862 }
863
864 // --- 4. Cell Indices (i, j, k) ---
865 if (cellIndices) {
866 cellIndices[3 * i + 0] = particle->cell[0];
867 cellIndices[3 * i + 1] = particle->cell[1];
868 cellIndices[3 * i + 2] = particle->cell[2];
869 }
870
871 // --- 5. Status ---
872 if (status) {
873 status[i] = (PetscInt)particle->location_status;
874 }
875
876 // --- 6. Diffusivity ---
877 if (diffusivity) {
878 diffusivity[i] = particle->diffusivity;
879 }
880
881 if(diffusivitygradient){
882 diffusivitygradient[i].x = particle->diffusivitygradient.x;
883 diffusivitygradient[i].y = particle->diffusivitygradient.y;
884 diffusivitygradient[i].z = particle->diffusivitygradient.z;
885 }
886 // --- 7. Psi ---
887 if (psi) {
888 psi[i] = particle->psi;
889 }
890
891 // LOG_LOOP_ALLOW(LOCAL, LOG_VERBOSE, i, 1000, "Updated fields for Particle [%d].\n", i);
892
894 PetscFunctionReturn(0);
895}
Here is the caller graph for this function:

◆ IsParticleInsideBoundingBox()

PetscBool IsParticleInsideBoundingBox ( const BoundingBox bbox,
const Particle particle 
)

Internal helper implementation: IsParticleInsideBoundingBox().

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

Local to this translation unit.

Definition at line 903 of file ParticleSwarm.c.

904{
905 PetscFunctionBeginUser;
907
908 // Validate input pointers
909 if (!bbox) {
910 // LOG_ALLOW error message and return PETSC_FALSE
911 LOG_ALLOW(LOCAL,LOG_ERROR, "Error - 'bbox' pointer is NULL.");
913 return PETSC_FALSE;
914 }
915 if (!particle) {
916 LOG_ALLOW(LOCAL,LOG_ERROR,"Error - 'particle' pointer is NULL.");
918 return PETSC_FALSE;
919 }
920
921 // Extract particle location and bounding box coordinates
922 const Cmpnts loc = particle->loc;
923 const Cmpnts min_coords = bbox->min_coords;
924 const Cmpnts max_coords = bbox->max_coords;
925
926 // LOG_ALLOW the particle location and bounding box coordinates for debugging
927 LOG_ALLOW_SYNC(LOCAL, LOG_VERBOSE, "Particle PID %ld location: (%.6f, %.6f, %.6f).\n",particle->PID, loc.x, loc.y, loc.z);
928 LOG_ALLOW_SYNC(LOCAL, LOG_VERBOSE, "BoundingBox min_coords: (%.6f, %.6f, %.6f), max_coords: (%.6f, %.6f, %.6f).\n",
929 min_coords.x, min_coords.y, min_coords.z, max_coords.x, max_coords.y, max_coords.z);
930
931 // Check if the particle's location is within the bounding box
932 if ((loc.x >= min_coords.x && loc.x <= max_coords.x) &&
933 (loc.y >= min_coords.y && loc.y <= max_coords.y) &&
934 (loc.z >= min_coords.z && loc.z <= max_coords.z)) {
935 // Particle is inside the bounding box
936 LOG_ALLOW_SYNC(LOCAL,LOG_VERBOSE, "Particle PID %ld is inside the bounding box.\n",particle->PID);
938 return PETSC_TRUE;
939 }
940
941 // Particle is outside the bounding box
942 LOG_ALLOW_SYNC(LOCAL, LOG_VERBOSE,"Particle PID %ld is outside the bounding box.\n",particle->PID);
944 return PETSC_FALSE;
945}
Here is the caller graph for this function:

◆ UpdateParticleWeights()

PetscErrorCode UpdateParticleWeights ( PetscReal *  d,
Particle particle 
)

Internal helper implementation: UpdateParticleWeights().

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

Local to this translation unit.

Definition at line 954 of file ParticleSwarm.c.

954 {
955
956 PetscFunctionBeginUser;
958
959 // Validate input pointers
960 if (!d || !particle) {
961 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
962 "Null pointer argument (d or particle).");
963 }
964
965
966 // Validate distances
967 for (PetscInt i = LEFT; i < NUM_FACES; i++) {
970 "face distance d[%d] = %f <= %f; "
971 "clamping to 1e-14 to avoid zero/negative.\n",
972 i, (double)d[i], INTERPOLATION_DISTANCE_TOLERANCE);
974 }
975 }
976
977 // LOG_ALLOW the input distances
979 "Calculating weights with distances: "
980 "[LEFT=%f, RIGHT=%f, BOTTOM=%f, TOP=%f, FRONT=%f, BACK=%f].\n",
981 d[LEFT], d[RIGHT], d[BOTTOM], d[TOP], d[FRONT], d[BACK]);
982
983 // Compute and update the particle's weights
984 particle->weights.x = d[LEFT] / (d[LEFT] + d[RIGHT]);
985 particle->weights.y = d[BOTTOM] / (d[BOTTOM] + d[TOP]);
986 particle->weights.z = d[BACK] / (d[FRONT] + d[BACK]);
987
988 // LOG_ALLOW the updated weights
990 "Updated particle weights: x=%f, y=%f, z=%f.\n",
991 particle->weights.x, particle->weights.y, particle->weights.z);
992
993
995 PetscFunctionReturn(0);
996}
#define INTERPOLATION_DISTANCE_TOLERANCE
@ TOP
Definition variables.h:147
@ FRONT
Definition variables.h:147
@ BOTTOM
Definition variables.h:147
@ BACK
Definition variables.h:147
@ LEFT
Definition variables.h:147
@ NUM_FACES
Definition variables.h:147
@ RIGHT
Definition variables.h:147
Here is the caller graph for this function:

◆ InitializeParticleSwarm()

PetscErrorCode InitializeParticleSwarm ( SimCtx simCtx)

Implementation of InitializeParticleSwarm().

High-level particle initialization orchestrator for a simulation run.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/ParticleSwarm.h.

See also
InitializeParticleSwarm()

Definition at line 1027 of file ParticleSwarm.c.

1028{
1029 PetscErrorCode ierr;
1030 PetscInt particlesPerProcess = 0;
1031 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1032
1033 PetscFunctionBeginUser;
1035
1036 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting particle swarm setup for %d particles.\n", simCtx->np);
1037
1038 // --- Phase 1: Create the DMSwarm Object (Always required) ---
1039 // This creates the container and registers the fields. It does not add particles yet.
1040 ierr = CreateParticleSwarm(user, simCtx->np, &particlesPerProcess, simCtx->bboxlist); CHKERRQ(ierr);
1041 LOG_ALLOW(GLOBAL, LOG_INFO, "DMSwarm object and fields created successfully.\n");
1042
1043
1044 // --- Phase 2: Decide whether to Initialize new particles or Load existing ones ---
1045 PetscBool should_initialize_new_particles = PETSC_FALSE;
1046 if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR){
1047 should_initialize_new_particles = PETSC_TRUE;
1048 }else{
1049 if (simCtx->StartStep == 0) {
1050 should_initialize_new_particles = PETSC_TRUE; // Standard fresh start
1051 } else {
1052 // It's a restart, so check the user's requested particle mode.
1053 if (strcmp(simCtx->particleRestartMode, "init") == 0) {
1054 should_initialize_new_particles = PETSC_TRUE; // User wants to re-initialize particles in a restarted flow.
1055 }
1056 }
1057 }
1058
1059 // --- Phase 3: Execute the chosen particle setup path ---
1060 if (should_initialize_new_particles) {
1061 // --- PATH A: Generate a fresh population of particles ---
1062 LOG_ALLOW(GLOBAL, LOG_INFO, "Mode: INITIALIZE. Generating new particle population.\n");
1063 PetscRandom randx, randy, randz;
1064 PetscRandom rand_logic_i, rand_logic_j, rand_logic_k;
1065
1066 ierr = InitializeRandomGenerators(user, &randx, &randy, &randz); CHKERRQ(ierr);
1067 ierr = InitializeLogicalSpaceRNGs(&rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1068 ierr = AssignInitialPropertiesToSwarm(user, particlesPerProcess, &randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k, simCtx->bboxlist); CHKERRQ(ierr);
1069 ierr = FinalizeSwarmSetup(&randx, &randy, &randz, &rand_logic_i, &rand_logic_j, &rand_logic_k); CHKERRQ(ierr);
1070
1071 } else {
1072 // --- PATH B: Load particle population from restart files ---
1073 // This path is only taken if simCtx->StartStep > 0 AND simCtx->particleRestartMode == "load"
1074 LOG_ALLOW(GLOBAL, LOG_INFO, "Mode: LOAD. Loading particle population from files for step %d.\n", simCtx->StartStep);
1075
1076 ierr = PreCheckAndResizeSwarm(user, simCtx->StartStep, "dat"); CHKERRQ(ierr);
1077
1078 ierr = ReadAllSwarmFields(user, simCtx->StartStep); CHKERRQ(ierr);
1079 // Note: We check for file-open errors inside ReadAllSwarmFields now.
1080
1081 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle data loaded. CellID and status are preserved from file.\n");
1082 }
1083
1084 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "Particle swarm setup complete.\n");
1085
1087 PetscFunctionReturn(0);
1088}
PetscErrorCode 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)
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 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().
PetscErrorCode ReadAllSwarmFields(UserCtx *user, PetscInt ti)
Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.
Definition io.c:1864
PetscErrorCode InitializeRandomGenerators(UserCtx *user, PetscRandom *randx, PetscRandom *randy, PetscRandom *randz)
Initializes random number generators for assigning particle properties.
Definition setup.c:3200
PetscErrorCode InitializeLogicalSpaceRNGs(PetscRandom *rand_logic_i, PetscRandom *rand_logic_j, PetscRandom *rand_logic_k)
Initializes random number generators for logical space operations [0.0, 1.0).
Definition setup.c:3241
UserCtx * user
Definition variables.h:571
UserMG usermg
Definition variables.h:852
PetscInt StartStep
Definition variables.h:705
char particleRestartMode[16]
Definition variables.h:833
BoundingBox * bboxlist
Definition variables.h:830
PetscInt mglevels
Definition variables.h:578
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:669
MGCtx * mgctx
Definition variables.h:581
ExecutionMode exec_mode
Definition variables.h:714
User-defined context containing data specific to a single computational grid level.
Definition variables.h:906
Here is the call graph for this function:
Here is the caller graph for this function: