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));
65
66 PetscCall(DMDAVecGetArray(user->
da, user->
P, &pressure));
67 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &velocity));
68 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
69 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
70 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
72 velocity[k][j][i] = (
Cmpnts){1.0, 2.0, 3.0};
73 }
74 }
75 }
76 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &velocity));
77 PetscCall(DMDAVecRestoreArray(user->
da, user->
P, &pressure));
81
82
83
84
86 PetscCall(PetscStrncpy(
88 "NormalizeRelativeField:P;"
89 "CellToNodeAverage:P>P_nodal;CellToNodeAverage:Ucat>Ucat_nodal;"
90 "ComputeQCriterion",
93
94 PetscCall(DMDAVecGetArrayRead(user->
da, user->
P, &pressure_result));
95 PetscCall(DMDAVecGetArrayRead(user->
da, user->
P_nodal, &pressure_nodal));
96 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat_nodal, &velocity_nodal));
97 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Qcrit, &qcrit));
98 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
99 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
100 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
101 const PetscBool physical_node =
102 (PetscBool)(i < user->info.mx - 1 && j < user->info.my - 1 &&
103 k < user->info.mz - 1);
104 const PetscBool q_point =
105 (PetscBool)(i >= 1 && i < user->info.mx - 1 &&
106 j >= 1 && j < user->info.my - 1 &&
107 k >= 1 && k < user->info.mz - 1);
108 const PetscReal expected_pressure = 2.0 * (
ScalarValue(i, j, k) - 111.0);
109
110 pressure_error = PetscMax(
111 pressure_error,
112 PetscAbsReal(pressure_result[k][j][i] - expected_pressure));
113 if (physical_node) {
114 const PetscReal expected_nodal =
116
117 pressure_nodal_error = PetscMax(
118 pressure_nodal_error,
119 PetscAbsReal(pressure_nodal[k][j][i] - expected_nodal));
120 velocity_nodal_error = PetscMax(
121 velocity_nodal_error,
122 PetscAbsReal(velocity_nodal[k][j][i].x - 1.0));
123 velocity_nodal_error = PetscMax(
124 velocity_nodal_error,
125 PetscAbsReal(velocity_nodal[k][j][i].y - 2.0));
126 velocity_nodal_error = PetscMax(
127 velocity_nodal_error,
128 PetscAbsReal(velocity_nodal[k][j][i].z - 3.0));
129 ++local_physical_nodes;
130 } else {
131 pressure_nodal_error = PetscMax(
132 pressure_nodal_error,
133 PetscAbsReal(pressure_nodal[k][j][i] -
kSentinel));
134 velocity_nodal_error = PetscMax(
135 velocity_nodal_error,
136 PetscAbsReal(velocity_nodal[k][j][i].x -
kSentinel));
137 velocity_nodal_error = PetscMax(
138 velocity_nodal_error,
139 PetscAbsReal(velocity_nodal[k][j][i].y -
kSentinel));
140 velocity_nodal_error = PetscMax(
141 velocity_nodal_error,
142 PetscAbsReal(velocity_nodal[k][j][i].z -
kSentinel));
143 }
144 qcrit_error = PetscMax(
145 qcrit_error,
146 PetscAbsReal(qcrit[k][j][i] - (q_point ? 0.0 :
kSentinel)));
147 if (q_point) ++local_q_points;
148 }
149 }
150 }
151 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Qcrit, &qcrit));
152 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat_nodal, &velocity_nodal));
153 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
P_nodal, &pressure_nodal));
154 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
P, &pressure_result));
155
156 PetscCallMPI(MPI_Allreduce(&local_physical_nodes, &global_physical_nodes, 1,
157 MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
158 PetscCallMPI(MPI_Allreduce(&local_q_points, &global_q_points, 1,
159 MPIU_INT, MPI_SUM, PETSC_COMM_WORLD));
161 global_physical_nodes,
162 "the Eulerian pipeline must visit every physical node exactly once"));
164 global_q_points,
165 "Q-criterion must visit every interior cell exactly once"));
167 "pressure normalization and dimensionalization are decomposition independent"));
169 "scalar nodal averaging covers rank interfaces and physical boundaries"));
171 "vector nodal averaging covers rank interfaces and physical boundaries"));
173 "Q-criterion covers the complete distributed interior"));
174
176 PetscFunctionReturn(0);
177}
PetscErrorCode DimensionalizeField(UserCtx *user, const char *field_name)
Scales a specified field from non-dimensional to dimensional units in-place.
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.