PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Macros | Functions
postprocessing_kernels.c File Reference
#include "postprocessing_kernels.h"
#include "statistics_accumulator.h"
#include "statistics_window.h"
#include "particle_field_catalog.h"
Include dependency graph for postprocessing_kernels.c:

Go to the source code of this file.

Macros

#define __FUNCT__   "DimensionalizeField"
 
#define __FUNCT__   "DimensionalizeAllLoadedFields"
 
#define __FUNCT__   "ExtendToLayoutBoundary"
 
#define __FUNCT__   "ComputeNodalAverage"
 
#define __FUNCT__   "ComputeWindowStatisticNodal"
 
#define __FUNCT__   "ComputeWindowStatisticsSummary"
 
#define __FUNCT__   "ComputeQCriterion"
 
#define __FUNCT__   "NormalizeRelativeField"
 
#define __FUNCT__   "ComputeSpecificKE"
 
#define __FUNCT__   "ComputeDisplacement"
 

Functions

PetscErrorCode DimensionalizeField (UserCtx *user, const char *field_name)
 Implementation of DimensionalizeField().
 
PetscErrorCode DimensionalizeAllLoadedFields (UserCtx *user)
 Internal helper implementation: DimensionalizeAllLoadedFields().
 
PetscErrorCode ExtendToLayoutBoundary (UserCtx *user, Vec global, PetscInt components)
 Implementation of ExtendToLayoutBoundary().
 
PetscErrorCode ComputeNodalAverage (UserCtx *user, const char *in_field_name, const char *out_field_name)
 Implementation of ComputeNodalAverage().
 
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)
 Implementation of ComputeWindowStatisticNodal().
 
PetscErrorCode ComputeWindowStatisticsSummary (UserCtx *user, PetscInt window_index, const char *output_prefix, PetscInt ti)
 Implementation of ComputeWindowStatisticsSummary().
 
PetscErrorCode ComputeQCriterion (UserCtx *user)
 Implementation of ComputeQCriterion().
 
PetscErrorCode NormalizeRelativeField (UserCtx *user, const char *relative_field_name)
 Implementation of NormalizeRelativeField().
 
PetscErrorCode ComputeSpecificKE (UserCtx *user, const char *velocity_field, const char *ske_field)
 Internal helper implementation: ComputeSpecificKE().
 
PetscErrorCode ComputeDisplacement (UserCtx *user, const char *disp_field)
 Internal helper implementation: ComputeDisplacement().
 

Macro Definition Documentation

◆ __FUNCT__ [1/10]

#define __FUNCT__   "DimensionalizeField"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [2/10]

#define __FUNCT__   "DimensionalizeAllLoadedFields"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [3/10]

#define __FUNCT__   "ExtendToLayoutBoundary"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [4/10]

#define __FUNCT__   "ComputeNodalAverage"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [5/10]

#define __FUNCT__   "ComputeWindowStatisticNodal"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [6/10]

#define __FUNCT__   "ComputeWindowStatisticsSummary"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [7/10]

#define __FUNCT__   "ComputeQCriterion"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [8/10]

#define __FUNCT__   "NormalizeRelativeField"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [9/10]

#define __FUNCT__   "ComputeSpecificKE"

Definition at line 8 of file postprocessing_kernels.c.

◆ __FUNCT__ [10/10]

#define __FUNCT__   "ComputeDisplacement"

Definition at line 8 of file postprocessing_kernels.c.

Function Documentation

◆ DimensionalizeField()

PetscErrorCode DimensionalizeField ( UserCtx user,
const char *  field_name 
)

Implementation of DimensionalizeField().

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

16{
17 PetscErrorCode ierr;
18 SimCtx *simCtx = user->simCtx;
19 Vec target_vec = NULL;
20 PetscReal scale_factor = 1.0;
21 char field_type[64] = "Unknown";
22 PetscBool is_swarm_field = PETSC_FALSE; // Flag for special swarm handling
23 const char *swarm_field_name = NULL; // Name of the field within the swarm
24
25 PetscFunctionBeginUser;
27 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx is NULL.");
28 if (!field_name) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "field_name is NULL.");
29
30 // --- 1. Identify the target Vec and the correct scaling factor ---
31 if (strcasecmp(field_name, "Ucat") == 0) {
32 target_vec = user->Ucat;
33 scale_factor = simCtx->scaling.U_ref;
34 strcpy(field_type, "Cartesian Velocity (L/T)");
35 } else if (strcasecmp(field_name, "Ucont") == 0) {
36 target_vec = user->Ucont;
37 scale_factor = simCtx->scaling.U_ref * simCtx->scaling.L_ref * simCtx->scaling.L_ref;
38 strcpy(field_type, "Contravariant Volume Flux (L^3/T)");
39 } else if (strcasecmp(field_name, "P") == 0) {
40 target_vec = user->P;
41 scale_factor = simCtx->scaling.P_ref;
42 strcpy(field_type, "Pressure (M L^-1 T^-2)");
43 } else if (strcasecmp(field_name, "Coordinates") == 0) {
44 ierr = DMGetCoordinates(user->da, &target_vec); CHKERRQ(ierr);
45 scale_factor = simCtx->scaling.L_ref;
46 strcpy(field_type, "Grid Coordinates (L)");
47 } else if (strcasecmp(field_name, "ParticlePosition") == 0) {
48 is_swarm_field = PETSC_TRUE;
49 swarm_field_name = "position";
50 scale_factor = simCtx->scaling.L_ref;
51 strcpy(field_type, "Particle Position (L)");
52 } else if (strcasecmp(field_name, "ParticleVelocity") == 0) {
53 is_swarm_field = PETSC_TRUE;
54 swarm_field_name = "velocity";
55 scale_factor = simCtx->scaling.U_ref;
56 strcpy(field_type, "Particle Velocity (L/T)");
57 } else {
58 LOG(GLOBAL, LOG_WARNING, "DimensionalizeField: Unknown or unhandled field_name '%s'. Field will not be scaled.\n", field_name);
60 PetscFunctionReturn(0);
61 }
62
63 // --- 2. Check for trivial scaling ---
64 if (PetscAbsReal(scale_factor - 1.0) < PETSC_MACHINE_EPSILON) {
65 LOG(GLOBAL, LOG_DEBUG, "DimensionalizeField: Scaling factor for '%s' is 1.0. Skipping operation.\n", field_name);
67 PetscFunctionReturn(0);
68 }
69
70 // --- 3. Perform the in-place scaling operation ---
71 LOG(GLOBAL, LOG_INFO, "Scaling '%s' field (%s) by factor %.4e.\n", field_name, field_type, scale_factor);
72
73 if (is_swarm_field) {
74 // Special handling for DMSwarm fields
75 ierr = DMSwarmCreateGlobalVectorFromField(user->swarm, swarm_field_name, &target_vec); CHKERRQ(ierr);
76 ierr = VecScale(target_vec, scale_factor); CHKERRQ(ierr);
77 ierr = DMSwarmDestroyGlobalVectorFromField(user->swarm, swarm_field_name, &target_vec); CHKERRQ(ierr);
78 } else {
79 // Standard handling for PETSc Vecs
80 if (target_vec) {
81 ierr = VecScale(target_vec, scale_factor); CHKERRQ(ierr);
82 } else {
83 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "Target vector for field '%s' was not found or is NULL.", field_name);
84 }
85 }
86
87 // --- 4. Post-scaling updates for special cases ---
88 if (strcasecmp(field_name, "Coordinates") == 0) {
89 ierr = UpdateLocalGhosts(user, FIELD_ID_COORDINATES); CHKERRQ(ierr);
90 }
91
93 PetscFunctionReturn(0);
94}
@ FIELD_ID_COORDINATES
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:859
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:84
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:850
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1838
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
PetscReal L_ref
Definition variables.h:677
Vec Ucont
Definition variables.h:939
Vec Ucat
Definition variables.h:939
ScalingCtx scaling
Definition variables.h:785
PetscReal P_ref
Definition variables.h:680
PetscReal U_ref
Definition variables.h:678
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:

◆ DimensionalizeAllLoadedFields()

PetscErrorCode DimensionalizeAllLoadedFields ( UserCtx user)

Internal helper implementation: DimensionalizeAllLoadedFields().

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

Local to this translation unit.

Definition at line 102 of file postprocessing_kernels.c.

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

◆ ExtendToLayoutBoundary()

PetscErrorCode ExtendToLayoutBoundary ( UserCtx user,
Vec  global,
PetscInt  components 
)

Implementation of ExtendToLayoutBoundary().

Populates the layout boundary of a field that was written on the interior only.

Full API contract is documented with the header declaration in include/postprocessing_kernels.h.

See also
ExtendToLayoutBoundary()

Definition at line 142 of file postprocessing_kernels.c.

143{
144 SimCtx *simCtx = NULL;
145 DM dm = NULL;
146 Vec local = NULL;
147 PetscInt periodic[3];
148
149 PetscFunctionBeginUser;
151 PetscCheck(user != NULL && global != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
152 "Context and field are required.");
153 PetscCheck(components == 1 || components == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
154 "ExtendToLayoutBoundary handles 1- or 3-component fields; got %d.", (int)components);
155 simCtx = user->simCtx;
156 dm = (components == 1) ? user->da : user->fda;
157
158 periodic[0] = simCtx->i_periodic;
159 periodic[1] = simCtx->j_periodic;
160 periodic[2] = simCtx->k_periodic;
161 if (!periodic[0] && !periodic[1] && !periodic[2]) {
162 /* Nothing is defined on a non-periodic layout boundary, so nothing is written.
163 * The boundary node keeps the value the producing kernel left there, and the
164 * spatial reductions that matter scientifically never read it. */
166 PetscFunctionReturn(0);
167 }
168
169 PetscCall(DMGetLocalVector(dm, &local));
170 /* One pass per periodic direction, each preceded by its own scatter. The order
171 * matters: after the i pass the i layout boundary carries data, so the j pass
172 * reading across it fills edges correctly, and the k pass then fills corners. */
173 for (PetscInt dir = 0; dir < 3; ++dir) {
174 DMDALocalInfo info;
175 const PetscReal ****source = NULL;
176 PetscReal ****target = NULL;
177 PetscInt extent = 0;
178
179 if (!periodic[dir]) continue;
180
181 PetscCall(DMGlobalToLocalBegin(dm, global, INSERT_VALUES, local));
182 PetscCall(DMGlobalToLocalEnd(dm, global, INSERT_VALUES, local));
183 PetscCall(DMDAGetLocalInfo(dm, &info));
184 extent = (dir == 0) ? info.mx : ((dir == 1) ? info.my : info.mz);
185
186 PetscCall(DMDAVecGetArrayDOFRead(dm, local, &source));
187 PetscCall(DMDAVecGetArrayDOF(dm, global, &target));
188 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
189 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
190 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
191 const PetscInt index = (dir == 0) ? i : ((dir == 1) ? j : k);
192 PetscInt ss = i, sj = j, sk = k;
193
194 /* The layout wraps one plane inside the DMDA extent: the low dummy
195 * plane repeats the last physical plane, and the high dummy plane
196 * repeats the first. PETSc's periodic ghosts supply both sources
197 * even when they live on another rank. */
198 if (index == 0) {
199 if (dir == 0) ss = extent - 2;
200 else if (dir == 1) sj = extent - 2;
201 else sk = extent - 2;
202 } else if (index == extent - 1) {
203 if (dir == 0) ss = extent + 1;
204 else if (dir == 1) sj = extent + 1;
205 else sk = extent + 1;
206 } else {
207 continue;
208 }
209 for (PetscInt c = 0; c < components; ++c) {
210 target[k][j][i][c] = source[sk][sj][ss][c];
211 }
212 }
213 }
214 }
215 PetscCall(DMDAVecRestoreArrayDOF(dm, global, &target));
216 PetscCall(DMDAVecRestoreArrayDOFRead(dm, local, &source));
217 }
218 PetscCall(DMRestoreLocalVector(dm, &local));
219
221 "-> KERNEL: Extended %d-component field across the periodic layout boundary "
222 "(i=%d, j=%d, k=%d).\n", (int)components,
223 (int)periodic[0], (int)periodic[1], (int)periodic[2]);
225 PetscFunctionReturn(0);
226}
#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
PetscInt k_periodic
Definition variables.h:791
PetscInt i_periodic
Definition variables.h:791
PetscInt j_periodic
Definition variables.h:791
Here is the caller graph for this function:

◆ ComputeNodalAverage()

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

Implementation of ComputeNodalAverage().

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

237{
238 PetscErrorCode ierr;
239 FieldId in_field_id;
240 Vec in_vec_local = NULL, out_vec_global = NULL;
241 DM dm_in = NULL, dm_out = NULL;
242 PetscInt dof = 0;
243
244 PetscFunctionBeginUser;
246 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeNodalAverage on '%s' -> '%s'.\n", in_field_name, out_field_name);
247
248 // --- 1. Map string names to PETSc objects ---
249 if (strcasecmp(in_field_name, "P") == 0) { in_vec_local = user->lP; dm_in = user->da; dof = 1; }
250 else if (strcasecmp(in_field_name, "Ucat") == 0) { in_vec_local = user->lUcat; dm_in = user->fda; dof = 3; }
251 else if (strcasecmp(in_field_name, "Psi") == 0) { in_vec_local = user->lPsi; dm_in = user->da; dof = 1; }
252 /* The staging pair carries derived statistics, which are config-counted and so
253 * cannot be named by a compile-time member of their own. */
254 else if (strcasecmp(in_field_name, "PostScalar") == 0) { in_vec_local = user->lPostScalar; dm_in = user->da; dof = 1; }
255 else if (strcasecmp(in_field_name, "PostVector") == 0) { in_vec_local = user->lPostVector; dm_in = user->fda; dof = 3; }
256 // ... (add other fields as needed) ...
257 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown input field name for nodal averaging: %s", in_field_name);
258
259 if (strcasecmp(out_field_name, "P_nodal") == 0) { out_vec_global = user->P_nodal; dm_out = user->da; }
260 else if (strcasecmp(out_field_name, "Ucat_nodal") == 0) { out_vec_global = user->Ucat_nodal; dm_out = user->fda; }
261 else if (strcasecmp(out_field_name, "Psi_nodal") == 0) { out_vec_global = user->Psi_nodal; dm_out = user->da; }
262 else if (strcasecmp(out_field_name, "PostScalarNodal") == 0) { out_vec_global = user->PostScalarNodal; dm_out = user->da; }
263 else if (strcasecmp(out_field_name, "PostVectorNodal") == 0) { out_vec_global = user->PostVectorNodal; dm_out = user->fda; }
264 // ... (add other fields as needed) ...
265 else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown output field name for nodal averaging: %s", out_field_name);
266
267 // --- 2. Ensure Input Data Ghosts are Up-to-Date ---
268 ierr = FieldIdFromName(in_field_name, &in_field_id); CHKERRQ(ierr);
269 ierr = UpdateLocalGhosts(user, in_field_id); CHKERRQ(ierr);
270
271 // --- 3. Get DMDA info and array pointers ---
272 DMDALocalInfo info;
273 ierr = DMDAGetLocalInfo(dm_out, &info); CHKERRQ(ierr);
274 /* Every owned output point is valid except the global high layout plane.
275 * A rank interface is not a boundary: its +1 source value is in the halo. */
276 const PetscInt i_end = PetscMin(info.xs + info.xm, info.mx - 1);
277 const PetscInt j_end = PetscMin(info.ys + info.ym, info.my - 1);
278 const PetscInt k_end = PetscMin(info.zs + info.zm, info.mz - 1);
279
280 if (dof == 1) { // --- Scalar Field Averaging ---
281 const PetscReal ***l_in_arr;
282 PetscReal ***g_out_arr;
283 ierr = DMDAVecGetArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
284 ierr = DMDAVecGetArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
285
286 // Loop over the output NODE locations. The loop bounds match the required
287 // size of the final subsampled grid.
288 for (PetscInt k = info.zs; k < k_end; k++) {
289 for (PetscInt j = info.ys; j < j_end; j++) {
290 for (PetscInt i = info.xs; i < i_end; i++) {
291 g_out_arr[k][j][i] = 0.125 * (l_in_arr[k][j][i] + l_in_arr[k][j][i+1] +
292 l_in_arr[k][j+1][i] + l_in_arr[k][j+1][i+1] +
293 l_in_arr[k+1][j][i] + l_in_arr[k+1][j][i+1] +
294 l_in_arr[k+1][j+1][i] + l_in_arr[k+1][j+1][i+1]);
295 }
296 }
297 }
298 ierr = DMDAVecRestoreArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
299 ierr = DMDAVecRestoreArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
300
301 } else if (dof == 3) { // --- Vector Field Averaging ---
302 const Cmpnts ***l_in_arr;
303 Cmpnts ***g_out_arr;
304 ierr = DMDAVecGetArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
305 ierr = DMDAVecGetArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
306
307 for (PetscInt k = info.zs; k < k_end; k++) {
308 for (PetscInt j = info.ys; j < j_end; j++) {
309 for (PetscInt i = info.xs; i < i_end; i++) {
310 g_out_arr[k][j][i].x = 0.125 * (l_in_arr[k][j][i].x + l_in_arr[k][j][i+1].x +
311 l_in_arr[k][j+1][i].x + l_in_arr[k][j+1][i+1].x +
312 l_in_arr[k+1][j][i].x + l_in_arr[k+1][j][i+1].x +
313 l_in_arr[k+1][j+1][i].x + l_in_arr[k+1][j+1][i+1].x);
314
315 g_out_arr[k][j][i].y = 0.125 * (l_in_arr[k][j][i].y + l_in_arr[k][j][i+1].y +
316 l_in_arr[k][j+1][i].y + l_in_arr[k][j+1][i+1].y +
317 l_in_arr[k+1][j][i].y + l_in_arr[k+1][j][i+1].y +
318 l_in_arr[k+1][j+1][i].y + l_in_arr[k+1][j+1][i+1].y);
319
320 g_out_arr[k][j][i].z = 0.125 * (l_in_arr[k][j][i].z + l_in_arr[k][j][i+1].z +
321 l_in_arr[k][j+1][i].z + l_in_arr[k][j+1][i+1].z +
322 l_in_arr[k+1][j][i].z + l_in_arr[k+1][j][i+1].z +
323 l_in_arr[k+1][j+1][i].z + l_in_arr[k+1][j+1][i+1].z);
324 }
325 }
326 }
327 ierr = DMDAVecRestoreArrayRead(dm_in,in_vec_local, (void*)&l_in_arr); CHKERRQ(ierr);
328 ierr = DMDAVecRestoreArray(dm_out,out_vec_global, (void*)&g_out_arr); CHKERRQ(ierr);
329 }
331 PetscFunctionReturn(0);
332}
PetscErrorCode FieldIdFromName(const char *field_name, FieldId *field_id)
Resolve a user-facing field name once into its typed identity.
FieldId
Compile-time identity for a catalogued Eulerian field.
Vec lPostScalar
Definition variables.h:959
Vec P_nodal
Definition variables.h:1001
Vec Ucat_nodal
Definition variables.h:1002
Vec lPsi
Definition variables.h:997
Vec PostScalarNodal
Definition variables.h:959
PetscScalar x
Definition variables.h:103
PetscScalar z
Definition variables.h:103
Vec PostVectorNodal
Definition variables.h:960
Vec Psi_nodal
Definition variables.h:1004
Vec lPostVector
Definition variables.h:960
Vec lUcat
Definition variables.h:939
PetscScalar y
Definition variables.h:103
A 3D point or vector with PetscScalar components.
Definition variables.h:102
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeWindowStatisticNodal()

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 
)

Implementation of ComputeWindowStatisticNodal().

Derives one accumulated statistic and converts it to nodal values.

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

See also
ComputeWindowStatisticNodal()

Definition at line 343 of file postprocessing_kernels.c.

347{
348 PetscErrorCode ierr;
349 SimCtx *simCtx = NULL;
350 PicurvDerivedField derived;
351 const PicurvWindowDefinition *definition = NULL;
352
353 PetscFunctionBeginUser;
355 PetscCheck(user != NULL && out_name != NULL && out_vec != NULL && out_components != NULL,
356 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Context and outputs are required.");
357 simCtx = user->simCtx;
358 PetscCheck(FieldStatisticsIsActive(simCtx) && user->fieldStatisticsStorage != NULL,
359 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
360 "No accumulated window state exists to derive.");
361 definition = &simCtx->fieldStatisticsWindows[window_index].definition;
362
363 /* Derive into the cell-centred staging pair, then reach the nodal path by
364 * catalogued name. A per-window accumulator has no compile-time offset, so
365 * staging is what lets the shared ghost and nodal kernels address it at all. */
366 ierr = PicurvWindowDerive(user, definition, &user->fieldStatisticsStorage[window_index],
367 outputs, output_index, user->PostScalar, user->PostVector,
368 &derived); CHKERRQ(ierr);
369 /* The derivation writes the physical interior only, so the layout boundary would
370 * otherwise reach the nodal average as structural zeros. Extend it before the
371 * ghost update, which then carries the written values outward. */
372 if (derived.components == 1) {
373 ierr = ExtendToLayoutBoundary(user, user->PostScalar, 1); CHKERRQ(ierr);
374 ierr = UpdateLocalGhosts(user, FIELD_ID_POST_SCALAR); CHKERRQ(ierr);
375 ierr = ComputeNodalAverage(user, "PostScalar", "PostScalarNodal"); CHKERRQ(ierr);
376 *out_vec = user->PostScalarNodal;
377 } else {
378 ierr = ExtendToLayoutBoundary(user, user->PostVector, 3); CHKERRQ(ierr);
379 ierr = UpdateLocalGhosts(user, FIELD_ID_POST_VECTOR); CHKERRQ(ierr);
380 ierr = ComputeNodalAverage(user, "PostVector", "PostVectorNodal"); CHKERRQ(ierr);
381 *out_vec = user->PostVectorNodal;
382 }
383 *out_components = derived.components;
384 ierr = PetscStrncpy(out_name, derived.name, name_size); CHKERRQ(ierr);
385
386 LOG_ALLOW(GLOBAL, LOG_DEBUG, "-> KERNEL: Derived '%s' (%d component(s)).\n",
387 out_name, (int)derived.components);
389 PetscFunctionReturn(0);
390}
@ FIELD_ID_POST_VECTOR
@ FIELD_ID_POST_SCALAR
PetscErrorCode ExtendToLayoutBoundary(UserCtx *user, Vec global, PetscInt components)
Implementation of ExtendToLayoutBoundary().
PetscErrorCode ComputeNodalAverage(UserCtx *user, const char *in_field_name, const char *out_field_name)
Implementation of ComputeNodalAverage().
PetscInt components
One or three.
char name[96]
Output field name, window qualified.
PetscErrorCode PicurvWindowDerive(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const char *outputs, PetscInt index, Vec scalar_target, Vec vector_target, PicurvDerivedField *field)
Derives one output field from centered accumulator state.
One derived output field, resolved by enumeration index.
PicurvWindowDefinition definition
PetscBool FieldStatisticsIsActive(const struct SimCtx *simCtx)
Reports whether this run has live field-statistics state.
The scientifically immutable definition of one window.
Vec PostScalar
Definition variables.h:959
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:771
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:962
Vec PostVector
Definition variables.h:960
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeWindowStatisticsSummary()

PetscErrorCode ComputeWindowStatisticsSummary ( UserCtx user,
PetscInt  window_index,
const char *  output_prefix,
PetscInt  ti 
)

Implementation of ComputeWindowStatisticsSummary().

Appends one convergence row for an accumulated window to its CSV history.

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

See also
ComputeWindowStatisticsSummary()

Definition at line 400 of file postprocessing_kernels.c.

402{
403 PetscErrorCode ierr;
404 SimCtx *simCtx = NULL;
405 const PicurvWindow *window = NULL;
406 const PicurvWindowStorage *storage = NULL;
407 PetscReal lowest = 1.0, highest = 0.0;
408 PetscReal mean_tke = 0.0;
409 PetscBool has_tke = PETSC_FALSE;
410 PetscInt derived_count = 0;
411 char path[PETSC_MAX_PATH_LEN];
412
413 PetscFunctionBeginUser;
415 PetscCheck(user != NULL && output_prefix != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
416 "Context and output prefix are required.");
417 simCtx = user->simCtx;
418 PetscCheck(FieldStatisticsIsActive(simCtx) && user->fieldStatisticsStorage != NULL,
419 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
420 "No accumulated window state exists to summarize.");
421 window = &simCtx->fieldStatisticsWindows[window_index];
422 storage = &user->fieldStatisticsStorage[window_index];
423
424 ierr = PicurvWindowValidFractionRange(user, &window->definition, storage,
425 window->sample_count, &lowest, &highest); CHKERRQ(ierr);
426
427 /* A single domain number is what makes the row plottable against step. It is
428 * produced by the same derivation the field output uses, so the scalar and the
429 * field can never disagree about what the window holds. */
430 ierr = PicurvWindowDerivedCount(&window->definition, storage, "tke", &derived_count); CHKERRQ(ierr);
431 if (derived_count > 0) {
432 PicurvDerivedField derived;
433
434 ierr = PicurvWindowDerive(user, &window->definition, storage, "tke", 0,
435 user->PostScalar, user->PostVector, &derived); CHKERRQ(ierr);
436 /* Averaged over the fluid cells the window actually sampled. A whole-vector
437 * mean would divide by boundary and dummy entries the derivation never
438 * writes, scaling the answer down by the fraction it never covered. */
439 ierr = PicurvWindowSpatialMean(user, &window->definition, storage,
440 user->PostScalar, &mean_tke); CHKERRQ(ierr);
441 has_tke = PETSC_TRUE;
442 }
443
444 if (simCtx->rank == 0) {
445 FILE *csv = NULL;
446 PetscBool exists = PETSC_FALSE;
447
448 ierr = PetscSNPrintf(path, sizeof(path), "%s_statistics_%s.csv",
449 output_prefix, window->definition.name); CHKERRQ(ierr);
450 ierr = PetscTestFile(path, 'r', &exists); CHKERRQ(ierr);
451 csv = fopen(path, exists ? "a" : "w");
452 PetscCheck(csv != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
453 "Unable to open statistics summary '%s'.", path);
454 if (!exists) {
455 fprintf(csv, "step,state,samples,total_weight,represented_time,"
456 "valid_fraction_min,valid_fraction_max,mean_tke\n");
457 }
458 fprintf(csv, "%" PetscInt_FMT ",%s,%d,%.10e,%.10e,%.6f,%.6f,",
459 ti, PicurvWindowStateName(window->state), window->sample_count,
460 (double)window->total_weight, (double)window->represented_time,
461 (double)lowest, (double)highest);
462 if (has_tke) fprintf(csv, "%.10e\n", (double)mean_tke);
463 else fprintf(csv, "\n");
464 PetscCheck(fclose(csv) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
465 "Unable to close statistics summary '%s'.", path);
466 }
467 LOG_ALLOW(GLOBAL, LOG_DEBUG, "-> KERNEL: Summarized window '%s' at step %" PetscInt_FMT ".\n",
468 window->definition.name, ti);
470 PetscFunctionReturn(0);
471}
PetscErrorCode PicurvWindowDerivedCount(const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const char *outputs, PetscInt *count)
Reports how many derived fields a requested output set produces.
PetscErrorCode PicurvWindowValidFractionRange(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt sample_count, PetscReal *minimum, PetscReal *maximum)
Reports the range of per-point valid fraction across a window's domain.
PetscErrorCode PicurvWindowSpatialMean(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, Vec field, PetscReal *mean)
Reports the spatial mean of a derived field over the points a window sampled.
Independent accumulator state for one window on one block.
PetscInt sample_count
PicurvWindowState state
PetscReal total_weight
const char * PicurvWindowStateName(PicurvWindowState state)
Returns a stable human-readable name for a window state.
PetscReal represented_time
Physical time the window covers.
Runtime state of one window.
PetscMPIInt rank
Definition variables.h:698
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeQCriterion()

PetscErrorCode ComputeQCriterion ( UserCtx user)

Implementation of ComputeQCriterion().

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

482{
483 PetscErrorCode ierr;
484 DMDALocalInfo info;
485 const Cmpnts ***lucat, ***lcsi, ***leta, ***lzet;
486 const PetscReal***laj, ***lnvert;
487 PetscReal ***gq;
488
489 PetscFunctionBeginUser;
491 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeQCriterion.\n");
492
493 // --- 1. Ensure all required ghost values are up-to-date ---
494 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT); CHKERRQ(ierr);
495 ierr = UpdateLocalGhosts(user, FIELD_ID_CSI); CHKERRQ(ierr);
496 ierr = UpdateLocalGhosts(user, FIELD_ID_ETA); CHKERRQ(ierr);
497 ierr = UpdateLocalGhosts(user, FIELD_ID_ZET); CHKERRQ(ierr);
498 ierr = UpdateLocalGhosts(user, FIELD_ID_AJ); CHKERRQ(ierr);
499 ierr = UpdateLocalGhosts(user, FIELD_ID_NVERT); CHKERRQ(ierr);
500
501 // --- 2. Get DMDA info and array pointers ---
502 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
503
504 ierr = DMDAVecGetArrayRead(user->fda, user->lUcat, (void*)&lucat); CHKERRQ(ierr);
505 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (void*)&lcsi); CHKERRQ(ierr);
506 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (void*)&leta); CHKERRQ(ierr);
507 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (void*)&lzet); CHKERRQ(ierr);
508 ierr = DMDAVecGetArrayRead(user->da, user->lAj, (void*)&laj); CHKERRQ(ierr);
509 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (void*)&lnvert); CHKERRQ(ierr);
510 ierr = DMDAVecGetArray(user->da, user->Qcrit, (void*)&gq); CHKERRQ(ierr);
511
512 // --- 3. Define Loop Bounds for INTERIOR Cells ---
513 PetscInt i_start = (info.xs == 0) ? 1 : info.xs;
514 PetscInt i_end = (info.xs + info.xm == info.mx) ? info.mx - 1 : info.xs + info.xm;
515 PetscInt j_start = (info.ys == 0) ? 1 : info.ys;
516 PetscInt j_end = (info.ys + info.ym == info.my) ? info.my - 1 : info.ys + info.ym;
517 PetscInt k_start = (info.zs == 0) ? 1 : info.zs;
518 PetscInt k_end = (info.zs + info.zm == info.mz) ? info.mz - 1 : info.zs + info.zm;
519
520 // --- 4. Main Computation Loop ---
521 for (PetscInt k = k_start; k < k_end; k++) {
522 for (PetscInt j = j_start; j < j_end; j++) {
523 for (PetscInt i = i_start; i < i_end; i++) {
524
525 // Calculate velocity derivatives in computational space (central differences)
526 PetscReal uc = 0.5 * (lucat[k][j][i+1].x - lucat[k][j][i-1].x);
527 PetscReal vc = 0.5 * (lucat[k][j][i+1].y - lucat[k][j][i-1].y);
528 PetscReal wc = 0.5 * (lucat[k][j][i+1].z - lucat[k][j][i-1].z);
529
530 PetscReal ue = 0.5 * (lucat[k][j+1][i].x - lucat[k][j-1][i].x);
531 PetscReal ve = 0.5 * (lucat[k][j+1][i].y - lucat[k][j-1][i].y);
532 PetscReal we = 0.5 * (lucat[k][j+1][i].z - lucat[k][j-1][i].z);
533
534 PetscReal uz = 0.5 * (lucat[k+1][j][i].x - lucat[k-1][j][i].x);
535 PetscReal vz = 0.5 * (lucat[k+1][j][i].y - lucat[k-1][j][i].y);
536 PetscReal wz = 0.5 * (lucat[k+1][j][i].z - lucat[k-1][j][i].z);
537
538 // Average metrics to the cell center
539 PetscReal csi1 = 0.5 * (lcsi[k][j][i].x + lcsi[k][j][i-1].x) * laj[k][j][i];
540 PetscReal csi2 = 0.5 * (lcsi[k][j][i].y + lcsi[k][j][i-1].y) * laj[k][j][i];
541 PetscReal csi3 = 0.5 * (lcsi[k][j][i].z + lcsi[k][j][i-1].z) * laj[k][j][i];
542
543 PetscReal eta1 = 0.5 * (leta[k][j][i].x + leta[k][j-1][i].x) * laj[k][j][i];
544 PetscReal eta2 = 0.5 * (leta[k][j][i].y + leta[k][j-1][i].y) * laj[k][j][i];
545 PetscReal eta3 = 0.5 * (leta[k][j][i].z + leta[k][j-1][i].z) * laj[k][j][i];
546
547 PetscReal zet1 = 0.5 * (lzet[k][j][i].x + lzet[k-1][j][i].x) * laj[k][j][i];
548 PetscReal zet2 = 0.5 * (lzet[k][j][i].y + lzet[k-1][j][i].y) * laj[k][j][i];
549 PetscReal zet3 = 0.5 * (lzet[k][j][i].z + lzet[k-1][j][i].z) * laj[k][j][i];
550
551 // Calculate velocity gradient tensor components d_ij = du_i/dx_j
552 PetscReal d11 = uc * csi1 + ue * eta1 + uz * zet1;
553 PetscReal d12 = uc * csi2 + ue * eta2 + uz * zet2;
554 PetscReal d13 = uc * csi3 + ue * eta3 + uz * zet3;
555
556 PetscReal d21 = vc * csi1 + ve * eta1 + vz * zet1;
557 PetscReal d22 = vc * csi2 + ve * eta2 + vz * zet2;
558 PetscReal d23 = vc * csi3 + ve * eta3 + vz * zet3;
559
560 PetscReal d31 = wc * csi1 + we * eta1 + wz * zet1;
561 PetscReal d32 = wc * csi2 + we * eta2 + wz * zet2;
562 PetscReal d33 = wc * csi3 + we * eta3 + wz * zet3;
563
564 // Strain-Rate Tensor S_ij = 0.5 * (d_ij + d_ji)
565 PetscReal s11 = d11;
566 PetscReal s12 = 0.5 * (d12 + d21);
567 PetscReal s13 = 0.5 * (d13 + d31);
568 PetscReal s22 = d22;
569 PetscReal s23 = 0.5 * (d23 + d32);
570 PetscReal s33 = d33;
571
572 // Vorticity Tensor Omega_ij = 0.5 * (d_ij - d_ji)
573 PetscReal w12 = 0.5 * (d12 - d21);
574 PetscReal w13 = 0.5 * (d13 - d31);
575 PetscReal w23 = 0.5 * (d23 - d32);
576
577 // Squared norms of the tensors
578 PetscReal s_norm_sq = s11*s11 + s22*s22 + s33*s33 + 2.0*(s12*s12 + s13*s13 + s23*s23);
579 PetscReal w_norm_sq = 2.0 * (w12*w12 + w13*w13 + w23*w23);
580
581 gq[k][j][i] = 0.5 * (w_norm_sq - s_norm_sq);
582
583 if (lnvert[k][j][i] > 0.1) {
584 gq[k][j][i] = 0.0;
585 }
586 }
587 }
588 }
589
590 // --- 5. Restore arrays ---
591 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcat, (void*)&lucat); CHKERRQ(ierr);
592 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (void*)&lcsi); CHKERRQ(ierr);
593 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (void*)&leta); CHKERRQ(ierr);
594 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (void*)&lzet); CHKERRQ(ierr);
595 ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, (void*)&laj); CHKERRQ(ierr);
596 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (void*)&lnvert); CHKERRQ(ierr);
597 ierr = DMDAVecRestoreArray(user->da, user->Qcrit, (void*)&gq); CHKERRQ(ierr);
598
599 /* The loop above skips the layout boundary, so extend it before anything reads
600 * Qcrit with a stencil. Q is not a moment: it does not vanish at a wall, so only
601 * the periodic case is defined and only that case is written. */
602 ierr = ExtendToLayoutBoundary(user, user->Qcrit, 1); CHKERRQ(ierr);
603
605 PetscFunctionReturn(0);
606}
@ FIELD_ID_CSI
@ FIELD_ID_NVERT
@ FIELD_ID_UCAT
@ FIELD_ID_AJ
@ FIELD_ID_ETA
@ FIELD_ID_ZET
Vec lNvert
Definition variables.h:939
Vec lZet
Definition variables.h:974
Vec Qcrit
Definition variables.h:1003
Vec lCsi
Definition variables.h:974
Vec lAj
Definition variables.h:974
Vec lEta
Definition variables.h:974
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 
)

Implementation of NormalizeRelativeField().

Normalizes pressure using the value at the configured logical grid point.

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

See also
NormalizeRelativeField()

Definition at line 616 of file postprocessing_kernels.c.

617{
618 PetscErrorCode ierr;
619 Vec P_vec = NULL;
620 DMDALocalInfo info;
621 PetscInt ip=1, jp=1, kp=1; // Default reference point
622 PetscReal p_ref = 0.0;
623 PetscReal p_ref_local = 0.0;
624 PetscInt found_local = 0, found_global = 0;
625 PostProcessParams *pps = user->simCtx->pps;
626
627 // Fetch the logical reference point from pps.
628 ip = pps->reference[0];
629 jp = pps->reference[1];
630 kp = pps->reference[2];
631
632 PetscFunctionBeginUser;
634 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running NormalizeRelativeField on '%s'.\n", relative_field_name);
635
636 // --- 1. Map string argument to the PETSc Vec ---
637 if (strcasecmp(relative_field_name, "P") == 0) {
638 P_vec = user->P;
639 } else {
640 SETERRQ(PETSC_COMM_SELF, 1, "NormalizeRelativeField only supports the primary 'P' field , not '%s' currently.", relative_field_name);
641 }
642
643 // --- 2. Read the logical reference point from whichever rank owns it ---
644 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
645 PetscCheck(ip >= 0 && ip < info.mx && jp >= 0 && jp < info.my &&
646 kp >= 0 && kp < info.mz,
647 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
648 "Reference point (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT
649 ") lies outside the %" PetscInt_FMT "x%" PetscInt_FMT "x%" PetscInt_FMT
650 " pressure layout.", ip, jp, kp, info.mx, info.my, info.mz);
651 if (ip >= info.xs && ip < info.xs + info.xm &&
652 jp >= info.ys && jp < info.ys + info.ym &&
653 kp >= info.zs && kp < info.zs + info.zm) {
654 const PetscReal ***pressure = NULL;
655
656 ierr = DMDAVecGetArrayRead(user->da, P_vec, &pressure); CHKERRQ(ierr);
657 p_ref_local = pressure[kp][jp][ip];
658 ierr = DMDAVecRestoreArrayRead(user->da, P_vec, &pressure); CHKERRQ(ierr);
659 found_local = 1;
660 }
661 ierr = MPI_Allreduce(&p_ref_local, &p_ref, 1, MPIU_REAL, MPI_SUM,
662 PETSC_COMM_WORLD); CHKERRQ(ierr);
663 ierr = MPI_Allreduce(&found_local, &found_global, 1, MPIU_INT, MPI_SUM,
664 PETSC_COMM_WORLD); CHKERRQ(ierr);
665 PetscCheck(found_global == 1, PETSC_COMM_WORLD, PETSC_ERR_PLIB,
666 "Reference pressure point must have exactly one owner; found %" PetscInt_FMT ".",
667 found_global);
669 "%s reference point (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT
670 ") has value %g.\n", relative_field_name, ip, jp, kp, (double)p_ref);
671
672 // --- 3. Perform the normalization (in-place shift) on the full distributed vector ---
673 ierr = VecShift(P_vec, -p_ref); CHKERRQ(ierr);
674 LOG_ALLOW(GLOBAL, LOG_DEBUG, "%s field normalized by subtracting %g.\n", relative_field_name, p_ref);
675
677 PetscFunctionReturn(0);
678}
PetscInt reference[3]
Definition variables.h:634
PostProcessParams * pps
Definition variables.h:890
Holds all configuration parameters for a post-processing run.
Definition variables.h:596
Here is the caller graph for this function:

◆ ComputeSpecificKE()

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

Internal helper implementation: ComputeSpecificKE().

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

Local to this translation unit.

Definition at line 689 of file postprocessing_kernels.c.

690{
691 PetscErrorCode ierr;
692 PetscInt n_local;
693 const PetscScalar (*vel_arr)[3]; // Access velocity as array of 3-component vectors
694 PetscScalar *ske_arr;
695
696 PetscFunctionBeginUser;
698 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeSpecificKE ('%s' -> '%s').\n", velocity_field, ske_field);
699
700 // Get local data arrays from the DMSwarm
701 ierr = DMSwarmGetLocalSize(user->swarm, &n_local); CHKERRQ(ierr);
702 if (n_local == 0) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
703
704 // Get read-only access to velocity and write access to the output field
705 ierr = DMSwarmGetField(user->swarm, velocity_field, NULL, NULL, (void**)&vel_arr); CHKERRQ(ierr);
706 ierr = DMSwarmGetField(user->post_swarm, ske_field, NULL, NULL, (void**)&ske_arr); CHKERRQ(ierr);
707
708 // Main computation loop
709 for (PetscInt p = 0; p < n_local; p++) {
710 const PetscScalar u = vel_arr[p][0];
711 const PetscScalar v = vel_arr[p][1];
712 const PetscScalar w = vel_arr[p][2];
713 const PetscScalar vel_sq = u*u + v*v + w*w;
714 ske_arr[p] = 0.5 * vel_sq;
715 }
716
717 // Restore arrays
718 ierr = DMSwarmRestoreField(user->swarm, velocity_field, NULL, NULL, (void**)&vel_arr); CHKERRQ(ierr);
719 ierr = DMSwarmRestoreField(user->post_swarm, ske_field, NULL, NULL, (void**)&ske_arr); CHKERRQ(ierr);
720
722 PetscFunctionReturn(0);
723}
DM post_swarm
Definition variables.h:1000
Here is the caller graph for this function:

◆ ComputeDisplacement()

PetscErrorCode ComputeDisplacement ( UserCtx user,
const char *  disp_field 
)

Internal helper implementation: ComputeDisplacement().

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

Local to this translation unit.

Definition at line 731 of file postprocessing_kernels.c.

732{
733 PetscErrorCode ierr;
734 PetscInt n_local;
735 const PetscReal (*pos_arr)[3];
736 PetscScalar *disp_out;
737 SimCtx *simCtx = user->simCtx;
738
739 PetscFunctionBeginUser;
741 LOG_ALLOW(GLOBAL, LOG_INFO, "-> KERNEL: Running ComputeDisplacement (-> '%s').\n", disp_field);
742
743 ierr = DMSwarmGetLocalSize(user->swarm, &n_local); CHKERRQ(ierr);
744 if (n_local == 0) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
745
746 const PetscReal x0 = simCtx->psrc_x;
747 const PetscReal y0 = simCtx->psrc_y;
748 const PetscReal z0 = simCtx->psrc_z;
749
750 ierr = DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
751 ierr = DMSwarmGetField(user->post_swarm, disp_field, NULL, NULL, (void**)&disp_out); CHKERRQ(ierr);
752
753 for (PetscInt p = 0; p < n_local; p++) {
754 const PetscReal dx = pos_arr[p][0] - x0;
755 const PetscReal dy = pos_arr[p][1] - y0;
756 const PetscReal dz = pos_arr[p][2] - z0;
757 disp_out[p] = PetscSqrtReal(dx*dx + dy*dy + dz*dz);
758 }
759
760 ierr = DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void**)&pos_arr); CHKERRQ(ierr);
761 ierr = DMSwarmRestoreField(user->post_swarm, disp_field, NULL, NULL, (void**)&disp_out); CHKERRQ(ierr);
762
764 PetscFunctionReturn(0);
765}
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_POSITION
PetscReal psrc_x
Definition variables.h:784
PetscReal psrc_z
Point source location for PARTICLE_INIT_POINT_SOURCE.
Definition variables.h:784
PetscReal psrc_y
Definition variables.h:784
Here is the call graph for this function:
Here is the caller graph for this function: