Exercises every Eulerian transformation currently dispatched by the pipeline.
35{
39 PetscReal ***pressure = NULL;
41 const PetscReal ***pressure_result = NULL;
42 const PetscReal ***pressure_nodal = NULL;
43 const PetscReal ***qcrit = NULL;
44 const Cmpnts ***velocity_nodal = NULL;
45 PetscReal pressure_error = 0.0;
46 PetscReal pressure_nodal_error = 0.0;
47 PetscReal velocity_nodal_error = 0.0;
48 PetscReal qcrit_error = 0.0;
49 PetscInt local_physical_nodes = 0;
50 PetscInt global_physical_nodes = 0;
51 PetscInt local_q_points = 0;
52 PetscInt global_q_points = 0;
53
54 PetscFunctionBeginUser;
56 PetscCall(PetscCalloc1(1, &simCtx->
pps));
64
65 PetscCall(DMDAVecGetArray(user->
da, user->
P, &pressure));
66 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &velocity));
67 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
68 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
69 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
71 velocity[k][j][i] = (
Cmpnts){1.0, 2.0, 3.0};
72 }
73 }
74 }
75 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &velocity));
76 PetscCall(DMDAVecRestoreArray(user->
da, user->
P, &pressure));
80
81 PetscCall(PetscStrncpy(
83 "NormalizeRelativeField:P;DimensionalizeAllLoadedFields;"
84 "CellToNodeAverage:P>P_nodal;CellToNodeAverage:Ucat>Ucat_nodal;"
85 "ComputeQCriterion",
88
89 PetscCall(DMDAVecGetArrayRead(user->
da, user->
P, &pressure_result));
90 PetscCall(DMDAVecGetArrayRead(user->
da, user->
P_nodal, &pressure_nodal));
91 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat_nodal, &velocity_nodal));
92 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Qcrit, &qcrit));
93 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
94 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
95 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
96 const PetscBool physical_node =
97 (PetscBool)(i < user->info.mx - 1 && j < user->info.my - 1 &&
98 k < user->info.mz - 1);
99 const PetscBool q_point =
100 (PetscBool)(i >= 1 && i < user->info.mx - 1 &&
101 j >= 1 && j < user->info.my - 1 &&
102 k >= 1 && k < user->info.mz - 1);
103 const PetscReal expected_pressure = 2.0 * (
ScalarValue(i, j, k) - 111.0);
104
105 pressure_error = PetscMax(
106 pressure_error,
107 PetscAbsReal(pressure_result[k][j][i] - expected_pressure));
108 if (physical_node) {
109 const PetscReal expected_nodal =
111
112 pressure_nodal_error = PetscMax(
113 pressure_nodal_error,
114 PetscAbsReal(pressure_nodal[k][j][i] - expected_nodal));
115 velocity_nodal_error = PetscMax(
116 velocity_nodal_error,
117 PetscAbsReal(velocity_nodal[k][j][i].x - 1.0));
118 velocity_nodal_error = PetscMax(
119 velocity_nodal_error,
120 PetscAbsReal(velocity_nodal[k][j][i].y - 2.0));
121 velocity_nodal_error = PetscMax(
122 velocity_nodal_error,
123 PetscAbsReal(velocity_nodal[k][j][i].z - 3.0));
124 ++local_physical_nodes;
125 } else {
126 pressure_nodal_error = PetscMax(
127 pressure_nodal_error,
128 PetscAbsReal(pressure_nodal[k][j][i] -
kSentinel));
129 velocity_nodal_error = PetscMax(
130 velocity_nodal_error,
131 PetscAbsReal(velocity_nodal[k][j][i].x -
kSentinel));
132 velocity_nodal_error = PetscMax(
133 velocity_nodal_error,
134 PetscAbsReal(velocity_nodal[k][j][i].y -
kSentinel));
135 velocity_nodal_error = PetscMax(
136 velocity_nodal_error,
137 PetscAbsReal(velocity_nodal[k][j][i].z -
kSentinel));
138 }
139 qcrit_error = PetscMax(
140 qcrit_error,
141 PetscAbsReal(qcrit[k][j][i] - (q_point ? 0.0 :
kSentinel)));
142 if (q_point) ++local_q_points;
143 }
144 }
145 }
146 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Qcrit, &qcrit));
147 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat_nodal, &velocity_nodal));
148 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
P_nodal, &pressure_nodal));
149 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
P, &pressure_result));
150
151 PetscCallMPI(MPI_Allreduce(&local_physical_nodes, &global_physical_nodes, 1,
152 MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
153 PetscCallMPI(MPI_Allreduce(&local_q_points, &global_q_points, 1,
154 MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
156 global_physical_nodes,
157 "the Eulerian pipeline must visit every physical node exactly once"));
159 global_q_points,
160 "Q-criterion must visit every interior cell exactly once"));
162 "pressure normalization and dimensionalization are decomposition independent"));
164 "scalar nodal averaging covers rank interfaces and physical boundaries"));
166 "vector nodal averaging covers rank interfaces and physical boundaries"));
168 "Q-criterion covers the complete distributed interior"));
169
171 PetscFunctionReturn(0);
172}
PetscErrorCode EulerianDataProcessingPipeline(UserCtx *user, PostProcessParams *pps)
Parses the processing pipeline string and executes the requested kernels.
static const PetscReal kSentinel
static PetscReal ScalarValue(PetscInt i, PetscInt j, PetscInt k)
Analytic scalar field used to expose misplaced or missing grid points.
static PetscErrorCode AssertGlobalError(PetscReal local_error, PetscReal tolerance, const char *context)
Requires every rank's maximum error to be within tolerance.
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
char process_pipeline[1024]
A 3D point or vector with PetscScalar components.
Holds all configuration parameters for a post-processing run.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.