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 143 of file postprocessing_kernels.c.

144{
145 PetscErrorCode ierr;
146 Vec in_vec_local = NULL, out_vec_global = NULL;
147 DM dm_in = NULL, dm_out = NULL;
148 PetscInt dof = 0;
149
150 PetscFunctionBeginUser;
152 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeNodalAverage on '%s' -> '%s'.\n", in_field_name, out_field_name);
153
154 // --- 1. Map string names to PETSc objects ---
155 if (strcasecmp(in_field_name, "P") == 0) { in_vec_local = user->lP; dm_in = user->da; dof = 1; }
156 else if (strcasecmp(in_field_name, "Ucat") == 0) { in_vec_local = user->lUcat; dm_in = user->fda; dof = 3; }
157 else if (strcasecmp(in_field_name, "Psi") == 0) { in_vec_local = user->lPsi; dm_in = user->da; dof = 1; }
158 // ... (add other fields as needed) ...
159 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown input field name for nodal averaging: %s", in_field_name);
160
161 if (strcasecmp(out_field_name, "P_nodal") == 0) { out_vec_global = user->P_nodal; dm_out = user->da; }
162 else if (strcasecmp(out_field_name, "Ucat_nodal") == 0) { out_vec_global = user->Ucat_nodal; dm_out = user->fda; }
163 else if (strcasecmp(out_field_name, "Psi_nodal") == 0) { out_vec_global = user->Psi_nodal; dm_out = user->da; }
164 // ... (add other fields as needed) ...
165 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown output field name for nodal averaging: %s", out_field_name);
166
167 // --- 2. Ensure Input Data Ghosts are Up-to-Date ---
168 ierr = UpdateLocalGhosts(user, in_field_name); CHKERRQ(ierr);
169
170 // --- 3. Get DMDA info and array pointers ---
171 DMDALocalInfo info;
172 ierr = DMDAGetLocalInfo(dm_out, &info); CHKERRQ(ierr);
173
174 if (dof == 1) { // --- Scalar Field Averaging ---
175 const PetscReal ***l_in_arr;
176 PetscReal ***g_out_arr;
177 ierr = DMDAVecGetArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
178 ierr = DMDAVecGetArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
179
180 // Loop over the output NODE locations. The loop bounds match the required
181 // size of the final subsampled grid.
182 for (PetscInt k = info.zs; k < info.zs + info.zm - 1; k++) {
183 for (PetscInt j = info.ys; j < info.ys + info.ym - 1; j++) {
184 for (PetscInt i = info.xs; i < info.xs + info.xm - 1; i++) {
185 g_out_arr[k][j][i] = 0.125 * (l_in_arr[k][j][i] + l_in_arr[k][j][i+1] +
186 l_in_arr[k][j+1][i] + l_in_arr[k][j+1][i+1] +
187 l_in_arr[k+1][j][i] + l_in_arr[k+1][j][i+1] +
188 l_in_arr[k+1][j+1][i] + l_in_arr[k+1][j+1][i+1]);
189 }
190 }
191 }
192 ierr = DMDAVecRestoreArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
193 ierr = DMDAVecRestoreArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
194
195 } else if (dof == 3) { // --- Vector Field Averaging ---
196 const Cmpnts ***l_in_arr;
197 Cmpnts ***g_out_arr;
198 ierr = DMDAVecGetArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
199 ierr = DMDAVecGetArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
200
201 for (PetscInt k = info.zs; k < info.zs + info.zm - 1; k++) {
202 for (PetscInt j = info.ys; j < info.ys + info.ym - 1; j++) {
203 for (PetscInt i = info.xs; i < info.xs + info.xm - 1; i++) {
204 g_out_arr[k][j][i].x = 0.125 * (l_in_arr[k][j][i].x + l_in_arr[k][j][i+1].x +
205 l_in_arr[k][j+1][i].x + l_in_arr[k][j+1][i+1].x +
206 l_in_arr[k+1][j][i].x + l_in_arr[k+1][j][i+1].x +
207 l_in_arr[k+1][j+1][i].x + l_in_arr[k+1][j+1][i+1].x);
208
209 g_out_arr[k][j][i].y = 0.125 * (l_in_arr[k][j][i].y + l_in_arr[k][j][i+1].y +
210 l_in_arr[k][j+1][i].y + l_in_arr[k][j+1][i+1].y +
211 l_in_arr[k+1][j][i].y + l_in_arr[k+1][j][i+1].y +
212 l_in_arr[k+1][j+1][i].y + l_in_arr[k+1][j+1][i+1].y);
213
214 g_out_arr[k][j][i].z = 0.125 * (l_in_arr[k][j][i].z + l_in_arr[k][j][i+1].z +
215 l_in_arr[k][j+1][i].z + l_in_arr[k][j+1][i+1].z +
216 l_in_arr[k+1][j][i].z + l_in_arr[k+1][j][i+1].z +
217 l_in_arr[k+1][j+1][i].z + l_in_arr[k+1][j+1][i+1].z);
218 }
219 }
220 }
221 ierr = DMDAVecRestoreArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
222 ierr = DMDAVecRestoreArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
223 }
225 PetscFunctionReturn(0);
226}
#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:779
@ 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:770
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1361
Vec P_nodal
Definition variables.h:887
Vec Ucat_nodal
Definition variables.h:888
Vec lPsi
Definition variables.h:883
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
Vec Psi_nodal
Definition variables.h:890
Vec lUcat
Definition variables.h:837
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 237 of file postprocessing_kernels.c.

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

368{
369 PetscErrorCode ierr;
370 Vec P_vec = NULL;
371 PetscMPIInt rank;
372 PetscInt ip=1, jp=1, kp=1; // Default reference point
373 PetscReal p_ref = 0.0;
374 PetscInt ref_point_global_idx[1];
375 PetscScalar ref_value_local[1];
376 IS is_from, is_to;
377 VecScatter scatter_ctx;
378 Vec ref_vec_seq;
379 PostProcessParams *pps = user->simCtx->pps;
380
381 // Fetch referenc point from pps.
382 ip = pps->reference[0];
383 jp = pps->reference[1];
384 kp = pps->reference[2];
385
386 PetscFunctionBeginUser;
388 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running NormalizeRelativeField on '%s'.\n", relative_field_name);
389
390 // --- 1. Map string argument to the PETSc Vec ---
391 if (strcasecmp(relative_field_name, "P") == 0) {
392 P_vec = user->P;
393 } else {
394 SETERRQ(PETSC_COMM_SELF, 1, "NormalizeRelativeField only supports the primary 'P' field , not '%s' currently.", relative_field_name);
395 }
396
397 // --- 2. Get reference point from options and calculate its global DA index ---
398 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
399
400 // Convert the (i,j,k) logical grid coordinates to the global 1D index used by the DMDA vector
401 ref_point_global_idx[0] = kp * (user->IM * user->JM) + jp * user->IM + ip;
402
403 // --- 3. Robustly Scatter the single reference value to rank 0 ---
404 // Create an Index Set (IS) for the source point (from the global vector)
405 ierr = ISCreateGeneral(PETSC_COMM_WORLD, 1, ref_point_global_idx, PETSC_COPY_VALUES, &is_from); CHKERRQ(ierr);
406
407 // Create a sequential vector on rank 0 to hold the result
408 ierr = VecCreateSeq(PETSC_COMM_SELF, 1, &ref_vec_seq); CHKERRQ(ierr);
409
410 // Create an Index Set for the destination point (index 0 of the new sequential vector)
411 PetscInt dest_idx[1] = {0};
412 ierr = ISCreateGeneral(PETSC_COMM_SELF, 1, dest_idx, PETSC_COPY_VALUES, &is_to); CHKERRQ(ierr);
413
414 // Create the scatter context and perform the scatter
415 ierr = VecScatterCreate(P_vec, is_from, ref_vec_seq, is_to, &scatter_ctx); CHKERRQ(ierr);
416 ierr = VecScatterBegin(scatter_ctx, P_vec, ref_vec_seq, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
417 ierr = VecScatterEnd(scatter_ctx, P_vec, ref_vec_seq, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
418
419 // On rank 0, get the value. On other ranks, this will do nothing.
420 if (rank == 0) {
421 ierr = VecGetValues(ref_vec_seq, 1, dest_idx, ref_value_local); CHKERRQ(ierr);
422 p_ref = ref_value_local[0];
423 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);
424 }
425
426 // --- 4. Broadcast the reference value from rank 0 to all other processes ---
427 ierr = MPI_Bcast(&p_ref, 1, MPIU_REAL, 0, PETSC_COMM_WORLD); CHKERRQ(ierr);
428
429 // --- 5. Perform the normalization (in-place shift) on the full distributed vector ---
430 ierr = VecShift(P_vec, -p_ref); CHKERRQ(ierr);
431 LOG_ALLOW(GLOBAL, LOG_DEBUG, "%s field normalized by subtracting %g.\n", relative_field_name, p_ref);
432
433 // --- 6. Cleanup ---
434 ierr = ISDestroy(&is_from); CHKERRQ(ierr);
435 ierr = ISDestroy(&is_to); CHKERRQ(ierr);
436 ierr = VecScatterDestroy(&scatter_ctx); CHKERRQ(ierr);
437 ierr = VecDestroy(&ref_vec_seq); CHKERRQ(ierr);
438
440 PetscFunctionReturn(0);
441}
#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:814
PetscInt reference[3]
Definition variables.h:582
PetscInt JM
Definition variables.h:820
PostProcessParams * pps
Definition variables.h:798
PetscInt IM
Definition variables.h:820
Holds all configuration parameters for a post-processing run.
Definition variables.h:553
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 Vec l_coords;
87 ierr = DMGetCoordinates(user->da, &target_vec); CHKERRQ(ierr); // Re-get the global vector
88 ierr = DMGetCoordinatesLocal(user->da, &l_coords); CHKERRQ(ierr);
89 ierr = DMGlobalToLocalBegin(user->fda, target_vec, INSERT_VALUES, l_coords); CHKERRQ(ierr);
90 ierr = DMGlobalToLocalEnd(user->fda, target_vec, INSERT_VALUES, l_coords); CHKERRQ(ierr);
91 }
92
94 PetscFunctionReturn(0);
95}
#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:625
Vec Ucont
Definition variables.h:837
Vec Ucat
Definition variables.h:837
ScalingCtx scaling
Definition variables.h:707
PetscReal P_ref
Definition variables.h:628
PetscReal U_ref
Definition variables.h:626
The master context for the entire simulation.
Definition variables.h:643
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 103 of file postprocessing_kernels.c.

104{
105 PetscErrorCode ierr;
106 SimCtx *simCtx = user->simCtx;
107
108 PetscFunctionBeginUser;
110
111 LOG(GLOBAL, LOG_INFO, "--- Converting all loaded fields to dimensional units ---\n");
112
113 // Scale the grid itself first
114 ierr = DimensionalizeField(user, "Coordinates"); CHKERRQ(ierr);
115
116 // Scale primary fluid fields
117 ierr = DimensionalizeField(user, "Ucat"); CHKERRQ(ierr);
118 ierr = DimensionalizeField(user, "Ucont"); CHKERRQ(ierr);
119 ierr = DimensionalizeField(user, "P"); CHKERRQ(ierr);
120
121 // If particles are present, scale their fields
122 if (simCtx->np > 0 && user->swarm) {
123 ierr = DimensionalizeField(user, "ParticlePosition"); CHKERRQ(ierr);
124 ierr = DimensionalizeField(user, "ParticleVelocity"); CHKERRQ(ierr);
125 }
126
127 LOG(GLOBAL, LOG_INFO, "--- Field dimensionalization complete ---\n");
128
130 PetscFunctionReturn(0);
131}
PetscErrorCode DimensionalizeField(UserCtx *user, const char *field_name)
Implementation of DimensionalizeField().
PetscInt np
Definition variables.h:739
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 452 of file postprocessing_kernels.c.

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

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