22static const char *
const kParticleVariables[] = {
"x",
"y",
"z",
"t",
"xi",
"eta",
"zeta",
"L_xi",
"L_eta",
"L_zeta",
"pid"};
23#define PARTICLE_VARIABLE_PID ((PetscInt)PICURV_SOURCE_VAR_CELL_COUNT)
24#define PARTICLE_VARIABLE_COUNT (PARTICLE_VARIABLE_PID + 1)
25#define PARTICLE_FIELD_MAX_COMPONENTS 3
26#define PARTICLE_FIELD_EXPRESSION_LENGTH 4096
27#define PARTICLE_FIELD_HISTOGRAM_BINS 10
50 PetscBool found = PETSC_FALSE;
53 PetscFunctionBeginUser;
55 PetscCheck(plan, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Plan output is required.");
57 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_count", prefix));
58 PetscCall(PetscOptionsGetInt(NULL, NULL, option, &count, &found));
63 PetscCall(PetscNew(plan));
64 PetscCall(PetscCalloc1(count, &(*plan)->bindings));
65 (*plan)->count = count;
66 for (PetscInt i = 0; i < count; ++i) {
71 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_%" PetscInt_FMT
"_name", prefix, i));
72 PetscCall(PetscOptionsGetString(NULL, NULL, option, name,
sizeof(name), &found));
73 PetscCheck(found, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
"%s is missing.", option);
78 "Particle field '%s' cannot be given an initial value: the runtime sets it from the "
79 "Eulerian fields or from particle location.", name);
81 PETSC_COMM_WORLD, PETSC_ERR_PLIB,
"Settable particle field '%s' must be a real quantity.", name);
82 for (PetscInt j = 0; j < i; ++j) {
83 PetscCheck((*plan)->bindings[j].field != binding->
field, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
84 "Particle field '%s' is configured twice.", name);
88 "Particle field '%s' has more components than an initial value supports.", name);
89 for (PetscInt c = 0; c < binding->
components; ++c) {
92 PetscCall(PetscSNPrintf(option,
sizeof(option),
"-%s_%" PetscInt_FMT
"_expr_%" PetscInt_FMT, prefix, i, c));
93 PetscCall(PetscOptionsGetString(NULL, NULL, option, text,
sizeof(text), &found));
94 PetscCheck(found, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
"%s is missing.", option);
100 PetscFunctionReturn(0);
106 PetscFunctionBeginUser;
108 *reads = PETSC_FALSE;
109 for (PetscInt b = 0; b < plan->
count; ++b)
112 PetscBool uses = PETSC_FALSE;
114 if (uses) *reads = PETSC_TRUE;
117 PetscFunctionReturn(0);
128 const PetscReal *positions = NULL, *weights = NULL;
129 const PetscInt64 *pids = NULL;
130 const PetscInt *cells = NULL;
131 PetscBool grid_lines = PETSC_FALSE;
132 const Cmpnts ***frac = NULL, ***len = NULL, ***csi = NULL, ***eta = NULL, ***zet = NULL;
133 const PetscReal ***aj = NULL;
135 PetscFunctionBeginUser;
138 PetscCheck(user && event, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context and event are required.");
143 Vec fraction = NULL, length = NULL;
144 PetscCall(DMCreateGlobalVector(user->
fda, &fraction));
145 PetscCall(DMCreateGlobalVector(user->
fda, &length));
149 PetscCall(DMGlobalToLocalBegin(user->
fda, fraction, INSERT_VALUES, plan->
local_fraction));
150 PetscCall(DMGlobalToLocalEnd(user->
fda, fraction, INSERT_VALUES, plan->
local_fraction));
151 PetscCall(DMGlobalToLocalBegin(user->
fda, length, INSERT_VALUES, plan->
local_length));
152 PetscCall(DMGlobalToLocalEnd(user->
fda, length, INSERT_VALUES, plan->
local_length));
153 PetscCall(VecDestroy(&length));
154 PetscCall(VecDestroy(&fraction));
157 PetscCheck(user->
swarm, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Swarm is required.");
165 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
166 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
167 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
168 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
170 for (PetscInt b = 0; b < plan->
count; ++b) {
173 PetscReal *field = NULL, scale = 1.0;
178 PetscCall(DMSwarmGetField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
179 for (PetscInt p = first; p < end; ++p) {
180 const PetscReal *position = &positions[3 * p];
181 const Cmpnts point = {position[0], position[1], position[2]};
193 const PetscInt i = cells[3 * p] + 1, j = cells[3 * p + 1] + 1, k = cells[3 * p + 2] + 1;
194 const PetscReal lengths[3] = {len[k][j][i].x, len[k][j][i].y, len[k][j][i].z};
199 for (PetscInt a = 0; a < 3; ++a) {
200 const PetscReal ds = PetscSqrtReal(edges[a].x * edges[a].x + edges[a].y * edges[a].y + edges[a].z * edges[a].z);
206 for (PetscInt c = 0; c < binding->
components; ++c) {
207 PetscReal value = 0.0;
210 PetscCheck(!PetscIsInfOrNanReal(value), PETSC_COMM_SELF, PETSC_ERR_FP,
211 "The initial value of '%s' is not finite for particle %lld at (%g, %g, %g).",
212 descriptor->
canonical_name, (
long long)pids[p], (
double)values[0],
213 (
double)values[1], (
double)values[2]);
214 field[binding->
components * p + c] = value / scale;
217 PetscCall(DMSwarmRestoreField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
220 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
221 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
222 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
223 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
224 PetscCall(DMDAVecRestoreArrayRead(user->
fda, plan->
local_length, &len));
233 PetscFunctionReturn(0);
246 PetscFunctionBeginUser;
250 PetscCall(DMSwarmGetLocalSize(user->
swarm, &nlocal));
251 if (simCtx->
rank == 0) {
252 char path[PETSC_MAX_PATH_LEN];
254 PetscCall(PetscSNPrintf(path,
sizeof(path),
"%s/particle_initial_fields.csv", simCtx->
analysis_dir));
255 csv = fopen(path,
"w");
259 fprintf(csv,
"field,component,count,mean,variance,min,max");
265 for (PetscInt b = 0; b < plan->
count; ++b) {
268 const PetscReal *field = NULL;
269 PetscReal scale = 1.0;
273 PetscCall(DMSwarmGetField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
274 for (PetscInt c = 0; c < binding->
components; ++c) {
276 PetscReal sums[3] = {0.0, 0.0, 0.0}, extremes[2] = {PETSC_MAX_REAL, PETSC_MAX_REAL};
279 for (PetscInt p = 0; p < nlocal; ++p) {
280 const PetscReal value = field[binding->
components * p + c] * scale;
283 sums[2] += value * value;
284 extremes[0] = PetscMin(extremes[0], value);
285 extremes[1] = PetscMin(extremes[1], -value);
287 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, sums, 3, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
288 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, extremes, 2, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD));
289 const PetscReal count = sums[0], lowest = extremes[0], highest = -extremes[1];
290 const PetscReal mean = (count > 0.0) ? sums[1] / count : 0.0;
291 const PetscReal variance = (count > 0.0) ? PetscMax(sums[2] / count - mean * mean, 0.0) : 0.0;
294 for (PetscInt p = 0; p < nlocal; ++p) {
295 const PetscReal value = field[binding->
components * p + c] * scale;
296 PetscInt bin = (PetscInt)((value - lowest) / width);
302 "[Particle IC] %s[%" PetscInt_FMT
"]: n=%.0f mean=%.6g var=%.6g min=%.6g max=%.6g\n",
303 descriptor->
canonical_name, c, (
double)count, (
double)mean, (
double)variance,
304 (
double)(count > 0.0 ? lowest : 0.0), (
double)(count > 0.0 ? highest : 0.0));
306 fprintf(csv,
"%s,%d,%.0f,%.10e,%.10e,%.10e,%.10e", descriptor->
canonical_name, (
int)c,
307 (
double)count, (
double)mean, (
double)variance,
308 (
double)(count > 0.0 ? lowest : 0.0), (
double)(count > 0.0 ? highest : 0.0));
313 PetscCall(DMSwarmRestoreField(user->
swarm, descriptor->
canonical_name, NULL, NULL, (
void **)&field));
315 if (csv) fclose(csv);
317 PetscFunctionReturn(0);
326 PetscFunctionBeginUser;
329 for (PetscInt b = 0; b < (*plan)->count; ++b) {
334 PetscCall(VecDestroy(&(*plan)->local_length));
335 PetscCall(VecDestroy(&(*plan)->local_fraction));
336 PetscCall(PetscFree((*plan)->bindings));
337 PetscCall(PetscFree(*plan));
339 PetscFunctionReturn(0);
PetscErrorCode ComputeCellEdgeVectors(PetscReal ajc, Cmpnts csi, Cmpnts eta, Cmpnts zet, Cmpnts edges[3])
Computes a cell's edge vectors along its three grid directions.
PetscErrorCode ComputeGridLineFractions(UserCtx *user, Vec fraction, Vec length)
Arc-length position of every owned cell centre along its three grid lines.
static const char *const kParticleVariables[]
Names a particle expression may use: those of every source (PicurvSourceVariable),...
#define PARTICLE_VARIABLE_COUNT
#define PARTICLE_VARIABLE_PID
ParticleFieldBinding * bindings
PetscErrorCode ParticleFieldPlanSummarize(UserCtx *user, const ParticleFieldPlan *plan)
Implementation of ParticleFieldPlanSummarize().
#define PARTICLE_FIELD_MAX_COMPONENTS
static PetscErrorCode PlanReadsGridLines(const ParticleFieldPlan *plan, PetscBool *reads)
Whether any configured expression reads a grid line's fraction or length.
PetscErrorCode ParticleFieldPlanApply(UserCtx *user, ParticleFieldPlan *plan, const ParticleFieldEvent *event, PetscInt first, PetscInt end)
Implementation of ParticleFieldPlanApply().
#define PARTICLE_FIELD_HISTOGRAM_BINS
PicurvExpression * component[3]
Vec local_fraction
Grid-line fractions, computed once when an expression first reads them.
PetscErrorCode ParticleFieldPlanDestroy(ParticleFieldPlan **plan)
Implementation of ParticleFieldPlanDestroy().
PetscErrorCode ParticleFieldPlanCreate(const char *prefix, ParticleFieldPlan **plan)
Implementation of ParticleFieldPlanCreate().
Vec local_length
Grid-line lengths, likewise.
#define PARTICLE_FIELD_EXPRESSION_LENGTH
One configured field: its identity and one expression per component.
Configured initial values of particle-carried fields.
PetscInt64 salt
Event identity keying random draws: 0 for the t=0 population.
When and why a plan is applied.
PetscErrorCode PicurvExpressionEvaluate(const PicurvExpression *expression, const PetscReal *values, const PicurvExpressionDrawKey *key, PetscReal *result)
Evaluate a compiled expression.
PetscErrorCode PicurvExpressionDestroy(PicurvExpression **expression)
Free a compiled expression.
@ PICURV_SOURCE_VAR_L_ZETA
Physical length of that zeta grid line [m].
@ PICURV_SOURCE_VAR_XI
Arc-length fraction along the xi grid line, 0 at the - face.
@ PICURV_SOURCE_VAR_T
Physical time [s].
@ PICURV_SOURCE_VAR_Y
Physical y [m].
@ PICURV_SOURCE_VAR_X
Physical x of the point [m].
@ PICURV_SOURCE_VAR_Z
Physical z [m].
PetscErrorCode PicurvExpressionUsesVariable(const PicurvExpression *expression, PetscInt index, PetscBool *uses)
Whether a compiled expression reads one of its variables.
PetscErrorCode PicurvExpressionCompile(const char *text, const char *const *names, PetscInt name_count, PetscBool allow_random, PicurvExpression **expression)
Compile one expression against a list of variable names.
static void PicurvSourceSetVariables(PetscReal *values, Cmpnts point, Cmpnts fraction, Cmpnts length, PetscReal L_ref)
Fill a source's position and grid-line variables at one point.
What a random draw is keyed on, besides its stream.
@ FIELD_DIMENSION_FIXED
The exponents are the field's dimension.
PetscErrorCode FieldDimensionReferenceScale(const ScalingCtx *scaling, FieldDimension dimension, PetscReal *scale)
Return the factor that turns a solver value of one dimension into physical units.
Logging utilities and macros for PETSc-based applications.
#define GLOBAL
Scope for global logging across all processes.
#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_HELPER_BEGIN
Marks the beginning of a profiled helper: timed only when enabled by name.
#define PROFILE_HELPER_END
Alias of PROFILE_FUNCTION_END for a function that began with PROFILE_HELPER_BEGIN.
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
@ LOG_INFO
Informational messages about program execution.
@ LOG_WARNING
Non-critical issues that warrant attention.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled function: an always-on aggregate timer.
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
ParticleFieldId
Compile-time identity for a persistent solver-particle field.
@ PARTICLE_FIELD_ID_WEIGHT
@ PARTICLE_FIELD_ID_POSITION
@ PARTICLE_FIELD_ID_CELL_ID
@ PARTICLE_FIELD_ID_COUNT
unsigned int capabilities
PetscErrorCode ParticleFieldIdFromName(const char *field_name, ParticleFieldId *field_id)
Resolve a canonical name or registered alias at a text-ingress boundary.
@ PARTICLE_FIELD_CAPABILITY_USER_INITIALIZE
The particle carries the value, so a configured initial value survives: nothing re-derives it from th...
PetscErrorCode ParticleFieldGetDescriptor(ParticleFieldId field_id, const ParticleFieldDescriptor **descriptor)
Return immutable metadata for a valid particle field ID.
const char * canonical_name
Immutable metadata for one persistent particle field.
SimCtx * simCtx
Back-pointer to the master simulation context.
char analysis_dir[PETSC_MAX_PATH_LEN]
PetscInt particleRandomSeed
Base seed for every particle RNG stream (-particle_random_seed).
A 3D point or vector with PetscScalar components.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.