PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
postprocessing_kernels.h
Go to the documentation of this file.
1#ifndef POSTPROCESSING_KERNELS_H
2#define POSTPROCESSING_KERNELS_H
3
4#include "variables.h"
5#include "logging.h"
6#include "io.h" // For the UpdateLocalGhosts function prototype
7
8// Function prototypes for post-processing kernels
9
10/**
11 * @brief Interpolates a cell-centered field to nodal locations using local stencil averaging.
12 *
13 * The kernel reads the input field by name, computes nodal values, and stores the
14 * output in the named destination field. Both fields must already exist in the
15 * current `UserCtx`.
16 *
17 * @param[in,out] user Block-level context that owns the source and destination vectors.
18 * @param[in] in_field_name Name of the input field to sample.
19 * @param[in] out_field_name Name of the output field to populate.
20 * @return PetscErrorCode 0 on success.
21 */
22PetscErrorCode ComputeNodalAverage(UserCtx* user, const char* in_field_name, const char* out_field_name);
23
24/**
25 * @brief Populates the layout boundary of a field that was written on the interior only.
26 *
27 * @details This is **not** a boundary condition. It enforces no physics and satisfies no
28 * equation. It replicates the layout convention that boundary-condition
29 * application already gives solver state fields, so that stencil kernels —
30 * `ComputeNodalAverage()` above all — read defined values instead of the
31 * structural zeros an interior-only producer leaves behind.
32 *
33 * Fields written by `PicurvWindowDerive()` and `ComputeQCriterion()` cover only
34 * the physical interior, so their layout boundary holds zeros that mean "never
35 * written" rather than "zero". A node on the domain edge averages four such
36 * entries with four real cells and comes out at roughly half its true value.
37 * Solver state fields never need this: `Ucat`, `P`, `Nu_t`, and `CS` all carry
38 * boundary values written when their boundary conditions were applied.
39 *
40 * **Only periodic directions are handled.** There the correct value exists and
41 * is exact — the low dummy plane repeats the last physical plane and the high
42 * dummy plane repeats the first. On a non-periodic face the correct value
43 * depends on both the quantity and the boundary type, and no single convention
44 * serves a staging buffer that carries stresses, pressure, and eddy viscosity in
45 * turn; nothing is written there rather than something invented. The design for
46 * the non-periodic case is recorded in @ref 60_Field_Statistics_Planned_Extensions.
47 *
48 * Operates on the global vector, so it must run **before** the caller's
49 * `UpdateLocalGhosts()`, which then carries the written values into every local
50 * ghost region. Rank interfaces are that scatter's responsibility and are never
51 * touched here.
52 *
53 * Multi-block interface boundaries are out of scope.
54 *
55 * @param[in] user Block context supplying the DMDA layout and periodicity.
56 * @param[in,out] global Global vector whose layout boundary is populated.
57 * @param[in] components Degrees of freedom carried: 1 or 3.
58 * @return Zero on success, or `PETSC_ERR_ARG_NULL` for a null argument, or
59 * `PETSC_ERR_ARG_OUTOFRANGE` for an unsupported component count.
60 */
61PetscErrorCode ExtendToLayoutBoundary(UserCtx *user, Vec global, PetscInt components);
62
63/**
64 * @brief Computes the Q-criterion diagnostic from the local velocity-gradient tensor.
65 *
66 * This kernel evaluates rotational versus strain-rate dominance and writes the
67 * result into the configured Q-criterion output vector for visualization and flow
68 * feature identification.
69 *
70 * @param[in,out] user Block-level context containing velocity fields and target output storage.
71 * @return PetscErrorCode 0 on success.
72 */
73PetscErrorCode ComputeQCriterion(UserCtx* user);
74
75/**
76 * @brief Normalizes pressure using the value at the configured logical grid point.
77 *
78 * The owning rank reads the reference value, shares it collectively, and every
79 * rank subtracts it in-place from its distributed portion of the field.
80 *
81 * @param[in,out] user Block-level context containing pressure and reference configuration.
82 * @param[in] relative_field_name Name of the field to normalize.
83 * @return PetscErrorCode 0 on success.
84 */
85PetscErrorCode NormalizeRelativeField(UserCtx* user, const char* relative_field_name);
86
87// Add more post-processing kernel prototypes as needed
88// =========================================================================
89// Dimensionalization Kernels
90// =========================================================================
91/**
92 * @brief Scales a specified field from non-dimensional to dimensional units in-place.
93 *
94 * This function acts as a dispatcher. It takes the string name of a field,
95 * identifies the corresponding PETSc Vec object and the correct physical
96 * scaling factor (e.g., U_ref for velocity, P_ref for pressure), and then
97 * performs an in-place VecScale operation. It correctly handles the different
98 * physical dimensions of Cartesian velocity vs. contravariant volume flux.
99 *
100 * @param[in,out] user The UserCtx containing the PETSc Vecs to be modified.
101 * @param[in] field_name The case-insensitive string name of the field to dimensionalize
102 * (e.g., "Ucat", "P", "Ucont", "Coordinates", "ParticlePosition", "ParticleVelocity").
103 * @return PetscErrorCode
104 */
105PetscErrorCode DimensionalizeField(UserCtx *user, const char *field_name);
106
107/**
108 * @brief Orchestrates the dimensionalization of all relevant fields loaded from a file.
109 *
110 * This function is intended to be called in the post-processor immediately after
111 * all solver output has been read into memory. It calls DimensionalizeField() for each of the core
112 * physical quantities to convert the entire loaded state from non-dimensional to
113 * dimensional units, preparing it for analysis and visualization.
114 *
115 * @param[in,out] user The UserCtx containing all the fields to be dimensionalized.
116 * @return PetscErrorCode
117 */
118PetscErrorCode DimensionalizeAllLoadedFields(UserCtx *user);
119
120// ===========================================================================
121// Particle Post-Processing Kernels
122// ===========================================================================
123
124
125/**
126 * @brief Computes the specific kinetic energy (KE per unit mass) for each particle.
127 *
128 * This kernel calculates SKE = 0.5 * |velocity|^2. It requires that the
129 * velocity field exists and will populate the specific kinetic energy field.
130 * The output field must be registered before this kernel is called.
131 *
132 * @param user The UserCtx containing the DMSwarm.
133 * @param velocity_field The name of the input vector field for particle velocity.
134 * @param ske_field The name of the output scalar field to store specific KE.
135 * @return PetscErrorCode
136 */
137PetscErrorCode ComputeSpecificKE(UserCtx* user, const char* velocity_field, const char* ske_field);
138
139/**
140 * @brief Computes the displacement magnitude |r_i - r_0| for each particle (per-particle VTK kernel).
141 *
142 * Reference point r_0 = (simCtx->psrc_x, psrc_y, psrc_z). Writes the scalar displacement to
143 * post_swarm[disp_field]. This is a visualisation kernel only — use ComputeParticleMSD from
144 * particle_statistics.h for quantitative global statistics.
145 *
146 * @param user The UserCtx containing the DMSwarms.
147 * @param disp_field Name of the output scalar field in post_swarm.
148 * @return PetscErrorCode
149 */
150PetscErrorCode ComputeDisplacement(UserCtx *user, const char *disp_field);
151
152/**
153 * @brief Derives one accumulated statistic and converts it to nodal values.
154 *
155 * The counterpart of ComputeNodalAverage() for accumulated window state: it takes an
156 * index into a window's requested output set, normalizes the centered state behind
157 * it, and leaves the result in the shared post-processing staging field ready for
158 * output. The staging vectors are reused between calls, so a caller must consume the
159 * result before requesting the next one.
160 *
161 * Derived statistics are left non-dimensional even when `global_operations.dimensionalize`
162 * is set. A Reynolds stress scales as velocity squared and a co-moment as a product of
163 * two different scales, none of which the existing per-field scaling table expresses;
164 * silently applying a velocity scale would be wrong rather than merely incomplete.
165 *
166 * @param[in] user Block context holding the accumulators and staging fields.
167 * @param[in] window_index Window whose state is derived.
168 * @param[in] outputs Comma-separated output kinds the recipe requested.
169 * @param[in] output_index Index into that output set.
170 * @param[out] out_name Name of the derived field, window qualified.
171 * @param[in] name_size Capacity of @p out_name.
172 * @param[out] out_vec Nodal vector holding the result; borrowed, not owned.
173 * @param[out] out_components Component count of the result.
174 * @return Zero on success, or a PETSc error.
175 */
176PetscErrorCode ComputeWindowStatisticNodal(UserCtx *user, PetscInt window_index,
177 const char *outputs, PetscInt output_index,
178 char *out_name, size_t name_size,
179 Vec *out_vec, PetscInt *out_components);
180
181/**
182 * @brief Appends one convergence row for an accumulated window to its CSV history.
183 *
184 * The counterpart of ComputeParticleMSD() for Eulerian window state: it reduces the
185 * window to the few numbers that answer whether it has run long enough — sample
186 * count, total weight, represented time, the per-point valid-fraction range, and the
187 * mean turbulent kinetic energy — and appends them as one row per processed step.
188 * No single field snapshot can answer that question, which is why the history exists
189 * beside the field output rather than instead of it.
190 *
191 * The mean is taken over the fluid cells the window actually sampled. Cells outside
192 * the target domain, and cells a moving mask excluded, hold zeros that mean "never
193 * measured"; averaging over them would scale the result down by the fraction of the
194 * grid the window never covered.
195 *
196 * @param[in] user Block context holding the accumulators and staging fields.
197 * @param[in] window_index Window to summarize.
198 * @param[in] output_prefix Output path prefix; the window name and `.csv` are appended.
199 * @param[in] ti Step being processed, recorded as the row's key.
200 * @return Zero on success, or a PETSc error.
201 */
202PetscErrorCode ComputeWindowStatisticsSummary(UserCtx *user, PetscInt window_index,
203 const char *output_prefix, PetscInt ti);
204
205#endif // POSTPROCESSING_KERNELS_H
Public interface for data input/output routines.
Logging utilities and macros for PETSc-based applications.
PetscErrorCode ComputeQCriterion(UserCtx *user)
Computes the Q-criterion diagnostic from the local velocity-gradient tensor.
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 ExtendToLayoutBoundary(UserCtx *user, Vec global, PetscInt components)
Populates the layout boundary of a field that was written on the interior only.
PetscErrorCode ComputeDisplacement(UserCtx *user, const char *disp_field)
Computes the displacement magnitude |r_i - r_0| for each particle (per-particle VTK kernel).
PetscErrorCode NormalizeRelativeField(UserCtx *user, const char *relative_field_name)
Normalizes pressure using the value at the configured logical grid point.
PetscErrorCode ComputeWindowStatisticsSummary(UserCtx *user, PetscInt window_index, const char *output_prefix, PetscInt ti)
Appends one convergence row for an accumulated window to its CSV history.
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 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 ComputeWindowStatisticNodal(UserCtx *user, PetscInt window_index, const char *outputs, PetscInt output_index, char *out_name, size_t name_size, Vec *out_vec, PetscInt *out_components)
Derives one accumulated statistic and converts it to nodal values.
Main header file for a complex fluid dynamics solver.
User-defined context containing data specific to a single computational grid level.
Definition variables.h:906