PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Functions
particle_statistics.h File Reference

Global statistics kernels for the Statistics Pipeline. More...

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

Go to the source code of this file.

Functions

PetscErrorCode ComputeParticleMSD (UserCtx *user, const char *stats_prefix, PetscInt ti)
 Computes the mean-squared displacement (MSD) of a particle cloud.
 

Detailed Description

Global statistics kernels for the Statistics Pipeline.

These kernels compute global aggregate quantities via MPI reduction — they do NOT produce per-particle VTK data. Each kernel appends one CSV row per call and logs a one-line summary via LOG_INFO.

Output file convention: {stats_prefix}_{kernel_name}.csv All MPI_Allreduce operations are internal; file I/O is rank-0-only.

To add a new statistic:

  1. Implement PetscErrorCode ComputeXxx(UserCtx*, const char*, PetscInt) in src/particle_statistics.c
  2. Declare it below.
  3. Add one else-if in GlobalStatisticsPipeline() in src/postprocessor.c No other files need to change.

Definition in file particle_statistics.h.

Function Documentation

◆ ComputeParticleMSD()

PetscErrorCode ComputeParticleMSD ( UserCtx user,
const char *  stats_prefix,
PetscInt  ti 
)

Computes the mean-squared displacement (MSD) of a particle cloud.

Reference point r0 = (simCtx->psrc_x, psrc_y, psrc_z). Diffusivity D = 1 / (Re * Sc), time t = ti * dt. Computes MSD_x, MSD_y, MSD_z (isotropy check), MSD_total, r_rms, centre-of-mass drift, and fractions inside 1σ/2σ/3σ theoretical shells. Appends one row to {stats_prefix}_msd.csv; writes header on first call.

Parameters
userThe UserCtx containing the DMSwarm (user->swarm).
stats_prefixBase filename prefix (e.g. "brownian_stats").
tiCurrent time-step index.
Returns
PetscErrorCode

Computes the mean-squared displacement (MSD) of a particle cloud.

Local to this translation unit.

Definition at line 130 of file particle_statistics.c.

131{
132 PetscErrorCode ierr;
133 SimCtx *simCtx = user->simCtx;
134 PetscMPIInt rank;
135
136 PetscFunctionBeginUser;
138
139 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
140
141 /* ------------------------------------------------------------------ *
142 * Physics parameters *
143 * ------------------------------------------------------------------ */
144 const PetscReal Re = (simCtx->ren > 0.0) ? simCtx->ren : 1.0;
145 const PetscReal Sc = (simCtx->schmidt_number > 0.0) ? simCtx->schmidt_number : 1.0;
146 const PetscReal D = 1.0 / (Re * Sc);
147 const PetscReal t = (PetscReal)ti * simCtx->dt;
148 const PetscReal x0 = simCtx->psrc_x;
149 const PetscReal y0 = simCtx->psrc_y;
150 const PetscReal z0 = simCtx->psrc_z;
151
152 /* ------------------------------------------------------------------ *
153 * Pass 1: local accumulation *
154 * ------------------------------------------------------------------ */
155 PetscInt n_local;
156 const PetscReal (*pos_arr)[3];
157
158 ierr = DMSwarmGetLocalSize(user->swarm, &n_local); CHKERRQ(ierr);
159 ierr = DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
160
161 PetscReal local_sq_x = 0.0, local_sq_y = 0.0, local_sq_z = 0.0;
162 PetscReal local_sx = 0.0, local_sy = 0.0, local_sz = 0.0;
163
164 for (PetscInt p = 0; p < n_local; p++) {
165 const PetscReal dx = pos_arr[p][0] - x0;
166 const PetscReal dy = pos_arr[p][1] - y0;
167 const PetscReal dz = pos_arr[p][2] - z0;
168 local_sq_x += dx * dx;
169 local_sq_y += dy * dy;
170 local_sq_z += dz * dz;
171 local_sx += dx;
172 local_sy += dy;
173 local_sz += dz;
174 }
175
176 ierr = DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
177
178 /* ------------------------------------------------------------------ *
179 * MPI reduction — 7 doubles + count *
180 * ------------------------------------------------------------------ */
181 PetscReal local_buf[7] = { local_sq_x, local_sq_y, local_sq_z,
182 local_sx, local_sy, local_sz,
183 (PetscReal)n_local };
184 PetscReal global_buf[7] = {0};
185 ierr = MPI_Allreduce(local_buf, global_buf, 7, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
186
187 const PetscReal N_total = global_buf[6];
188 if (N_total < 1.0) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); } /* no particles */
189
190 const PetscReal MSD_x = global_buf[0] / N_total;
191 const PetscReal MSD_y = global_buf[1] / N_total;
192 const PetscReal MSD_z = global_buf[2] / N_total;
193 const PetscReal com_x = global_buf[3] / N_total;
194 const PetscReal com_y = global_buf[4] / N_total;
195 const PetscReal com_z = global_buf[5] / N_total;
196
197 const PetscReal MSD_total = MSD_x + MSD_y + MSD_z;
198 const PetscReal r_rms_meas = PetscSqrtReal(MSD_total);
199 const PetscReal r_theory = (t > 1e-300) ? PetscSqrtReal(6.0 * D * t) : 0.0;
200 const PetscReal rel_err_pct = (r_theory > 1e-12)
201 ? PetscAbsReal(r_rms_meas - r_theory) / r_theory * 100.0
202 : 0.0;
203
204 /* ------------------------------------------------------------------ *
205 * Pass 2: fraction inside σ-shells *
206 * ------------------------------------------------------------------ */
207 ierr = DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
208
209 PetscInt local_n1 = 0, local_n2 = 0, local_n3 = 0;
210 const PetscReal r1 = r_theory;
211 const PetscReal r2 = 2.0 * r_theory;
212 const PetscReal r3 = 3.0 * r_theory;
213
214 for (PetscInt p = 0; p < n_local; p++) {
215 const PetscReal dx = pos_arr[p][0] - x0;
216 const PetscReal dy = pos_arr[p][1] - y0;
217 const PetscReal dz = pos_arr[p][2] - z0;
218 const PetscReal r = PetscSqrtReal(dx*dx + dy*dy + dz*dz);
219 if (r < r1) local_n1++;
220 if (r < r2) local_n2++;
221 if (r < r3) local_n3++;
222 }
223
224 ierr = DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
225
226 PetscReal local_counts[3] = { (PetscReal)local_n1,
227 (PetscReal)local_n2,
228 (PetscReal)local_n3 };
229 PetscReal global_counts[3] = {0};
230 ierr = MPI_Allreduce(local_counts, global_counts, 3, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
231
232 const PetscReal frac_1s = global_counts[0] / N_total * 100.0;
233 const PetscReal frac_2s = global_counts[1] / N_total * 100.0;
234 const PetscReal frac_3s = global_counts[2] / N_total * 100.0;
235
236 /* ------------------------------------------------------------------ *
237 * Output: CSV + LOG_INFO (rank 0 only) *
238 * ------------------------------------------------------------------ */
239 if (rank == 0) {
240 char csv_path[PETSC_MAX_PATH_LEN];
241 char row_line[1024];
242 PetscSNPrintf(csv_path, sizeof(csv_path), "%s_msd.csv", stats_prefix);
243 PetscSNPrintf(
244 row_line,
245 sizeof(row_line),
246 "%d,%.6e,%.0f,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.4f,%.6e,%.6e,%.6e,%.2f,%.2f,%.2f\n",
247 (int)ti, t, N_total,
248 MSD_x, MSD_y, MSD_z, MSD_total,
249 r_rms_meas, r_theory, rel_err_pct,
250 com_x, com_y, com_z,
251 frac_1s, frac_2s, frac_3s
252 );
253 PetscCall(RewriteParticleMSDCSV(csv_path, ti, row_line));
254
256 "[MSD ti=%d t=%.4f] total=%.4e theory=%.4e err=%.2f%% | "
257 "fracs: %.1f/%.1f/%.1f%% | COM: (%.2e,%.2e,%.2e)\n",
258 (int)ti, t, MSD_total, r_theory * r_theory, rel_err_pct,
259 frac_1s, frac_2s, frac_3s,
260 com_x, com_y, com_z);
261 }
262
264 PetscFunctionReturn(0);
265}
#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: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
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_POSITION
static PetscErrorCode RewriteParticleMSDCSV(const char *csv_path, PetscInt ti, const char *row_line)
Rewrite the MSD CSV so the requested timestep appears exactly once.
PetscReal schmidt_number
Definition variables.h:787
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
PetscReal ren
Definition variables.h:744
PetscReal dt
Definition variables.h:710
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: