PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Functions
postprocessing_kernels.h File Reference
#include "variables.h"
#include "logging.h"
#include "io.h"
Include dependency graph for postprocessing_kernels.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

PetscErrorCode ComputeNodalAverage (UserCtx *user, const char *in_field_name, const char *out_field_name)
 Interpolates a cell-centered field to nodal locations using local stencil averaging.
 
PetscErrorCode ComputeQCriterion (UserCtx *user)
 Computes the Q-criterion diagnostic from the local velocity-gradient tensor.
 
PetscErrorCode NormalizeRelativeField (UserCtx *user, const char *relative_field_name)
 Normalizes a relative scalar field using the configured reference pressure scale.
 
PetscErrorCode DimensionalizeField (UserCtx *user, const char *field_name)
 Scales a specified field from non-dimensional to dimensional units in-place.
 
PetscErrorCode DimensionalizeAllLoadedFields (UserCtx *user)
 Orchestrates the dimensionalization of all relevant fields loaded from a file.
 
PetscErrorCode ComputeSpecificKE (UserCtx *user, const char *velocity_field, const char *ske_field)
 Computes the specific kinetic energy (KE per unit mass) for each particle.
 
PetscErrorCode ComputeDisplacement (UserCtx *user, const char *disp_field)
 Computes the displacement magnitude |r_i - r_0| for each particle (per-particle VTK kernel).
 

Function Documentation

◆ ComputeNodalAverage()

PetscErrorCode ComputeNodalAverage ( UserCtx user,
const char *  in_field_name,
const char *  out_field_name 
)

Interpolates a cell-centered field to nodal locations using local stencil averaging.

The kernel reads the input field by name, computes nodal values, and stores the output in the named destination field. Both fields must already exist in the current UserCtx.

Parameters
[in,out]userBlock-level context that owns the source and destination vectors.
[in]in_field_nameName of the input field to sample.
[in]out_field_nameName of the output field to populate.
Returns
PetscErrorCode 0 on success.

Interpolates a cell-centered field to nodal locations using local stencil averaging.

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

See also
ComputeNodalAverage()

Definition at line 139 of file postprocessing_kernels.c.

140{
141 PetscErrorCode ierr;
142 Vec in_vec_local = NULL, out_vec_global = NULL;
143 DM dm_in = NULL, dm_out = NULL;
144 PetscInt dof = 0;
145
146 PetscFunctionBeginUser;
148 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeNodalAverage on '%s' -> '%s'.\n", in_field_name, out_field_name);
149
150 // --- 1. Map string names to PETSc objects ---
151 if (strcasecmp(in_field_name, "P") == 0) { in_vec_local = user->lP; dm_in = user->da; dof = 1; }
152 else if (strcasecmp(in_field_name, "Ucat") == 0) { in_vec_local = user->lUcat; dm_in = user->fda; dof = 3; }
153 else if (strcasecmp(in_field_name, "Psi") == 0) { in_vec_local = user->lPsi; dm_in = user->da; dof = 1; }
154 // ... (add other fields as needed) ...
155 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown input field name for nodal averaging: %s", in_field_name);
156
157 if (strcasecmp(out_field_name, "P_nodal") == 0) { out_vec_global = user->P_nodal; dm_out = user->da; }
158 else if (strcasecmp(out_field_name, "Ucat_nodal") == 0) { out_vec_global = user->Ucat_nodal; dm_out = user->fda; }
159 else if (strcasecmp(out_field_name, "Psi_nodal") == 0) { out_vec_global = user->Psi_nodal; dm_out = user->da; }
160 // ... (add other fields as needed) ...
161 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown output field name for nodal averaging: %s", out_field_name);
162
163 // --- 2. Ensure Input Data Ghosts are Up-to-Date ---
164 ierr = UpdateLocalGhosts(user, in_field_name); CHKERRQ(ierr);
165
166 // --- 3. Get DMDA info and array pointers ---
167 DMDALocalInfo info;
168 ierr = DMDAGetLocalInfo(dm_out, &info); CHKERRQ(ierr);
169
170 if (dof == 1) { // --- Scalar Field Averaging ---
171 const PetscReal ***l_in_arr;
172 PetscReal ***g_out_arr;
173 ierr = DMDAVecGetArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
174 ierr = DMDAVecGetArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
175
176 // Loop over the output NODE locations. The loop bounds match the required
177 // size of the final subsampled grid.
178 for (PetscInt k = info.zs; k < info.zs + info.zm - 1; k++) {
179 for (PetscInt j = info.ys; j < info.ys + info.ym - 1; j++) {
180 for (PetscInt i = info.xs; i < info.xs + info.xm - 1; i++) {
181 g_out_arr[k][j][i] = 0.125 * (l_in_arr[k][j][i] + l_in_arr[k][j][i+1] +
182 l_in_arr[k][j+1][i] + l_in_arr[k][j+1][i+1] +
183 l_in_arr[k+1][j][i] + l_in_arr[k+1][j][i+1] +
184 l_in_arr[k+1][j+1][i] + l_in_arr[k+1][j+1][i+1]);
185 }
186 }
187 }
188 ierr = DMDAVecRestoreArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
189 ierr = DMDAVecRestoreArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
190
191 } else if (dof == 3) { // --- Vector Field Averaging ---
192 const Cmpnts ***l_in_arr;
193 Cmpnts ***g_out_arr;
194 ierr = DMDAVecGetArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
195 ierr = DMDAVecGetArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
196
197 for (PetscInt k = info.zs; k < info.zs + info.zm - 1; k++) {
198 for (PetscInt j = info.ys; j < info.ys + info.ym - 1; j++) {
199 for (PetscInt i = info.xs; i < info.xs + info.xm - 1; i++) {
200 g_out_arr[k][j][i].x = 0.125 * (l_in_arr[k][j][i].x + l_in_arr[k][j][i+1].x +
201 l_in_arr[k][j+1][i].x + l_in_arr[k][j+1][i+1].x +
202 l_in_arr[k+1][j][i].x + l_in_arr[k+1][j][i+1].x +
203 l_in_arr[k+1][j+1][i].x + l_in_arr[k+1][j+1][i+1].x);
204
205 g_out_arr[k][j][i].y = 0.125 * (l_in_arr[k][j][i].y + l_in_arr[k][j][i+1].y +
206 l_in_arr[k][j+1][i].y + l_in_arr[k][j+1][i+1].y +
207 l_in_arr[k+1][j][i].y + l_in_arr[k+1][j][i+1].y +
208 l_in_arr[k+1][j+1][i].y + l_in_arr[k+1][j+1][i+1].y);
209
210 g_out_arr[k][j][i].z = 0.125 * (l_in_arr[k][j][i].z + l_in_arr[k][j][i+1].z +
211 l_in_arr[k][j+1][i].z + l_in_arr[k][j+1][i+1].z +
212 l_in_arr[k+1][j][i].z + l_in_arr[k+1][j][i+1].z +
213 l_in_arr[k+1][j+1][i].z + l_in_arr[k+1][j+1][i+1].z);
214 }
215 }
216 }
217 ierr = DMDAVecRestoreArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
218 ierr = DMDAVecRestoreArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
219 }
221 PetscFunctionReturn(0);
222}
#define GLOBAL
Scope for global logging across all processes.
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:199
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:827
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:818
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1755
Vec P_nodal
Definition variables.h:957
Vec Ucat_nodal
Definition variables.h:958
Vec lPsi
Definition variables.h:953
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
Vec Psi_nodal
Definition variables.h:960
Vec lUcat
Definition variables.h:904
PetscScalar y
Definition variables.h:101
A 3D point or vector with PetscScalar components.
Definition variables.h:100
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeQCriterion()

PetscErrorCode ComputeQCriterion ( UserCtx user)

Computes the Q-criterion diagnostic from the local velocity-gradient tensor.

This kernel evaluates rotational versus strain-rate dominance and writes the result into the configured Q-criterion output vector for visualization and flow feature identification.

Parameters
[in,out]userBlock-level context containing velocity fields and target output storage.
Returns
PetscErrorCode 0 on success.

Computes the Q-criterion diagnostic from the local velocity-gradient tensor.

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

See also
ComputeQCriterion()

Definition at line 233 of file postprocessing_kernels.c.

234{
235 PetscErrorCode ierr;
236 DMDALocalInfo info;
237 const Cmpnts ***lucat, ***lcsi, ***leta, ***lzet;
238 const PetscReal***laj, ***lnvert;
239 PetscReal ***gq;
240
241 PetscFunctionBeginUser;
243 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeQCriterion.\n");
244
245 // --- 1. Ensure all required ghost values are up-to-date ---
246 ierr = UpdateLocalGhosts(user, "Ucat"); CHKERRQ(ierr);
247 ierr = UpdateLocalGhosts(user, "Csi"); CHKERRQ(ierr);
248 ierr = UpdateLocalGhosts(user, "Eta"); CHKERRQ(ierr);
249 ierr = UpdateLocalGhosts(user, "Zet"); CHKERRQ(ierr);
250 ierr = UpdateLocalGhosts(user, "Aj"); CHKERRQ(ierr);
251 ierr = UpdateLocalGhosts(user, "Nvert"); CHKERRQ(ierr);
252
253 // --- 2. Get DMDA info and array pointers ---
254 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
255
256 ierr = DMDAVecGetArrayRead(user->fda, user->lUcat, (void*)&lucat); CHKERRQ(ierr);
257 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (void*)&lcsi); CHKERRQ(ierr);
258 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (void*)&leta); CHKERRQ(ierr);
259 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (void*)&lzet); CHKERRQ(ierr);
260 ierr = DMDAVecGetArrayRead(user->da, user->lAj, (void*)&laj); CHKERRQ(ierr);
261 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (void*)&lnvert); CHKERRQ(ierr);
262 ierr = DMDAVecGetArray(user->da, user->Qcrit, (void*)&gq); CHKERRQ(ierr);
263
264 // --- 3. Define Loop Bounds for INTERIOR Cells ---
265 PetscInt i_start = (info.xs == 0) ? 1 : info.xs;
266 PetscInt i_end = (info.xs + info.xm == info.mx) ? info.mx - 1 : info.xs + info.xm;
267 PetscInt j_start = (info.ys == 0) ? 1 : info.ys;
268 PetscInt j_end = (info.ys + info.ym == info.my) ? info.my - 1 : info.ys + info.ym;
269 PetscInt k_start = (info.zs == 0) ? 1 : info.zs;
270 PetscInt k_end = (info.zs + info.zm == info.mz) ? info.mz - 1 : info.zs + info.zm;
271
272 // --- 4. Main Computation Loop ---
273 for (PetscInt k = k_start; k < k_end; k++) {
274 for (PetscInt j = j_start; j < j_end; j++) {
275 for (PetscInt i = i_start; i < i_end; i++) {
276
277 // Calculate velocity derivatives in computational space (central differences)
278 PetscReal uc = 0.5 * (lucat[k][j][i+1].x - lucat[k][j][i-1].x);
279 PetscReal vc = 0.5 * (lucat[k][j][i+1].y - lucat[k][j][i-1].y);
280 PetscReal wc = 0.5 * (lucat[k][j][i+1].z - lucat[k][j][i-1].z);
281
282 PetscReal ue = 0.5 * (lucat[k][j+1][i].x - lucat[k][j-1][i].x);
283 PetscReal ve = 0.5 * (lucat[k][j+1][i].y - lucat[k][j-1][i].y);
284 PetscReal we = 0.5 * (lucat[k][j+1][i].z - lucat[k][j-1][i].z);
285
286 PetscReal uz = 0.5 * (lucat[k+1][j][i].x - lucat[k-1][j][i].x);
287 PetscReal vz = 0.5 * (lucat[k+1][j][i].y - lucat[k-1][j][i].y);
288 PetscReal wz = 0.5 * (lucat[k+1][j][i].z - lucat[k-1][j][i].z);
289
290 // Average metrics to the cell center
291 PetscReal csi1 = 0.5 * (lcsi[k][j][i].x + lcsi[k][j][i-1].x) * laj[k][j][i];
292 PetscReal csi2 = 0.5 * (lcsi[k][j][i].y + lcsi[k][j][i-1].y) * laj[k][j][i];
293 PetscReal csi3 = 0.5 * (lcsi[k][j][i].z + lcsi[k][j][i-1].z) * laj[k][j][i];
294
295 PetscReal eta1 = 0.5 * (leta[k][j][i].x + leta[k][j-1][i].x) * laj[k][j][i];
296 PetscReal eta2 = 0.5 * (leta[k][j][i].y + leta[k][j-1][i].y) * laj[k][j][i];
297 PetscReal eta3 = 0.5 * (leta[k][j][i].z + leta[k][j-1][i].z) * laj[k][j][i];
298
299 PetscReal zet1 = 0.5 * (lzet[k][j][i].x + lzet[k-1][j][i].x) * laj[k][j][i];
300 PetscReal zet2 = 0.5 * (lzet[k][j][i].y + lzet[k-1][j][i].y) * laj[k][j][i];
301 PetscReal zet3 = 0.5 * (lzet[k][j][i].z + lzet[k-1][j][i].z) * laj[k][j][i];
302
303 // Calculate velocity gradient tensor components d_ij = du_i/dx_j
304 PetscReal d11 = uc * csi1 + ue * eta1 + uz * zet1;
305 PetscReal d12 = uc * csi2 + ue * eta2 + uz * zet2;
306 PetscReal d13 = uc * csi3 + ue * eta3 + uz * zet3;
307
308 PetscReal d21 = vc * csi1 + ve * eta1 + vz * zet1;
309 PetscReal d22 = vc * csi2 + ve * eta2 + vz * zet2;
310 PetscReal d23 = vc * csi3 + ve * eta3 + vz * zet3;
311
312 PetscReal d31 = wc * csi1 + we * eta1 + wz * zet1;
313 PetscReal d32 = wc * csi2 + we * eta2 + wz * zet2;
314 PetscReal d33 = wc * csi3 + we * eta3 + wz * zet3;
315
316 // Strain-Rate Tensor S_ij = 0.5 * (d_ij + d_ji)
317 PetscReal s11 = d11;
318 PetscReal s12 = 0.5 * (d12 + d21);
319 PetscReal s13 = 0.5 * (d13 + d31);
320 PetscReal s22 = d22;
321 PetscReal s23 = 0.5 * (d23 + d32);
322 PetscReal s33 = d33;
323
324 // Vorticity Tensor Omega_ij = 0.5 * (d_ij - d_ji)
325 PetscReal w12 = 0.5 * (d12 - d21);
326 PetscReal w13 = 0.5 * (d13 - d31);
327 PetscReal w23 = 0.5 * (d23 - d32);
328
329 // Squared norms of the tensors
330 PetscReal s_norm_sq = s11*s11 + s22*s22 + s33*s33 + 2.0*(s12*s12 + s13*s13 + s23*s23);
331 PetscReal w_norm_sq = 2.0 * (w12*w12 + w13*w13 + w23*w23);
332
333 gq[k][j][i] = 0.5 * (w_norm_sq - s_norm_sq);
334
335 if (lnvert[k][j][i] > 0.1) {
336 gq[k][j][i] = 0.0;
337 }
338 }
339 }
340 }
341
342 // --- 5. Restore arrays ---
343 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcat, (void*)&lucat); CHKERRQ(ierr);
344 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (void*)&lcsi); CHKERRQ(ierr);
345 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (void*)&leta); CHKERRQ(ierr);
346 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (void*)&lzet); CHKERRQ(ierr);
347 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, (void*)&laj); CHKERRQ(ierr);
348 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (void*)&lnvert); CHKERRQ(ierr);
349 ierr = DMDAVecRestoreArray(user->da, user->Qcrit, (void*)&gq); CHKERRQ(ierr);
350
352 PetscFunctionReturn(0);
353}
Vec lNvert
Definition variables.h:904
Vec lZet
Definition variables.h:927
Vec Qcrit
Definition variables.h:959
Vec lCsi
Definition variables.h:927
Vec lAj
Definition variables.h:927
Vec lEta
Definition variables.h:927
Here is the call graph for this function:
Here is the caller graph for this function:

◆ NormalizeRelativeField()

PetscErrorCode NormalizeRelativeField ( UserCtx user,
const char *  relative_field_name 
)

Normalizes a relative scalar field using the configured reference pressure scale.

This is primarily used for pressure-normalized outputs in post-processing. The operation is in-place on the selected field.

Parameters
[in,out]userBlock-level context containing scaling information.
[in]relative_field_nameName of the field to normalize.
Returns
PetscErrorCode 0 on success.

Normalizes a relative scalar field using the configured reference pressure scale.

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

See also
NormalizeRelativeField()

Definition at line 363 of file postprocessing_kernels.c.

364{
365 PetscErrorCode ierr;
366 Vec P_vec = NULL;
367 PetscMPIInt rank;
368 PetscInt ip=1, jp=1, kp=1; // Default reference point
369 PetscReal p_ref = 0.0;
370 PetscInt ref_point_global_idx[1];
371 PetscScalar ref_value_local[1];
372 IS is_from, is_to;
373 VecScatter scatter_ctx;
374 Vec ref_vec_seq;
375 PostProcessParams *pps = user->simCtx->pps;
376
377 // Fetch referenc point from pps.
378 ip = pps->reference[0];
379 jp = pps->reference[1];
380 kp = pps->reference[2];
381
382 PetscFunctionBeginUser;
384 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running NormalizeRelativeField on '%s'.\n", relative_field_name);
385
386 // --- 1. Map string argument to the PETSc Vec ---
387 if (strcasecmp(relative_field_name, "P") == 0) {
388 P_vec = user->P;
389 } else {
390 SETERRQ(PETSC_COMM_SELF, 1, "NormalizeRelativeField only supports the primary 'P' field , not '%s' currently.", relative_field_name);
391 }
392
393 // --- 2. Get reference point from options and calculate its global DA index ---
394 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
395
396 // Convert the (i,j,k) logical grid coordinates to the global 1D index used by the DMDA vector
397 ref_point_global_idx[0] = kp * (user->IM * user->JM) + jp * user->IM + ip;
398
399 // --- 3. Robustly Scatter the single reference value to rank 0 ---
400 // Create an Index Set (IS) for the source point (from the global vector)
401 ierr = ISCreateGeneral(PETSC_COMM_WORLD, 1, ref_point_global_idx, PETSC_COPY_VALUES, &is_from); CHKERRQ(ierr);
402
403 // Create a sequential vector on rank 0 to hold the result
404 ierr = VecCreateSeq(PETSC_COMM_SELF, 1, &ref_vec_seq); CHKERRQ(ierr);
405
406 // Create an Index Set for the destination point (index 0 of the new sequential vector)
407 PetscInt dest_idx[1] = {0};
408 ierr = ISCreateGeneral(PETSC_COMM_SELF, 1, dest_idx, PETSC_COPY_VALUES, &is_to); CHKERRQ(ierr);
409
410 // Create the scatter context and perform the scatter
411 ierr = VecScatterCreate(P_vec, is_from, ref_vec_seq, is_to, &scatter_ctx); CHKERRQ(ierr);
412 ierr = VecScatterBegin(scatter_ctx, P_vec, ref_vec_seq, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
413 ierr = VecScatterEnd(scatter_ctx, P_vec, ref_vec_seq, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
414
415 // On rank 0, get the value. On other ranks, this will do nothing.
416 if (rank == 0) {
417 ierr = VecGetValues(ref_vec_seq, 1, dest_idx, ref_value_local); CHKERRQ(ierr);
418 p_ref = ref_value_local[0];
419 LOG_ALLOW(LOCAL, LOG_DEBUG, "%s reference point (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ") has value %g.\n", relative_field_name, jp, kp, ip, p_ref);
420 }
421
422 // --- 4. Broadcast the reference value from rank 0 to all other processes ---
423 ierr = MPI_Bcast(&p_ref, 1, MPIU_REAL, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
424
425 // --- 5. Perform the normalization (in-place shift) on the full distributed vector ---
426 ierr = VecShift(P_vec, -p_ref); CHKERRQ(ierr);
427 LOG_ALLOW(GLOBAL, LOG_DEBUG, "%s field normalized by subtracting %g.\n", relative_field_name, p_ref);
428
429 // --- 6. Cleanup ---
430 ierr = ISDestroy(&is_from); CHKERRQ(ierr);
431 ierr = ISDestroy(&is_to); CHKERRQ(ierr);
432 ierr = VecScatterDestroy(&scatter_ctx); CHKERRQ(ierr);
433 ierr = VecDestroy(&ref_vec_seq); CHKERRQ(ierr);
434
436 PetscFunctionReturn(0);
437}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:879
PetscInt reference[3]
Definition variables.h:623
PetscInt JM
Definition variables.h:885
PostProcessParams * pps
Definition variables.h:860
PetscInt IM
Definition variables.h:885
Holds all configuration parameters for a post-processing run.
Definition variables.h:594
Here is the caller graph for this function:

◆ DimensionalizeField()

PetscErrorCode DimensionalizeField ( UserCtx user,
const char *  field_name 
)

Scales a specified field from non-dimensional to dimensional units in-place.

This function acts as a dispatcher. It takes the string name of a field, identifies the corresponding PETSc Vec object and the correct physical scaling factor (e.g., U_ref for velocity, P_ref for pressure), and then performs an in-place VecScale operation. It correctly handles the different physical dimensions of Cartesian velocity vs. contravariant volume flux.

Parameters
[in,out]userThe UserCtx containing the PETSc Vecs to be modified.
[in]field_nameThe case-insensitive string name of the field to dimensionalize (e.g., "Ucat", "P", "Ucont", "Coordinates", "ParticlePosition", "ParticleVelocity").
Returns
PetscErrorCode

Scales a specified field from non-dimensional to dimensional units in-place.

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

See also
DimensionalizeField()

Definition at line 12 of file postprocessing_kernels.c.

13{
14 PetscErrorCode ierr;
15 SimCtx *simCtx = user->simCtx;
16 Vec target_vec = NULL;
17 PetscReal scale_factor = 1.0;
18 char field_type[64] = "Unknown";
19 PetscBool is_swarm_field = PETSC_FALSE; // Flag for special swarm handling
20 const char *swarm_field_name = NULL; // Name of the field within the swarm
21
22 PetscFunctionBeginUser;
24 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx is NULL.");
25 if (!field_name) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "field_name is NULL.");
26
27 // --- 1. Identify the target Vec and the correct scaling factor ---
28 if (strcasecmp(field_name, "Ucat") == 0) {
29 target_vec = user->Ucat;
30 scale_factor = simCtx->scaling.U_ref;
31 strcpy(field_type, "Cartesian Velocity (L/T)");
32 } else if (strcasecmp(field_name, "Ucont") == 0) {
33 target_vec = user->Ucont;
34 scale_factor = simCtx->scaling.U_ref * simCtx->scaling.L_ref * simCtx->scaling.L_ref;
35 strcpy(field_type, "Contravariant Volume Flux (L^3/T)");
36 } else if (strcasecmp(field_name, "P") == 0) {
37 target_vec = user->P;
38 scale_factor = simCtx->scaling.P_ref;
39 strcpy(field_type, "Pressure (M L^-1 T^-2)");
40 } else if (strcasecmp(field_name, "Coordinates") == 0) {
41 ierr = DMGetCoordinates(user->da, &target_vec); CHKERRQ(ierr);
42 scale_factor = simCtx->scaling.L_ref;
43 strcpy(field_type, "Grid Coordinates (L)");
44 } else if (strcasecmp(field_name, "ParticlePosition") == 0) {
45 is_swarm_field = PETSC_TRUE;
46 swarm_field_name = "position";
47 scale_factor = simCtx->scaling.L_ref;
48 strcpy(field_type, "Particle Position (L)");
49 } else if (strcasecmp(field_name, "ParticleVelocity") == 0) {
50 is_swarm_field = PETSC_TRUE;
51 swarm_field_name = "velocity";
52 scale_factor = simCtx->scaling.U_ref;
53 strcpy(field_type, "Particle Velocity (L/T)");
54 } else {
55 LOG(GLOBAL, LOG_WARNING, "DimensionalizeField: Unknown or unhandled field_name '%s'. Field will not be scaled.\n", field_name);
57 PetscFunctionReturn(0);
58 }
59
60 // --- 2. Check for trivial scaling ---
61 if (PetscAbsReal(scale_factor - 1.0) < PETSC_MACHINE_EPSILON) {
62 LOG(GLOBAL, LOG_DEBUG, "DimensionalizeField: Scaling factor for '%s' is 1.0. Skipping operation.\n", field_name);
64 PetscFunctionReturn(0);
65 }
66
67 // --- 3. Perform the in-place scaling operation ---
68 LOG(GLOBAL, LOG_INFO, "Scaling '%s' field (%s) by factor %.4e.\n", field_name, field_type, scale_factor);
69
70 if (is_swarm_field) {
71 // Special handling for DMSwarm fields
72 ierr = DMSwarmCreateGlobalVectorFromField(user->swarm, swarm_field_name, &target_vec); CHKERRQ(ierr);
73 ierr = VecScale(target_vec, scale_factor); CHKERRQ(ierr);
74 ierr = DMSwarmDestroyGlobalVectorFromField(user->swarm, swarm_field_name, &target_vec); CHKERRQ(ierr);
75 } else {
76 // Standard handling for PETSc Vecs
77 if (target_vec) {
78 ierr = VecScale(target_vec, scale_factor); CHKERRQ(ierr);
79 } else {
80 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "Target vector for field '%s' was not found or is NULL.", field_name);
81 }
82 }
83
84 // --- 4. Post-scaling updates for special cases ---
85 if (strcasecmp(field_name, "Coordinates") == 0) {
86 ierr = UpdateLocalGhosts(user, "Coordinates"); CHKERRQ(ierr);
87 }
88
90 PetscFunctionReturn(0);
91}
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:83
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
PetscReal L_ref
Definition variables.h:666
Vec Ucont
Definition variables.h:904
Vec Ucat
Definition variables.h:904
ScalingCtx scaling
Definition variables.h:763
PetscReal P_ref
Definition variables.h:669
PetscReal U_ref
Definition variables.h:667
The master context for the entire simulation.
Definition variables.h:684
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DimensionalizeAllLoadedFields()

PetscErrorCode DimensionalizeAllLoadedFields ( UserCtx user)

Orchestrates the dimensionalization of all relevant fields loaded from a file.

This function is intended to be called in the post-processor immediately after all solver output has been read into memory. It calls DimensionalizeField() for each of the core physical quantities to convert the entire loaded state from non-dimensional to dimensional units, preparing it for analysis and visualization.

Parameters
[in,out]userThe UserCtx containing all the fields to be dimensionalized.
Returns
PetscErrorCode

Orchestrates the dimensionalization of all relevant fields loaded from a file.

Local to this translation unit.

Definition at line 99 of file postprocessing_kernels.c.

100{
101 PetscErrorCode ierr;
102 SimCtx *simCtx = user->simCtx;
103
104 PetscFunctionBeginUser;
106
107 LOG(GLOBAL, LOG_INFO, "--- Converting all loaded fields to dimensional units ---\n");
108
109 // Scale the grid itself first
110 ierr = DimensionalizeField(user, "Coordinates"); CHKERRQ(ierr);
111
112 // Scale primary fluid fields
113 ierr = DimensionalizeField(user, "Ucat"); CHKERRQ(ierr);
114 ierr = DimensionalizeField(user, "Ucont"); CHKERRQ(ierr);
115 ierr = DimensionalizeField(user, "P"); CHKERRQ(ierr);
116
117 // If particles are present, scale their fields
118 if (simCtx->np > 0 && user->swarm) {
119 ierr = DimensionalizeField(user, "ParticlePosition"); CHKERRQ(ierr);
120 ierr = DimensionalizeField(user, "ParticleVelocity"); CHKERRQ(ierr);
121 }
122
123 LOG(GLOBAL, LOG_INFO, "--- Field dimensionalization complete ---\n");
124
126 PetscFunctionReturn(0);
127}
PetscErrorCode DimensionalizeField(UserCtx *user, const char *field_name)
Implementation of DimensionalizeField().
PetscInt np
Definition variables.h:796
Here is the call graph for this function:

◆ ComputeSpecificKE()

PetscErrorCode ComputeSpecificKE ( UserCtx user,
const char *  velocity_field,
const char *  ske_field 
)

Computes the specific kinetic energy (KE per unit mass) for each particle.

This kernel calculates SKE = 0.5 * |velocity|^2. It requires that the velocity field exists and will populate the specific kinetic energy field. The output field must be registered before this kernel is called.

Parameters
userThe UserCtx containing the DMSwarm.
velocity_fieldThe name of the input vector field for particle velocity.
ske_fieldThe name of the output scalar field to store specific KE.
Returns
PetscErrorCode

Computes the specific kinetic energy (KE per unit mass) for each particle.

Local to this translation unit.

Definition at line 448 of file postprocessing_kernels.c.

449{
450 PetscErrorCode ierr;
451 PetscInt n_local;
452 const PetscScalar (*vel_arr)[3]; // Access velocity as array of 3-component vectors
453 PetscScalar *ske_arr;
454
455 PetscFunctionBeginUser;
457 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeSpecificKE ('%s' -> '%s').\n", velocity_field, ske_field);
458
459 // Get local data arrays from the DMSwarm
460 ierr = DMSwarmGetLocalSize(user->swarm, &n_local); CHKERRQ(ierr);
461 if (n_local == 0) PetscFunctionReturn(0);
462
463 // Get read-only access to velocity and write access to the output field
464 ierr = DMSwarmGetField(user->swarm, velocity_field, NULL, NULL, (void**)&vel_arr); CHKERRQ(ierr);
465 ierr = DMSwarmGetField(user->post_swarm, ske_field, NULL, NULL, (void**)&ske_arr); CHKERRQ(ierr);
466
467 // Main computation loop
468 for (PetscInt p = 0; p < n_local; p++) {
469 const PetscScalar u = vel_arr[p][0];
470 const PetscScalar v = vel_arr[p][1];
471 const PetscScalar w = vel_arr[p][2];
472 const PetscScalar vel_sq = u*u + v*v + w*w;
473 ske_arr[p] = 0.5 * vel_sq;
474 }
475
476 // Restore arrays
477 ierr = DMSwarmRestoreField(user->swarm, velocity_field, NULL, NULL, (void**)&vel_arr); CHKERRQ(ierr);
478 ierr = DMSwarmRestoreField(user->post_swarm, ske_field, NULL, NULL, (void**)&ske_arr); CHKERRQ(ierr);
479
481 PetscFunctionReturn(0);
482}
DM post_swarm
Definition variables.h:956
Here is the caller graph for this function:

◆ ComputeDisplacement()

PetscErrorCode ComputeDisplacement ( UserCtx user,
const char *  disp_field 
)

Computes the displacement magnitude |r_i - r_0| for each particle (per-particle VTK kernel).

Reference point r_0 = (simCtx->psrc_x, psrc_y, psrc_z). Writes the scalar displacement to post_swarm[disp_field]. This is a visualisation kernel only — use ComputeParticleMSD from particle_statistics.h for quantitative global statistics.

Parameters
userThe UserCtx containing the DMSwarms.
disp_fieldName of the output scalar field in post_swarm.
Returns
PetscErrorCode

Computes the displacement magnitude |r_i - r_0| for each particle (per-particle VTK kernel).

Local to this translation unit.

Definition at line 490 of file postprocessing_kernels.c.

491{
492 PetscErrorCode ierr;
493 PetscInt n_local;
494 const PetscReal (*pos_arr)[3];
495 PetscScalar *disp_out;
496 SimCtx *simCtx = user->simCtx;
497
498 PetscFunctionBeginUser;
500 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeDisplacement (-> '%s').\n", disp_field);
501
502 ierr = DMSwarmGetLocalSize(user->swarm, &n_local); CHKERRQ(ierr);
503 if (n_local == 0) PetscFunctionReturn(0);
504
505 const PetscReal x0 = simCtx->psrc_x;
506 const PetscReal y0 = simCtx->psrc_y;
507 const PetscReal z0 = simCtx->psrc_z;
508
509 ierr = DMSwarmGetField(user->swarm, "position", NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
510 ierr = DMSwarmGetField(user->post_swarm, disp_field, NULL, NULL, (void**)&disp_out); CHKERRQ(ierr);
511
512 for (PetscInt p = 0; p < n_local; p++) {
513 const PetscReal dx = pos_arr[p][0] - x0;
514 const PetscReal dy = pos_arr[p][1] - y0;
515 const PetscReal dz = pos_arr[p][2] - z0;
516 disp_out[p] = PetscSqrtReal(dx*dx + dy*dy + dz*dz);
517 }
518
519 ierr = DMSwarmRestoreField(user->swarm, "position", NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
520 ierr = DMSwarmRestoreField(user->post_swarm, disp_field, NULL, NULL, (void**)&disp_out); CHKERRQ(ierr);
521
523 PetscFunctionReturn(0);
524}
PetscReal psrc_x
Definition variables.h:762
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
Definition variables.h:762
PetscReal psrc_y
Definition variables.h:762
Here is the caller graph for this function: