PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Data Structures | Typedefs | Functions
ParticleInitialConditions.h File Reference

Configured initial values of particle-carried fields. More...

#include "variables.h"
#include "particle_field_catalog.h"
#include "expression.h"
Include dependency graph for ParticleInitialConditions.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ParticleFieldEvent
 When and why a plan is applied. More...
 

Typedefs

typedef struct ParticleFieldPlan ParticleFieldPlan
 Compiled initial values for every configured particle field.
 

Functions

PetscErrorCode ParticleFieldPlanCreate (const char *prefix, ParticleFieldPlan **plan)
 Read a plan from the options database.
 
PetscErrorCode ParticleFieldPlanApply (UserCtx *user, ParticleFieldPlan *plan, const ParticleFieldEvent *event, PetscInt first, PetscInt end)
 Write the plan's values into swarm entries [first, end) of this rank.
 
PetscErrorCode ParticleFieldPlanSummarize (UserCtx *user, const ParticleFieldPlan *plan)
 Log and record the realized initial values of every planned field.
 
PetscErrorCode ParticleFieldPlanDestroy (ParticleFieldPlan **plan)
 Free a plan and its compiled expressions.
 

Detailed Description

Configured initial values of particle-carried fields.

A plan binds each configured particle field to one compiled expression per component. Expressions are written in physical units: x, y, z are physical coordinates, t is physical time, and a value is divided by its field's catalog reference scale when written. The plan is applied to a contiguous local range of swarm entries, so the t=0 population and, later, particles injected at a boundary share one path.

The expressions are compiled and evaluated by the shared engine in expression.h.

Definition in file ParticleInitialConditions.h.


Data Structure Documentation

◆ ParticleFieldEvent

struct ParticleFieldEvent

When and why a plan is applied.

Definition at line 29 of file ParticleInitialConditions.h.

Data Fields
PetscReal physical_time Time, in seconds, the evaluated particles appear at.
PetscInt64 salt Event identity keying random draws: 0 for the t=0 population.

Typedef Documentation

◆ ParticleFieldPlan

Compiled initial values for every configured particle field.

Definition at line 26 of file ParticleInitialConditions.h.

Function Documentation

◆ ParticleFieldPlanCreate()

PetscErrorCode ParticleFieldPlanCreate ( const char *  prefix,
ParticleFieldPlan **  plan 
)

Read a plan from the options database.

Reads -<prefix>_count, and for each field i, -<prefix>_<i>_name and one expression per component, -<prefix>_<i>_expr_<c>. Every named field must be a particle-carried field of the catalog (capability USER_INITIALIZE).

Parameters
[in]prefixOption prefix without its dash: particle_fields for the t=0 population, particle_inlet_<n>_fields for an inlet.
[out]planCompiled plan, or NULL when no field is configured.
Returns
Zero on success; PETSC_ERR_ARG_WRONG for an unknown or non-settable field or a malformed expression.

Read a plan from the options database.

See also
ParticleFieldPlanCreate()

Definition at line 47 of file ParticleInitialConditions.c.

48{
49 PetscInt count = 0;
50 PetscBool found = PETSC_FALSE;
51 char option[256];
52
53 PetscFunctionBeginUser;
55 PetscCheck(plan, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Plan output is required.");
56 *plan = NULL;
57 PetscCall(PetscSNPrintf(option, sizeof(option), "-%s_count", prefix));
58 PetscCall(PetscOptionsGetInt(NULL, NULL, option, &count, &found));
59 if (!found || count == 0) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
60 PetscCheck(count > 0 && count <= PARTICLE_FIELD_ID_COUNT, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
61 "%s must be between 0 and %d (got %" PetscInt_FMT ").", option, (int)PARTICLE_FIELD_ID_COUNT, count);
62
63 PetscCall(PetscNew(plan));
64 PetscCall(PetscCalloc1(count, &(*plan)->bindings));
65 (*plan)->count = count;
66 for (PetscInt i = 0; i < count; ++i) {
67 ParticleFieldBinding *binding = &(*plan)->bindings[i];
68 const ParticleFieldDescriptor *descriptor = NULL;
69 char name[64];
70
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);
74 PetscCall(ParticleFieldIdFromName(name, &binding->field));
75 PetscCall(ParticleFieldGetDescriptor(binding->field, &descriptor));
76 PetscCheck(descriptor->capabilities & PARTICLE_FIELD_CAPABILITY_USER_INITIALIZE, PETSC_COMM_WORLD,
77 PETSC_ERR_ARG_WRONG,
78 "Particle field '%s' cannot be given an initial value: the runtime sets it from the "
79 "Eulerian fields or from particle location.", name);
80 PetscCheck(descriptor->dimension.kind == FIELD_DIMENSION_FIXED && descriptor->data_type == PETSC_REAL,
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);
85 }
86 binding->components = descriptor->components;
87 PetscCheck(binding->components <= PARTICLE_FIELD_MAX_COMPONENTS, PETSC_COMM_WORLD, PETSC_ERR_PLIB,
88 "Particle field '%s' has more components than an initial value supports.", name);
89 for (PetscInt c = 0; c < binding->components; ++c) {
91
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);
96 &binding->component[c]));
97 }
98 }
100 PetscFunctionReturn(0);
101}
static const char *const kParticleVariables[]
Names a particle expression may use: those of every source (PicurvSourceVariable),...
#define PARTICLE_VARIABLE_COUNT
#define PARTICLE_FIELD_MAX_COMPONENTS
PicurvExpression * component[3]
#define PARTICLE_FIELD_EXPRESSION_LENGTH
One configured field: its identity and one expression per component.
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.
Definition expression.c:551
@ FIELD_DIMENSION_FIXED
The exponents are the field's dimension.
FieldDimensionKind kind
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:1029
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled function: an always-on aggregate timer.
Definition logging.h:1000
@ PARTICLE_FIELD_ID_COUNT
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.
Immutable metadata for one persistent particle field.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParticleFieldPlanApply()

PetscErrorCode ParticleFieldPlanApply ( UserCtx *  user,
ParticleFieldPlan *  plan,
const ParticleFieldEvent *  event,
PetscInt  first,
PetscInt  end 
)

Write the plan's values into swarm entries [first, end) of this rank.

Each rank evaluates its own entries. Every rank calls it even with an empty range: the first call that reads a grid line's fraction or length is collective, computing them once for the plan. Those expressions need each particle's cell and weights. A value that is not finite is an error naming the particle and its position.

Parameters
[in,out]userBlock owning the swarm.
[in]planPlan to apply; NULL does nothing.
[in]eventTime and identity of the event producing these particles.
[in]firstFirst local entry.
[in]endOne past the last local entry.
Returns
Zero on success.

Write the plan's values into swarm entries [first, end) of this rank.

See also
ParticleFieldPlanApply()

Definition at line 124 of file ParticleInitialConditions.c.

126{
127 SimCtx *simCtx = NULL;
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;
134
135 PetscFunctionBeginUser;
137 if (!plan) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
138 PetscCheck(user && event, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Context and event are required.");
139 simCtx = user->simCtx;
140 /* Before the empty-range return: the fractions are collective, and a rank may hold no particle. */
141 PetscCall(PlanReadsGridLines(plan, &grid_lines));
142 if (grid_lines && !plan->local_fraction) {
143 Vec fraction = NULL, length = NULL;
144 PetscCall(DMCreateGlobalVector(user->fda, &fraction));
145 PetscCall(DMCreateGlobalVector(user->fda, &length));
146 PetscCall(ComputeGridLineFractions(user, fraction, length));
147 PetscCall(DMCreateLocalVector(user->fda, &plan->local_fraction));
148 PetscCall(DMCreateLocalVector(user->fda, &plan->local_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));
155 }
156 if (end > first) {
157 PetscCheck(user->swarm, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Swarm is required.");
158 PetscCall(DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void **)&positions));
159 PetscCall(DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_PID), NULL, NULL, (void **)&pids));
160 if (grid_lines) {
161 PetscCall(DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_CELL_ID), NULL, NULL, (void **)&cells));
162 PetscCall(DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_WEIGHT), NULL, NULL, (void **)&weights));
163 PetscCall(DMDAVecGetArrayRead(user->fda, plan->local_fraction, &frac));
164 PetscCall(DMDAVecGetArrayRead(user->fda, plan->local_length, &len));
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));
169 }
170 for (PetscInt b = 0; b < plan->count; ++b) {
171 const ParticleFieldBinding *binding = &plan->bindings[b];
172 const ParticleFieldDescriptor *descriptor = NULL;
173 PetscReal *field = NULL, scale = 1.0;
174
175 PetscCall(ParticleFieldGetDescriptor(binding->field, &descriptor));
176 /* A value is physical; the swarm stores solver units. */
177 PetscCall(FieldDimensionReferenceScale(&simCtx->scaling, descriptor->dimension, &scale));
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]};
182 const PicurvExpressionDrawKey key = {
183 (PetscInt64)simCtx->particleRandomSeed, pids[p], event->salt, (PetscInt64)binding->field,
184 };
185 PetscReal values[PARTICLE_VARIABLE_COUNT] = {0.0};
186
187 values[PICURV_SOURCE_VAR_X] = position[0] * simCtx->scaling.L_ref;
188 values[PICURV_SOURCE_VAR_Y] = position[1] * simCtx->scaling.L_ref;
189 values[PICURV_SOURCE_VAR_Z] = position[2] * simCtx->scaling.L_ref;
190 if (grid_lines) {
191 /* The host cell in cell-centred numbering; a line's fraction is known at the
192 cell's centre, and moves with the particle by its share of the cell's edge. */
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};
195 Cmpnts edges[3];
196
197 PicurvSourceSetVariables(values, point, frac[k][j][i], len[k][j][i], simCtx->scaling.L_ref);
198 PetscCall(ComputeCellEdgeVectors(aj[k][j][i], csi[k][j][i], eta[k][j][i], zet[k][j][i], edges));
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);
201 values[PICURV_SOURCE_VAR_XI + a] += (weights[3 * p + a] - 0.5) * ds / lengths[a];
202 }
203 }
204 values[PICURV_SOURCE_VAR_T] = event->physical_time;
205 values[PARTICLE_VARIABLE_PID] = (PetscReal)pids[p];
206 for (PetscInt c = 0; c < binding->components; ++c) {
207 PetscReal value = 0.0;
208
209 PetscCall(PicurvExpressionEvaluate(binding->component[c], values, &key, &value));
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;
215 }
216 }
217 PetscCall(DMSwarmRestoreField(user->swarm, descriptor->canonical_name, NULL, NULL, (void **)&field));
218 }
219 if (grid_lines) {
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));
225 PetscCall(DMDAVecRestoreArrayRead(user->fda, plan->local_fraction, &frac));
226 PetscCall(DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_WEIGHT), NULL, NULL, (void **)&weights));
227 PetscCall(DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_CELL_ID), NULL, NULL, (void **)&cells));
228 }
229 PetscCall(DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_PID), NULL, NULL, (void **)&pids));
230 PetscCall(DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void **)&positions));
231 }
233 PetscFunctionReturn(0);
234}
PetscErrorCode ComputeCellEdgeVectors(PetscReal ajc, Cmpnts csi, Cmpnts eta, Cmpnts zet, Cmpnts edges[3])
Computes a cell's edge vectors along its three grid directions.
Definition Metric.c:749
PetscErrorCode ComputeGridLineFractions(UserCtx *user, Vec fraction, Vec length)
Arc-length position of every owned cell centre along its three grid lines.
Definition Metric.c:1362
#define PARTICLE_VARIABLE_PID
ParticleFieldBinding * bindings
static PetscErrorCode PlanReadsGridLines(const ParticleFieldPlan *plan, PetscBool *reads)
Whether any configured expression reads a grid line's fraction or length.
Vec local_fraction
Grid-line fractions, computed once when an expression first reads them.
Vec local_length
Grid-line lengths, likewise.
PetscInt64 salt
Event identity keying random draws: 0 for the t=0 population.
PetscErrorCode PicurvExpressionEvaluate(const PicurvExpression *expression, const PetscReal *values, const PicurvExpressionDrawKey *key, PetscReal *result)
Evaluate a compiled expression.
Definition expression.c:724
@ PICURV_SOURCE_VAR_XI
Arc-length fraction along the xi grid line, 0 at the - face.
Definition expression.h:163
@ PICURV_SOURCE_VAR_T
Physical time [s].
Definition expression.h:162
@ PICURV_SOURCE_VAR_Y
Physical y [m].
Definition expression.h:160
@ PICURV_SOURCE_VAR_X
Physical x of the point [m].
Definition expression.h:159
@ PICURV_SOURCE_VAR_Z
Physical z [m].
Definition expression.h:161
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.
Definition expression.h:252
What a random draw is keyed on, besides its stream.
Definition expression.h:85
PetscErrorCode FieldDimensionReferenceScale(const ScalingCtx *scaling, FieldDimension dimension, PetscReal *scale)
Return the factor that turns a solver value of one dimension into physical units.
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_WEIGHT
@ PARTICLE_FIELD_ID_POSITION
@ PARTICLE_FIELD_ID_PID
@ PARTICLE_FIELD_ID_CELL_ID
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:1160
PetscReal L_ref
Definition variables.h:898
ScalingCtx scaling
Definition variables.h:1003
PetscInt particleRandomSeed
Base seed for every particle RNG stream (-particle_random_seed).
Definition variables.h:1050
A 3D point or vector with PetscScalar components.
Definition variables.h:144
The master context for the entire simulation.
Definition variables.h:916
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParticleFieldPlanSummarize()

PetscErrorCode ParticleFieldPlanSummarize ( UserCtx *  user,
const ParticleFieldPlan *  plan 
)

Log and record the realized initial values of every planned field.

Collective. Reports count, mean, variance, minimum, maximum, and a ten-bin histogram per field component, in physical units, to the log and to particle_initial_fields.csv in the run's metrics directory.

Parameters
[in]userBlock owning the swarm.
[in]planPlan whose fields are summarized; NULL does nothing.
Returns
Zero on success.

Log and record the realized initial values of every planned field.

See also
ParticleFieldPlanSummarize()

Definition at line 240 of file ParticleInitialConditions.c.

241{
242 SimCtx *simCtx = NULL;
243 FILE *csv = NULL;
244 PetscInt nlocal = 0;
245
246 PetscFunctionBeginUser;
248 if (!plan) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
249 simCtx = user->simCtx;
250 PetscCall(DMSwarmGetLocalSize(user->swarm, &nlocal));
251 if (simCtx->rank == 0) {
252 char path[PETSC_MAX_PATH_LEN];
253
254 PetscCall(PetscSNPrintf(path, sizeof(path), "%s/particle_initial_fields.csv", simCtx->analysis_dir));
255 csv = fopen(path, "w");
256 if (!csv) {
257 LOG_ALLOW(GLOBAL, LOG_WARNING, "Could not write '%s'.\n", path);
258 } else {
259 fprintf(csv, "field,component,count,mean,variance,min,max");
260 for (int bin = 0; bin < PARTICLE_FIELD_HISTOGRAM_BINS; ++bin) fprintf(csv, ",bin_%d", bin);
261 fprintf(csv, "\n");
262 }
263 }
264
265 for (PetscInt b = 0; b < plan->count; ++b) {
266 const ParticleFieldBinding *binding = &plan->bindings[b];
267 const ParticleFieldDescriptor *descriptor = NULL;
268 const PetscReal *field = NULL;
269 PetscReal scale = 1.0;
270
271 PetscCall(ParticleFieldGetDescriptor(binding->field, &descriptor));
272 PetscCall(FieldDimensionReferenceScale(&simCtx->scaling, descriptor->dimension, &scale));
273 PetscCall(DMSwarmGetField(user->swarm, descriptor->canonical_name, NULL, NULL, (void **)&field));
274 for (PetscInt c = 0; c < binding->components; ++c) {
275 /* Sums and extremes in one reduction, then a histogram over the global range. */
276 PetscReal sums[3] = {0.0, 0.0, 0.0}, extremes[2] = {PETSC_MAX_REAL, PETSC_MAX_REAL};
277 PetscReal bins_local[PARTICLE_FIELD_HISTOGRAM_BINS] = {0.0}, bins[PARTICLE_FIELD_HISTOGRAM_BINS];
278
279 for (PetscInt p = 0; p < nlocal; ++p) {
280 const PetscReal value = field[binding->components * p + c] * scale;
281 sums[0] += 1.0;
282 sums[1] += value;
283 sums[2] += value * value;
284 extremes[0] = PetscMin(extremes[0], value);
285 extremes[1] = PetscMin(extremes[1], -value);
286 }
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;
292 const PetscReal width = (highest > lowest) ? (highest - lowest) / PARTICLE_FIELD_HISTOGRAM_BINS : 1.0;
293
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);
297 bins_local[PetscMax(0, PetscMin(bin, PARTICLE_FIELD_HISTOGRAM_BINS - 1))] += 1.0;
298 }
299 PetscCallMPI(MPI_Allreduce(bins_local, bins, PARTICLE_FIELD_HISTOGRAM_BINS, MPIU_REAL, MPI_SUM,
300 PETSC_COMM_WORLD));
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));
305 if (csv) {
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));
309 for (int bin = 0; bin < PARTICLE_FIELD_HISTOGRAM_BINS; ++bin) fprintf(csv, ",%.0f", (double)bins[bin]);
310 fprintf(csv, "\n");
311 }
312 }
313 PetscCall(DMSwarmRestoreField(user->swarm, descriptor->canonical_name, NULL, NULL, (void **)&field));
314 }
315 if (csv) fclose(csv);
317 PetscFunctionReturn(0);
318}
#define PARTICLE_FIELD_HISTOGRAM_BINS
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#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:214
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
PetscMPIInt rank
Definition variables.h:919
char analysis_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:942
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParticleFieldPlanDestroy()

PetscErrorCode ParticleFieldPlanDestroy ( ParticleFieldPlan **  plan)

Free a plan and its compiled expressions.

Parameters
[in,out]planPlan to free; set to NULL.
Returns
Zero on success.

Free a plan and its compiled expressions.

See also
ParticleFieldPlanDestroy()

Definition at line 324 of file ParticleInitialConditions.c.

325{
326 PetscFunctionBeginUser;
328 if (!plan || !*plan) { PROFILE_HELPER_END; PetscFunctionReturn(0); }
329 for (PetscInt b = 0; b < (*plan)->count; ++b) {
330 for (PetscInt c = 0; c < PARTICLE_FIELD_MAX_COMPONENTS; ++c) {
331 PetscCall(PicurvExpressionDestroy(&(*plan)->bindings[b].component[c]));
332 }
333 }
334 PetscCall(VecDestroy(&(*plan)->local_length));
335 PetscCall(VecDestroy(&(*plan)->local_fraction));
336 PetscCall(PetscFree((*plan)->bindings));
337 PetscCall(PetscFree(*plan));
339 PetscFunctionReturn(0);
340}
PetscErrorCode PicurvExpressionDestroy(PicurvExpression **expression)
Free a compiled expression.
Definition expression.c:818
#define PROFILE_HELPER_BEGIN
Marks the beginning of a profiled helper: timed only when enabled by name.
Definition logging.h:1014
#define PROFILE_HELPER_END
Alias of PROFILE_FUNCTION_END for a function that began with PROFILE_HELPER_BEGIN.
Definition logging.h:1033
Here is the call graph for this function:
Here is the caller graph for this function: