PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Functions
test_poisson_rhs.c File Reference

C unit tests for Poisson, RHS, body-force, and diffusivity helpers. More...

#include "test_support.h"
#include "poisson.h"
#include "rhs.h"
#include "setup.h"
#include "verification_sources.h"
Include dependency graph for test_poisson_rhs.c:

Go to the source code of this file.

Functions

static PetscErrorCode EnsurePoissonAndRhsVectors (UserCtx *user)
 Allocates Poisson/RHS support vectors required by the tests.
 
static PetscErrorCode TestUpdatePressureAddsPhi (void)
 Tests that pressure updates add the correction potential.
 
static PetscErrorCode TestPoissonRHSZeroDivergence (void)
 Tests that the Poisson RHS is zero for zero-divergence velocity.
 
static PetscErrorCode TestComputeBodyForcesDispatcher (void)
 Tests the body-force dispatcher across supported source terms.
 
static PetscErrorCode TestComputeEulerianDiffusivityMolecularOnly (void)
 Tests Eulerian diffusivity for the molecular-only configuration.
 
static PetscErrorCode TestConvectionZeroField (void)
 Tests that convection vanishes for a quiescent field.
 
static PetscErrorCode TestViscousUniformField (void)
 Tests that viscous terms vanish for a uniform field.
 
static PetscErrorCode ScaleMinimalMetricsToSpacing (UserCtx *user, PetscReal h)
 Rescales the minimal fixture's unit metrics to cubic cells of edge h.
 
static PetscErrorCode ClarkToMolecularRatioPerX (PetscReal h, PetscInt probe, PetscReal *ratio_per_x)
 Returns the Clark contribution over the molecular viscous one, per unit x, at one cell.
 
static PetscErrorCode TestClarkGradientModelScalesWithFilterWidthSquared (void)
 Tests that the Clark gradient model scales as the square of the filter width.
 
static PetscErrorCode TestComputeRHSZeroFieldNoForcing (void)
 Tests that the full RHS remains zero without forcing on a quiescent field.
 
static PetscErrorCode TestComputeEulerianDiffusivityGradientConstantField (void)
 Tests diffusivity-gradient computation on a constant field.
 
static PetscErrorCode TestComputeEulerianDiffusivityVerificationLinearX (void)
 Tests verification-driven linear diffusivity override and its gradient.
 
static PetscErrorCode TestAssemblePoissonOperatorPopulatesRows (void)
 Tests that Poisson matrix assembly produces a populated operator on a tiny Cartesian grid.
 
static PetscErrorCode RandomizeMinimalFaceMetrics (UserCtx *user)
 Fills every face metric and Jacobian of the minimal fixture with reproducible random values, so each face gradient carries all of its cross terms.
 
static PetscErrorCode TestOperatorAndProjectionShareOneFaceGradient (void)
 Tests that the operator is exactly the divergence of the projection's gradient.
 
static PetscErrorCode TestProjectionZeroPhiLeavesVelocityUnchanged (void)
 Tests that projection leaves a zero pressure-correction field unchanged.
 
static PetscErrorCode TestProjectionLinearPhiCorrectsVelocity (void)
 Tests that projection applies the expected x-direction correction for a linear pressure field.
 
static PetscErrorCode PerturbInteriorFaceFluxes (UserCtx *user, PetscReal amplitude)
 Adds a smooth divergent perturbation to every interior face flux.
 
static PetscErrorCode TestPoissonSolverMultigridProjectsToDivergenceFree (void)
 Tests that the production multigrid Poisson solve and projection remove a divergence.
 
static PetscErrorCode CountFileOccurrences (const char *path, const char *needle, PetscInt *count)
 Counts the occurrences of needle in a text file; a missing file counts zero.
 
static PetscErrorCode TestPoissonSolverMultigridReusesItsSolver (void)
 Tests that the multigrid solver is built once and reused on later steps.
 
static PetscErrorCode TestPoissonSolverMultigridHonoursDistinctSweeps (void)
 Tests that unequal pre- and post-smoothing counts give two distinct smoothers.
 
static PetscErrorCode TestPoissonNullSpaceRemovesTheInteriorMean (void)
 Tests the null space attached to the operator.
 
static PetscErrorCode TestPoissonSolverMultigridRefusesAnOvercoarsenedHierarchy (void)
 Tests that an over-coarsened hierarchy stops the run at the Poisson solve.
 
int main (int argc, char **argv)
 Runs the unit-poisson-rhs PETSc test binary.
 

Detailed Description

C unit tests for Poisson, RHS, body-force, and diffusivity helpers.

Definition in file test_poisson_rhs.c.

Function Documentation

◆ EnsurePoissonAndRhsVectors()

static PetscErrorCode EnsurePoissonAndRhsVectors ( UserCtx *  user)
static

Allocates Poisson/RHS support vectors required by the tests.

Definition at line 16 of file test_poisson_rhs.c.

17{
18 PetscFunctionBeginUser;
19 if (!user->Phi) PetscCall(DMCreateGlobalVector(user->da, &user->Phi));
20 if (!user->lPhi) PetscCall(DMCreateLocalVector(user->da, &user->lPhi));
21 if (!user->Aj) PetscCall(DMCreateGlobalVector(user->da, &user->Aj));
22 if (!user->lAj) PetscCall(DMCreateLocalVector(user->da, &user->lAj));
23 if (!user->Diffusivity) PetscCall(DMCreateGlobalVector(user->da, &user->Diffusivity));
24 if (!user->lDiffusivity) PetscCall(DMCreateLocalVector(user->da, &user->lDiffusivity));
25 PetscFunctionReturn(0);
26}
Vec Diffusivity
Definition variables.h:1116
Vec lDiffusivity
Definition variables.h:1116
Here is the caller graph for this function:

◆ TestUpdatePressureAddsPhi()

static PetscErrorCode TestUpdatePressureAddsPhi ( void  )
static

Tests that pressure updates add the correction potential.

Definition at line 31 of file test_poisson_rhs.c.

32{
33 SimCtx *simCtx = NULL;
34 UserCtx *user = NULL;
35
36 PetscFunctionBeginUser;
37 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
38 PetscCall(EnsurePoissonAndRhsVectors(user));
39 PetscCall(VecSet(user->P, 1.0));
40 PetscCall(VecSet(user->Phi, 0.25));
41
42 PetscCall(UpdatePressure(user));
43 PetscCall(PicurvAssertVecConstant(user->P, 1.25, 1.0e-12, "UpdatePressure should add Phi into P"));
44
45 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
46 PetscFunctionReturn(0);
47}
PetscErrorCode UpdatePressure(UserCtx *user)
Adds the pressure correction to the pressure, P += Phi, and refreshes both fields' periodic images an...
Definition poisson.c:416
static PetscErrorCode EnsurePoissonAndRhsVectors(UserCtx *user)
Allocates Poisson/RHS support vectors required by the tests.
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 PicurvAssertVecConstant(Vec vec, PetscScalar expected, PetscReal tol, const char *context)
Asserts that a PETSc vector is spatially constant within tolerance.
The master context for the entire simulation.
Definition variables.h:859
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPoissonRHSZeroDivergence()

static PetscErrorCode TestPoissonRHSZeroDivergence ( void  )
static

Tests that the Poisson RHS is zero for zero-divergence velocity.

Definition at line 52 of file test_poisson_rhs.c.

53{
54 SimCtx *simCtx = NULL;
55 UserCtx *user = NULL;
56 Vec B = NULL;
57
58 PetscFunctionBeginUser;
59 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
60 PetscCall(EnsurePoissonAndRhsVectors(user));
61
62 simCtx->dt = 0.5;
63 PetscCall(VecSet(user->Ucont, 0.0));
64 PetscCall(VecSet(user->Nvert, 0.0));
65 PetscCall(VecSet(user->Aj, 1.0));
66 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
67 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
68 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
69 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
70 PetscCall(DMGlobalToLocalBegin(user->da, user->Aj, INSERT_VALUES, user->lAj));
71 PetscCall(DMGlobalToLocalEnd(user->da, user->Aj, INSERT_VALUES, user->lAj));
72
73 PetscCall(VecDuplicate(user->P, &B));
74 PetscCall(ComputePoissonRHS(user, B));
75 PetscCall(PicurvAssertVecConstant(B, 0.0, 1.0e-12, "zero velocity divergence should produce zero Poisson RHS"));
76 PetscCall(PicurvAssertRealNear(0.0, simCtx->poissonSourceImbalance, 1.0e-12, "global Poisson RHS sum should be zero"));
77
78 PetscCall(VecDestroy(&B));
79 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
80 PetscFunctionReturn(0);
81}
PetscErrorCode ComputePoissonRHS(UserCtx *user, Vec B)
Forms the right-hand side of the pressure-correction equation.
Definition poisson.c:353
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
Vec lNvert
Definition variables.h:1113
PetscReal poissonSourceImbalance
Definition variables.h:1026
PetscReal dt
Definition variables.h:874
Vec Ucont
Definition variables.h:1113
Vec lUcont
Definition variables.h:1113
Vec Nvert
Definition variables.h:1113
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestComputeBodyForcesDispatcher()

static PetscErrorCode TestComputeBodyForcesDispatcher ( void  )
static

Tests the body-force dispatcher across supported source terms.

Definition at line 86 of file test_poisson_rhs.c.

87{
88 SimCtx *simCtx = NULL;
89 UserCtx *user = NULL;
90 Vec rct = NULL;
91 Cmpnts ***rct_arr = NULL;
92 Cmpnts ***l_csi = NULL;
93 Cmpnts ***l_eta = NULL;
94 Cmpnts ***l_zet = NULL;
95
96 PetscFunctionBeginUser;
97 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
98 PetscCall(VecDuplicate(user->Ucont, &rct));
99 PetscCall(VecZeroEntries(rct));
100
107 simCtx->bulkVelocityCorrection = 2.0;
108 simCtx->dt = 1.0;
109 simCtx->forceScalingFactor = 1.0;
110 simCtx->drivingForceMagnitude = 0.0;
111 PetscCall(VecSet(user->Nvert, 0.0));
112 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
113 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
114 PetscCall(DMDAVecGetArray(user->fda, user->lCsi, &l_csi));
115 PetscCall(DMDAVecGetArray(user->fda, user->lEta, &l_eta));
116 PetscCall(DMDAVecGetArray(user->fda, user->lZet, &l_zet));
117 l_csi[1][1][1].x = 1.0; l_csi[1][1][1].y = 0.0; l_csi[1][1][1].z = 0.0;
118 l_eta[1][1][1].x = 0.0; l_eta[1][1][1].y = 1.0; l_eta[1][1][1].z = 0.0;
119 l_zet[1][1][1].x = 0.0; l_zet[1][1][1].y = 0.0; l_zet[1][1][1].z = 1.0;
120 PetscCall(DMDAVecRestoreArray(user->fda, user->lZet, &l_zet));
121 PetscCall(DMDAVecRestoreArray(user->fda, user->lEta, &l_eta));
122 PetscCall(DMDAVecRestoreArray(user->fda, user->lCsi, &l_csi));
123
124 PetscCall(ComputeBodyForces(user, rct));
125 PetscCall(DMDAVecGetArrayRead(user->fda, rct, &rct_arr));
126 PetscCall(PicurvAssertRealNear(1.5, simCtx->drivingForceMagnitude, 1.0e-12,
127 "ComputeBodyForces should update the driven-flow controller magnitude"));
128 PetscCall(PicurvAssertRealNear(0.0, rct_arr[1][1][1].y, 1.0e-12, "ComputeBodyForces should keep y unchanged"));
129 PetscCall(PicurvAssertRealNear(0.0, rct_arr[1][1][1].z, 1.0e-12, "ComputeBodyForces should keep z unchanged"));
130 PetscCall(DMDAVecRestoreArrayRead(user->fda, rct, &rct_arr));
131
132 PetscCall(VecDestroy(&rct));
133 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
134 PetscFunctionReturn(0);
135}
PetscErrorCode ComputeBodyForces(UserCtx *user, Vec Rct)
General dispatcher for applying all active body forces (momentum sources).
Definition rhs.c:1129
@ PERIODIC
Definition variables.h:318
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:1099
PetscReal forceScalingFactor
Definition variables.h:961
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:342
BCHandlerType handler_type
Definition variables.h:393
PetscReal bulkVelocityCorrection
Definition variables.h:973
PetscScalar x
Definition variables.h:122
PetscScalar z
Definition variables.h:122
PetscScalar y
Definition variables.h:122
BCType mathematical_type
Definition variables.h:392
PetscReal drivingForceMagnitude
Definition variables.h:961
@ BC_FACE_NEG_X
Definition variables.h:288
@ BC_FACE_POS_X
Definition variables.h:288
A 3D point or vector with PetscScalar components.
Definition variables.h:121
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestComputeEulerianDiffusivityMolecularOnly()

static PetscErrorCode TestComputeEulerianDiffusivityMolecularOnly ( void  )
static

Tests Eulerian diffusivity for the molecular-only configuration.

Definition at line 140 of file test_poisson_rhs.c.

141{
142 SimCtx *simCtx = NULL;
143 UserCtx *user = NULL;
144 PetscReal ***diff_arr = NULL;
145
146 PetscFunctionBeginUser;
147 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
148 PetscCall(EnsurePoissonAndRhsVectors(user));
149
150 simCtx->ren = 2.0;
151 simCtx->schmidt_number = 4.0;
152 simCtx->les = PETSC_FALSE;
153 PetscCall(VecZeroEntries(user->Diffusivity));
154
155 PetscCall(ComputeEulerianDiffusivity(user));
156 PetscCall(DMDAVecGetArrayRead(user->da, user->Diffusivity, &diff_arr));
157 PetscCall(PicurvAssertRealNear(0.125, diff_arr[1][1][1], 1.0e-12, "molecular diffusivity interior value"));
158 PetscCall(DMDAVecRestoreArrayRead(user->da, user->Diffusivity, &diff_arr));
159
160 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
161 PetscFunctionReturn(0);
162}
PetscErrorCode ComputeEulerianDiffusivity(UserCtx *user)
Computes the effective diffusivity scalar field (Gamma_eff) on the Eulerian grid.
Definition rhs.c:1867
PetscReal schmidt_number
Definition variables.h:948
PetscReal ren
Definition variables.h:906
PetscInt les
Active LES closure; an LESModelType value.
Definition variables.h:984
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestConvectionZeroField()

static PetscErrorCode TestConvectionZeroField ( void  )
static

Tests that convection vanishes for a quiescent field.

Definition at line 167 of file test_poisson_rhs.c.

168{
169 SimCtx *simCtx = NULL;
170 UserCtx *user = NULL;
171 Vec conv = NULL;
172
173 PetscFunctionBeginUser;
174 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
175 PetscCall(VecDuplicate(user->lUcont, &conv));
176 PetscCall(VecSet(user->Ucont, 0.0));
177 PetscCall(VecSet(user->Ucat, 0.0));
178 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
179 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
180 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
181 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
182
183 PetscCall(Convection(user, user->lUcont, user->lUcat, conv));
184 PetscCall(PicurvAssertVecConstant(conv, 0.0, 1.0e-12, "Convection should vanish for a quiescent field"));
185
186 PetscCall(VecDestroy(&conv));
187 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
188 PetscFunctionReturn(0);
189}
PetscErrorCode Convection(UserCtx *user, Vec Ucont, Vec Ucat, Vec Conv)
Computes the convective contribution to the contravariant momentum RHS.
Definition rhs.c:14
Vec lUcat
Definition variables.h:1113
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestViscousUniformField()

static PetscErrorCode TestViscousUniformField ( void  )
static

Tests that viscous terms vanish for a uniform field.

Definition at line 194 of file test_poisson_rhs.c.

195{
196 SimCtx *simCtx = NULL;
197 UserCtx *user = NULL;
198 Vec visc = NULL;
199
200 PetscFunctionBeginUser;
201 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
202 PetscCall(VecDuplicate(user->lUcont, &visc));
203 PetscCall(VecSet(user->Ucont, 1.0));
204 PetscCall(VecSet(user->Ucat, 1.0));
205 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
206 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
207 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
208 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
209
210 PetscCall(Viscous(user, user->lUcont, user->lUcat, visc));
211 PetscCall(PicurvAssertVecConstant(visc, 0.0, 1.0e-12, "Viscous should vanish for a uniform field"));
212
213 PetscCall(VecDestroy(&visc));
214 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
215 PetscFunctionReturn(0);
216}
PetscErrorCode Viscous(UserCtx *user, Vec Ucont, Vec Ucat, Vec Visc)
Computes the viscous contribution to the contravariant momentum RHS.
Definition rhs.c:435
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ScaleMinimalMetricsToSpacing()

static PetscErrorCode ScaleMinimalMetricsToSpacing ( UserCtx *  user,
PetscReal  h 
)
static

Rescales the minimal fixture's unit metrics to cubic cells of edge h.

Definition at line 220 of file test_poisson_rhs.c.

221{
222 Vec area_vectors[12] = {user->Csi, user->Eta, user->Zet, user->ICsi, user->IEta, user->IZet,
223 user->JCsi, user->JEta, user->JZet, user->KCsi, user->KEta, user->KZet};
224 Vec local_area[12] = {user->lCsi, user->lEta, user->lZet, user->lICsi, user->lIEta, user->lIZet,
225 user->lJCsi, user->lJEta, user->lJZet, user->lKCsi, user->lKEta, user->lKZet};
226 Vec jacobians[4] = {user->Aj, user->IAj, user->JAj, user->KAj};
227 Vec local_jac[4] = {user->lAj, user->lIAj, user->lJAj, user->lKAj};
228
229 PetscFunctionBeginUser;
230 for (PetscInt v = 0; v < 12; ++v) {
231 PetscCall(VecScale(area_vectors[v], h * h)); /* a face of a cube of edge h */
232 PetscCall(DMGlobalToLocalBegin(user->fda, area_vectors[v], INSERT_VALUES, local_area[v]));
233 PetscCall(DMGlobalToLocalEnd(user->fda, area_vectors[v], INSERT_VALUES, local_area[v]));
234 }
235 for (PetscInt v = 0; v < 4; ++v) {
236 PetscCall(VecSet(jacobians[v], 1.0 / (h * h * h)));
237 PetscCall(DMGlobalToLocalBegin(user->da, jacobians[v], INSERT_VALUES, local_jac[v]));
238 PetscCall(DMGlobalToLocalEnd(user->da, jacobians[v], INSERT_VALUES, local_jac[v]));
239 }
240 PetscFunctionReturn(0);
241}
Vec lIEta
Definition variables.h:1151
Vec lIZet
Definition variables.h:1151
Vec lKEta
Definition variables.h:1153
Vec lJCsi
Definition variables.h:1152
Vec lKZet
Definition variables.h:1153
Vec lJEta
Definition variables.h:1152
Vec lKCsi
Definition variables.h:1153
Vec lJZet
Definition variables.h:1152
Vec lICsi
Definition variables.h:1151
Here is the caller graph for this function:

◆ ClarkToMolecularRatioPerX()

static PetscErrorCode ClarkToMolecularRatioPerX ( PetscReal  h,
PetscInt  probe,
PetscReal *  ratio_per_x 
)
static

Returns the Clark contribution over the molecular viscous one, per unit x, at one cell.

The field is u_x = x^2 on cubic cells of edge h, so du/dx = 2x and the exact gradient-model stress tau_11 = (h^2/12)(du/dx)^2 varies along x. Both the model's and viscosity's contributions leave Viscous() through the same flux differences, so their ratio does not depend on how Viscous() normalizes its output.

Definition at line 252 of file test_poisson_rhs.c.

253{
254 SimCtx *simCtx = NULL;
255 UserCtx *user = NULL;
256 Vec molecular = NULL, with_clark = NULL;
257 Cmpnts ***ucat = NULL, ***visc0 = NULL, ***visc1 = NULL;
258 const PetscInt n = 10, mid = n / 2;
259
260 PetscFunctionBeginUser;
261 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, n, n, n));
262 PetscCall(ScaleMinimalMetricsToSpacing(user, h));
263 simCtx->ren = 1.0;
264 simCtx->les = NO_LES_MODEL;
265
266 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &ucat));
267 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k)
268 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j)
269 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
270 const PetscReal x = (i - 0.5) * h; /* cell centre */
271 ucat[k][j][i].x = x * x; ucat[k][j][i].y = 0.0; ucat[k][j][i].z = 0.0;
272 }
273 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &ucat));
274 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
275 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
276 PetscCall(VecSet(user->lUcont, 0.0));
277
278 PetscCall(VecDuplicate(user->lUcont, &molecular));
279 PetscCall(VecDuplicate(user->lUcont, &with_clark));
280 simCtx->les_gradient_model = 0;
281 PetscCall(Viscous(user, user->lUcont, user->lUcat, molecular));
282 simCtx->les_gradient_model = 1;
283 PetscCall(Viscous(user, user->lUcont, user->lUcat, with_clark));
284
285 PetscCall(DMDAVecGetArrayRead(user->fda, molecular, &visc0));
286 PetscCall(DMDAVecGetArrayRead(user->fda, with_clark, &visc1));
287 {
288 const PetscReal v_molecular = visc0[mid][mid][probe].x;
289 const PetscReal v_clark = visc1[mid][mid][probe].x - v_molecular;
290 PetscCheck(PetscAbsReal(v_molecular) > 0.0, PETSC_COMM_SELF, PETSC_ERR_PLIB,
291 "The molecular viscous term vanished at the probe; the fixture is wrong.");
292 *ratio_per_x = (v_clark / v_molecular) / ((probe - 0.5) * h);
293 }
294 PetscCall(DMDAVecRestoreArrayRead(user->fda, with_clark, &visc1));
295 PetscCall(DMDAVecRestoreArrayRead(user->fda, molecular, &visc0));
296 PetscCall(VecDestroy(&with_clark));
297 PetscCall(VecDestroy(&molecular));
298 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
299 PetscFunctionReturn(0);
300}
static PetscErrorCode ScaleMinimalMetricsToSpacing(UserCtx *user, PetscReal h)
Rescales the minimal fixture's unit metrics to cubic cells of edge h.
@ NO_LES_MODEL
Definition variables.h:549
PetscInt les_gradient_model
Add the Clark gradient (tensor-diffusivity) term to the viscous flux.
Definition variables.h:986
DMDALocalInfo info
Definition variables.h:1086
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestClarkGradientModelScalesWithFilterWidthSquared()

static PetscErrorCode TestClarkGradientModelScalesWithFilterWidthSquared ( void  )
static

Tests that the Clark gradient model scales as the square of the filter width.

The gradient-model stress is tau_ij = (Delta_k^2/12) du_i/dx_k du_j/dx_k, so for a fixed physical field its force grows as Delta^2 relative to the molecular viscous force. Halving the spacing must therefore divide the Clark-to-molecular ratio at a given x by four. Fixtures with unit cells hide any error in the power of Delta, which is why the spacing is varied here.

Definition at line 311 of file test_poisson_rhs.c.

312{
313 PetscReal coarse = 0.0, fine = 0.0;
314
315 PetscFunctionBeginUser;
316 /* Probe cells chosen so the two spacings give comparable x without being on a
317 boundary: cell 5 at h = 0.2 and cell 5 at h = 0.1. The ratio is per unit x. */
318 PetscCall(ClarkToMolecularRatioPerX(0.2, 5, &coarse));
319 PetscCall(ClarkToMolecularRatioPerX(0.1, 5, &fine));
320 PetscCall(PicurvAssertBool((PetscBool)(coarse < 0.0 && fine < 0.0),
321 "the gradient model removes momentum where du/dx grows along x"));
322 PetscCall(PicurvAssertRealNear(4.0, coarse / fine, 1.0e-8,
323 "halving the filter width divides the gradient-model force by four"));
324 /* Exact value: the molecular flux carries both halves of the symmetric stress,
325 2 nu du/dx per unit area, so its difference across a cell is 4 nu h^3 for
326 u = x^2; the model's is -(2/3) h^5 x. Their ratio per unit x is -h^2/(6 nu),
327 which pins the 1/12 coefficient as well as the power of Delta. */
328 PetscCall(PicurvAssertRealNear(-0.2 * 0.2 / 6.0, coarse, 1.0e-10,
329 "gradient-model force matches (Delta^2/12) du/dx du/dx at h = 0.2"));
330 PetscCall(PicurvAssertRealNear(-0.1 * 0.1 / 6.0, fine, 1.0e-10,
331 "gradient-model force matches (Delta^2/12) du/dx du/dx at h = 0.1"));
332 PetscFunctionReturn(0);
333}
static PetscErrorCode ClarkToMolecularRatioPerX(PetscReal h, PetscInt probe, PetscReal *ratio_per_x)
Returns the Clark contribution over the molecular viscous one, per unit x, at one cell.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestComputeRHSZeroFieldNoForcing()

static PetscErrorCode TestComputeRHSZeroFieldNoForcing ( void  )
static

Tests that the full RHS remains zero without forcing on a quiescent field.

Definition at line 339 of file test_poisson_rhs.c.

340{
341 SimCtx *simCtx = NULL;
342 UserCtx *user = NULL;
343
344 PetscFunctionBeginUser;
345 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
346 PetscCall(VecSet(user->Ucont, 0.0));
347 PetscCall(VecSet(user->Ucat, 0.0));
348 PetscCall(VecSet(user->Nvert, 0.0));
349 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
350 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
351 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
352 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucat, INSERT_VALUES, user->lUcat));
353 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
354 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
355
356 PetscCall(ComputeRHS(user, user->Rhs));
357 PetscCall(PicurvAssertVecConstant(user->Rhs, 0.0, 1.0e-12, "ComputeRHS should remain zero without forcing on a quiescent field"));
358
359 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
360 PetscFunctionReturn(0);
361}
PetscErrorCode ComputeRHS(UserCtx *user, Vec Rhs)
Computes the Right-Hand Side (RHS) of the momentum equations.
Definition rhs.c:1157
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestComputeEulerianDiffusivityGradientConstantField()

static PetscErrorCode TestComputeEulerianDiffusivityGradientConstantField ( void  )
static

Tests diffusivity-gradient computation on a constant field.

Definition at line 366 of file test_poisson_rhs.c.

367{
368 SimCtx *simCtx = NULL;
369 UserCtx *user = NULL;
370
371 PetscFunctionBeginUser;
372 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
373 PetscCall(VecSet(user->Diffusivity, 0.75));
374 PetscCall(DMGlobalToLocalBegin(user->da, user->Diffusivity, INSERT_VALUES, user->lDiffusivity));
375 PetscCall(DMGlobalToLocalEnd(user->da, user->Diffusivity, INSERT_VALUES, user->lDiffusivity));
376
377 PetscCall(ComputeEulerianDiffusivityGradient(user));
378 PetscCall(PicurvAssertVecConstant(user->DiffusivityGradient, 0.0, 1.0e-12, "constant diffusivity should yield zero diffusivity gradient"));
379
380 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
381 PetscFunctionReturn(0);
382}
PetscErrorCode ComputeEulerianDiffusivityGradient(UserCtx *user)
Computes the Eulerian gradient of the effective diffusivity field.
Definition rhs.c:1999
Vec DiffusivityGradient
Definition variables.h:1117
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestComputeEulerianDiffusivityVerificationLinearX()

static PetscErrorCode TestComputeEulerianDiffusivityVerificationLinearX ( void  )
static

Tests verification-driven linear diffusivity override and its gradient.

Definition at line 387 of file test_poisson_rhs.c.

388{
389 SimCtx *simCtx = NULL;
390 UserCtx *user = NULL;
391 PetscReal ***diff_arr = NULL;
392 Cmpnts ***grad_arr = NULL;
393 Cmpnts ***cent = NULL;
394 const PetscReal gamma0 = 0.5;
395 const PetscReal slope_x = 0.25;
396
397 PetscFunctionBeginUser;
398 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
399 PetscCall(PetscStrncpy(simCtx->eulerianSource, "analytical", sizeof(simCtx->eulerianSource)));
400 simCtx->verificationDiffusivity.enabled = PETSC_TRUE;
401 PetscCall(PetscStrncpy(simCtx->verificationDiffusivity.mode, "analytical", sizeof(simCtx->verificationDiffusivity.mode)));
402 PetscCall(PetscStrncpy(simCtx->verificationDiffusivity.profile, "LINEAR_X", sizeof(simCtx->verificationDiffusivity.profile)));
403 simCtx->verificationDiffusivity.gamma0 = gamma0;
404 simCtx->verificationDiffusivity.slope_x = slope_x;
405
407 "verification diffusivity override should report as active"));
408 PetscCall(ComputeEulerianDiffusivity(user));
409 PetscCall(ComputeEulerianDiffusivityGradient(user));
410
411 PetscCall(DMDAVecGetArrayRead(user->da, user->Diffusivity, &diff_arr));
412 PetscCall(DMDAVecGetArrayRead(user->fda, user->Cent, &cent));
413 PetscCall(PicurvAssertRealNear(gamma0 + slope_x * cent[2][2][2].x, diff_arr[2][2][2], 1.0e-12,
414 "verification override should populate the linear diffusivity field"));
415 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Cent, &cent));
416 PetscCall(DMDAVecRestoreArrayRead(user->da, user->Diffusivity, &diff_arr));
417
418 PetscCall(DMDAVecGetArrayRead(user->fda, user->DiffusivityGradient, &grad_arr));
419 PetscCall(PicurvAssertRealNear(slope_x / user->IM, grad_arr[2][2][2].x, 1.0e-12,
420 "linear verification diffusivity should yield the current finite-difference x gradient"));
421 PetscCall(PicurvAssertRealNear(0.0, grad_arr[2][2][2].y, 1.0e-12,
422 "linear verification diffusivity should keep y gradient zero"));
423 PetscCall(PicurvAssertRealNear(0.0, grad_arr[2][2][2].z, 1.0e-12,
424 "linear verification diffusivity should keep z gradient zero"));
425 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->DiffusivityGradient, &grad_arr));
426
427 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
428 PetscFunctionReturn(0);
429}
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:879
PetscInt IM
Definition variables.h:1088
VerificationDiffusivityConfig verificationDiffusivity
Definition variables.h:939
PetscBool VerificationDiffusivityOverrideActive(const SimCtx *simCtx)
Reports whether a verification-only diffusivity override is active.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestAssemblePoissonOperatorPopulatesRows()

static PetscErrorCode TestAssemblePoissonOperatorPopulatesRows ( void  )
static

Tests that Poisson matrix assembly produces a populated operator on a tiny Cartesian grid.

Definition at line 433 of file test_poisson_rhs.c.

434{
435 SimCtx *simCtx = NULL;
436 UserCtx *user = NULL;
437 PetscInt rows = 0, cols = 0;
438 PetscInt ncols = 0;
439 const PetscInt *col_idx = NULL;
440 const PetscScalar *values = NULL;
441 PetscInt interior_row = 0;
442
443 PetscFunctionBeginUser;
444 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 4, 4, 4));
445 PetscCall(VecSet(user->Nvert, 0.0));
446 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
447 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
448
449 PetscCall(AssemblePoissonOperator(user));
450 PetscCall(PicurvAssertBool((PetscBool)(user->A != NULL), "AssemblePoissonOperator should allocate the Poisson operator"));
451
452 PetscCall(MatGetSize(user->A, &rows, &cols));
453 PetscCall(PicurvAssertIntEqual(user->info.mx * user->info.my * user->info.mz, rows, "Poisson operator row count should match the DA node count"));
454 PetscCall(PicurvAssertIntEqual(rows, cols, "Poisson operator should be square"));
455
456 interior_row = (2 * user->info.my + 2) * user->info.mx + 2;
457 PetscCall(MatGetRow(user->A, interior_row, &ncols, &col_idx, &values));
458 PetscCall(PicurvAssertBool((PetscBool)(ncols > 1), "Interior Poisson row should couple to neighboring nodes"));
459 PetscCall(PicurvAssertBool((PetscBool)(values != NULL), "Interior Poisson row should expose non-null coefficients"));
460 PetscCall(MatRestoreRow(user->A, interior_row, &ncols, &col_idx, &values));
461
462 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
463 PetscFunctionReturn(0);
464}
PetscErrorCode AssemblePoissonOperator(UserCtx *user)
Assembles the pressure-correction operator on one multigrid level.
Definition poisson.c:251
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RandomizeMinimalFaceMetrics()

static PetscErrorCode RandomizeMinimalFaceMetrics ( UserCtx *  user)
static

Fills every face metric and Jacobian of the minimal fixture with reproducible random values, so each face gradient carries all of its cross terms.

Definition at line 469 of file test_poisson_rhs.c.

470{
471 Vec face_metrics[9] = {user->ICsi, user->IEta, user->IZet, user->JCsi, user->JEta,
472 user->JZet, user->KCsi, user->KEta, user->KZet};
473 Vec local_metrics[9] = {user->lICsi, user->lIEta, user->lIZet, user->lJCsi, user->lJEta,
474 user->lJZet, user->lKCsi, user->lKEta, user->lKZet};
475 Vec jacobians[4] = {user->Aj, user->IAj, user->JAj, user->KAj};
476 Vec local_jac[4] = {user->lAj, user->lIAj, user->lJAj, user->lKAj};
477 PetscRandom rnd;
478
479 PetscFunctionBeginUser;
480 PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rnd));
481 PetscCall(PetscRandomSetInterval(rnd, 0.5, 1.5));
482 PetscCall(PetscRandomSetSeed(rnd, 2026));
483 PetscCall(PetscRandomSeed(rnd));
484 for (PetscInt v = 0; v < 9; ++v) {
485 PetscCall(VecSetRandom(face_metrics[v], rnd));
486 PetscCall(DMGlobalToLocalBegin(user->fda, face_metrics[v], INSERT_VALUES, local_metrics[v]));
487 PetscCall(DMGlobalToLocalEnd(user->fda, face_metrics[v], INSERT_VALUES, local_metrics[v]));
488 }
489 for (PetscInt v = 0; v < 4; ++v) {
490 PetscCall(VecSetRandom(jacobians[v], rnd));
491 PetscCall(DMGlobalToLocalBegin(user->da, jacobians[v], INSERT_VALUES, local_jac[v]));
492 PetscCall(DMGlobalToLocalEnd(user->da, jacobians[v], INSERT_VALUES, local_jac[v]));
493 }
494 PetscCall(PetscRandomDestroy(&rnd));
495 PetscFunctionReturn(0);
496}
Here is the caller graph for this function:

◆ TestOperatorAndProjectionShareOneFaceGradient()

static PetscErrorCode TestOperatorAndProjectionShareOneFaceGradient ( void  )
static

Tests that the operator is exactly the divergence of the projection's gradient.

With random non-orthogonal metrics and one solid cell, projecting a zero flux with a random Phi and forming the right-hand side of the result must reproduce -A Phi on every fluid row. The identity holds for any metric values only if the operator and the projection use the same face gradient, including its one-sided forms beside walls and solid cells.

Definition at line 506 of file test_poisson_rhs.c.

507{
508 SimCtx *simCtx = NULL;
509 UserCtx *user = NULL;
510 Vec B = NULL, APhi = NULL;
511 PetscRandom rnd;
512 PetscReal ***nvert;
513 const PetscReal ***b, ***aphi;
514 PetscReal worst = 0.0;
515
516 PetscFunctionBeginUser;
517 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 7, 7, 7));
518 PetscCall(EnsurePoissonAndRhsVectors(user));
519 simCtx->dt = 0.3;
520 PetscCall(RandomizeMinimalFaceMetrics(user));
521
522 PetscCall(VecSet(user->Nvert, 0.0));
523 PetscCall(DMDAVecGetArray(user->da, user->Nvert, &nvert));
524 if (user->info.xs <= 3 && 3 < user->info.xs + user->info.xm &&
525 user->info.ys <= 3 && 3 < user->info.ys + user->info.ym &&
526 user->info.zs <= 3 && 3 < user->info.zs + user->info.zm) nvert[3][3][3] = 1.0;
527 PetscCall(DMDAVecRestoreArray(user->da, user->Nvert, &nvert));
528 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
529 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
530
531 PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rnd));
532 PetscCall(PetscRandomSetSeed(rnd, 7));
533 PetscCall(PetscRandomSeed(rnd));
534 PetscCall(VecSetRandom(user->Phi, rnd));
535 PetscCall(PetscRandomDestroy(&rnd));
536 PetscCall(DMGlobalToLocalBegin(user->da, user->Phi, INSERT_VALUES, user->lPhi));
537 PetscCall(DMGlobalToLocalEnd(user->da, user->Phi, INSERT_VALUES, user->lPhi));
538 PetscCall(VecSet(user->Ucont, 0.0));
539 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
540 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
541
542 PetscCall(AssemblePoissonOperator(user));
543 PetscCall(ProjectVelocity(user));
544 PetscCall(VecDuplicate(user->P, &B));
545 PetscCall(ComputePoissonRHS(user, B));
546 PetscCall(VecDuplicate(user->Phi, &APhi));
547 PetscCall(MatMult(user->A, user->Phi, APhi));
548
549 PetscCall(DMDAVecGetArrayRead(user->da, B, &b));
550 PetscCall(DMDAVecGetArrayRead(user->da, APhi, &aphi));
551 PetscCall(DMDAVecGetArray(user->da, user->Nvert, &nvert));
552 for (PetscInt k = PetscMax(user->info.zs, 1); k < PetscMin(user->info.zs + user->info.zm, user->info.mz - 1); k++) {
553 for (PetscInt j = PetscMax(user->info.ys, 1); j < PetscMin(user->info.ys + user->info.ym, user->info.my - 1); j++) {
554 for (PetscInt i = PetscMax(user->info.xs, 1); i < PetscMin(user->info.xs + user->info.xm, user->info.mx - 1); i++) {
555 if (nvert[k][j][i] > 0.1) continue;
556 worst = PetscMax(worst, PetscAbsReal(b[k][j][i] + aphi[k][j][i]) / (1.0 + PetscAbsReal(aphi[k][j][i])));
557 }
558 }
559 }
560 PetscCall(DMDAVecRestoreArray(user->da, user->Nvert, &nvert));
561 PetscCall(DMDAVecRestoreArrayRead(user->da, APhi, &aphi));
562 PetscCall(DMDAVecRestoreArrayRead(user->da, B, &b));
563 PetscCall(PicurvAssertRealNear(0.0, worst, 1.0e-12,
564 "the right-hand side of the projected flux should equal -A Phi on every fluid row"));
565
566 PetscCall(VecDestroy(&APhi));
567 PetscCall(VecDestroy(&B));
568 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
569 PetscFunctionReturn(0);
570}
PetscErrorCode ProjectVelocity(UserCtx *user)
Corrects the contravariant flux with the gradient of Phi.
Definition poisson.c:438
static PetscErrorCode RandomizeMinimalFaceMetrics(UserCtx *user)
Fills every face metric and Jacobian of the minimal fixture with reproducible random values,...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestProjectionZeroPhiLeavesVelocityUnchanged()

static PetscErrorCode TestProjectionZeroPhiLeavesVelocityUnchanged ( void  )
static

Tests that projection leaves a zero pressure-correction field unchanged.

Definition at line 575 of file test_poisson_rhs.c.

576{
577 SimCtx *simCtx = NULL;
578 UserCtx *user = NULL;
579
580 PetscFunctionBeginUser;
581 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
582 PetscCall(VecSet(user->Ucont, 0.0));
583 PetscCall(VecSet(user->Phi, 0.0));
584 PetscCall(VecSet(user->Nvert, 0.0));
585 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
586 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
587 PetscCall(DMGlobalToLocalBegin(user->da, user->Phi, INSERT_VALUES, user->lPhi));
588 PetscCall(DMGlobalToLocalEnd(user->da, user->Phi, INSERT_VALUES, user->lPhi));
589 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
590 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
591
592 PetscCall(ProjectVelocity(user));
593 PetscCall(PicurvAssertVecConstant(user->Ucont, 0.0, 1.0e-12, "ProjectVelocity should leave a zero-velocity field unchanged when Phi is zero"));
594
595 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
596 PetscFunctionReturn(0);
597}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestProjectionLinearPhiCorrectsVelocity()

static PetscErrorCode TestProjectionLinearPhiCorrectsVelocity ( void  )
static

Tests that projection applies the expected x-direction correction for a linear pressure field.

Definition at line 601 of file test_poisson_rhs.c.

602{
603 SimCtx *simCtx = NULL;
604 UserCtx *user = NULL;
605 PetscReal ***phi = NULL;
606 Cmpnts ***ucont = NULL;
607
608 PetscFunctionBeginUser;
609 PetscCall(PicurvCreateMinimalContexts(&simCtx, &user, 6, 6, 6));
610 simCtx->dt = COEF_TIME_ACCURACY;
611 PetscCall(VecSet(user->Ucont, 0.0));
612 PetscCall(VecSet(user->Nvert, 0.0));
613 PetscCall(DMDAVecGetArray(user->da, user->Phi, &phi));
614 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; ++k) {
615 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; ++j) {
616 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; ++i) {
617 phi[k][j][i] = (PetscReal)i;
618 }
619 }
620 }
621 PetscCall(DMDAVecRestoreArray(user->da, user->Phi, &phi));
622 PetscCall(DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
623 PetscCall(DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont));
624 PetscCall(DMGlobalToLocalBegin(user->da, user->Phi, INSERT_VALUES, user->lPhi));
625 PetscCall(DMGlobalToLocalEnd(user->da, user->Phi, INSERT_VALUES, user->lPhi));
626 PetscCall(DMGlobalToLocalBegin(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
627 PetscCall(DMGlobalToLocalEnd(user->da, user->Nvert, INSERT_VALUES, user->lNvert));
628
629 PetscCall(ProjectVelocity(user));
630
631 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucont, &ucont));
632 PetscCall(PicurvAssertRealNear(-1.0, ucont[2][2][2].x, 1.0e-10, "ProjectVelocity should subtract the x pressure gradient under identity metrics"));
633 PetscCall(PicurvAssertRealNear(0.0, ucont[2][2][2].y, 1.0e-10, "ProjectVelocity should leave the y component unchanged for an x-only gradient"));
634 PetscCall(PicurvAssertRealNear(0.0, ucont[2][2][2].z, 1.0e-10, "ProjectVelocity should leave the z component unchanged for an x-only gradient"));
635 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucont, &ucont));
636
637 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
638 PetscFunctionReturn(0);
639}
#define COEF_TIME_ACCURACY
Coefficient controlling the temporal accuracy scheme (e.g., 1.5 for 2nd Order Backward Difference).
Definition variables.h:75
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PerturbInteriorFaceFluxes()

static PetscErrorCode PerturbInteriorFaceFluxes ( UserCtx *  user,
PetscReal  amplitude 
)
static

Adds a smooth divergent perturbation to every interior face flux.

Boundary faces are left alone, so the inflow still balances the outflow and the Neumann pressure problem stays solvable.

Definition at line 645 of file test_poisson_rhs.c.

646{
647 DMDALocalInfo info = user->info;
648 Cmpnts ***ucont;
649
650 PetscFunctionBeginUser;
651 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &ucont));
652 for (PetscInt k = PetscMax(info.zs, 1); k < PetscMin(info.zs + info.zm, info.mz - 1); k++) {
653 for (PetscInt j = PetscMax(info.ys, 1); j < PetscMin(info.ys + info.ym, info.my - 1); j++) {
654 for (PetscInt i = PetscMax(info.xs, 1); i < PetscMin(info.xs + info.xm, info.mx - 1); i++) {
655 if (i <= info.mx - 3) ucont[k][j][i].x += amplitude * PetscSinReal(1.3 * i + 0.7 * j + 0.4 * k);
656 if (j <= info.my - 3) ucont[k][j][i].y += amplitude * PetscCosReal(0.9 * i + 1.1 * j + 0.3 * k);
657 if (k <= info.mz - 3) ucont[k][j][i].z += amplitude * PetscSinReal(0.5 * i + 0.8 * j + 1.7 * k);
658 }
659 }
660 }
661 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &ucont));
662 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCONT));
663 PetscFunctionReturn(0);
664}
@ FIELD_ID_UCONT
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:2489
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPoissonSolverMultigridProjectsToDivergenceFree()

static PetscErrorCode TestPoissonSolverMultigridProjectsToDivergenceFree ( void  )
static

Tests that the production multigrid Poisson solve and projection remove a divergence.

Runs PoissonSolver_Multigrid through the real setup path with a three-level hierarchy, then the same UpdatePressure/ProjectVelocity pair the time loop uses, and requires the projected field to be divergence-free to the solve tolerance.

Definition at line 672 of file test_poisson_rhs.c.

673{
674 SimCtx *simCtx = NULL;
675 UserCtx *user = NULL;
676 char tmpdir[PETSC_MAX_PATH_LEN];
677 PetscReal before;
678
679 PetscFunctionBeginUser;
681 NULL, PETSC_FALSE,
682 "-im 17\n-jm 17\n-km 17\n-mg_level 3\n"
683 "-ps_ksp_rtol 1.0e-12\n-ps_ksp_atol 1.0e-14\n-ps_ksp_max_it 200\n",
684 &simCtx, &user, tmpdir, sizeof(tmpdir)));
685 PetscCall(PicurvAssertIntEqual(3, simCtx->usermg.mglevels, "fixture should build a three-level hierarchy"));
686
687 PetscCall(PerturbInteriorFaceFluxes(user, 0.2));
688 PetscCall(ComputeDivergence(user));
689 before = simCtx->MaxDiv;
690 PetscCall(PicurvAssertBool((PetscBool)(before > 1.0e-2), "perturbation should make the field divergent"));
691
692 PetscCall(PoissonSolver_Multigrid(&simCtx->usermg));
693 PetscCall(UpdatePressure(user));
694 PetscCall(ProjectVelocity(user));
695 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCONT));
696 PetscCall(ComputeDivergence(user));
697 PetscCall(PicurvAssertBool((PetscBool)(simCtx->MaxDiv < 1.0e-9 * before),
698 "multigrid solve plus projection should leave no divergence above the solve tolerance"));
699
700 PetscCall(PicurvDestroyRuntimeContext(&simCtx));
701 PetscCall(PicurvRemoveTempDir(tmpdir));
702 PetscFunctionReturn(0);
703}
PetscErrorCode PoissonSolver_Multigrid(UserMG *usermg)
Solves the pressure-correction equation for every block with geometric multigrid.
Definition poisson.c:952
PetscErrorCode ComputeDivergence(UserCtx *user)
Computes the discrete divergence of the contravariant velocity field.
Definition setup.c:3685
static PetscErrorCode PerturbInteriorFaceFluxes(UserCtx *user, PetscReal amplitude)
Adds a smooth divergent perturbation to every interior face flux.
PetscErrorCode PicurvDestroyRuntimeContext(SimCtx **simCtx_ptr)
Finalizes and frees a runtime context built by PicurvBuildTinyRuntimeContext.
PetscErrorCode PicurvBuildTinyRuntimeContextWithOptions(const char *bcs_contents, PetscBool enable_particles, const char *extra_options, SimCtx **simCtx_out, UserCtx **user_out, char *tmpdir, size_t tmpdir_len)
Builds the tiny runtime context with extra control-file options appended.
PetscErrorCode PicurvRemoveTempDir(const char *path)
Recursively removes a temporary directory created by PicurvMakeTempDir.
UserMG usermg
Definition variables.h:1015
PetscReal MaxDiv
Definition variables.h:1027
PetscInt mglevels
Definition variables.h:736
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CountFileOccurrences()

static PetscErrorCode CountFileOccurrences ( const char *  path,
const char *  needle,
PetscInt *  count 
)
static

Counts the occurrences of needle in a text file; a missing file counts zero.

Definition at line 708 of file test_poisson_rhs.c.

709{
710 FILE *file;
711 char line[1024];
712
713 PetscFunctionBeginUser;
714 *count = 0;
715 file = fopen(path, "r");
716 if (!file) PetscFunctionReturn(0);
717 while (fgets(line, sizeof(line), file)) {
718 if (strstr(line, needle)) (*count)++;
719 }
720 fclose(file);
721 PetscFunctionReturn(0);
722}
Here is the caller graph for this function:

◆ TestPoissonSolverMultigridReusesItsSolver()

static PetscErrorCode TestPoissonSolverMultigridReusesItsSolver ( void  )
static

Tests that the multigrid solver is built once and reused on later steps.

Two consecutive solves must use the same Krylov solver and operator, both must converge, and the convergence log must hold one header per step.

Definition at line 729 of file test_poisson_rhs.c.

730{
731 SimCtx *simCtx = NULL;
732 UserCtx *user = NULL;
733 char tmpdir[PETSC_MAX_PATH_LEN], log_path[PETSC_MAX_PATH_LEN + 64];
734 KSP first_ksp;
735 Mat first_operator;
736 KSPConvergedReason reason;
737 PetscInt headers = 0;
738
739 PetscFunctionBeginUser;
741 NULL, PETSC_FALSE,
742 "-im 17\n-jm 17\n-km 17\n-mg_level 3\n"
743 "-ps_ksp_rtol 1.0e-12\n-ps_ksp_atol 1.0e-14\n-ps_ksp_max_it 200\n",
744 &simCtx, &user, tmpdir, sizeof(tmpdir)));
745
746 simCtx->step = simCtx->StartStep + 1;
747 PetscCall(PerturbInteriorFaceFluxes(user, 0.2));
748 PetscCall(PoissonSolver_Multigrid(&simCtx->usermg));
749 first_ksp = user->ksp;
750 first_operator = user->A;
751 PetscCall(PicurvAssertBool((PetscBool)(first_ksp != NULL), "the first solve should build and keep the solver"));
752 PetscCall(KSPGetConvergedReason(user->ksp, &reason));
753 PetscCall(PicurvAssertBool((PetscBool)(reason > 0), "the first solve should converge"));
754
755 simCtx->step++;
756 PetscCall(PerturbInteriorFaceFluxes(user, 0.1));
757 PetscCall(PoissonSolver_Multigrid(&simCtx->usermg));
758 PetscCall(PicurvAssertBool((PetscBool)(user->ksp == first_ksp), "the second solve should reuse the solver"));
759 PetscCall(PicurvAssertBool((PetscBool)(user->A == first_operator), "the second solve should reuse the operator"));
760 PetscCall(KSPGetConvergedReason(user->ksp, &reason));
761 PetscCall(PicurvAssertBool((PetscBool)(reason > 0), "the reused solver should converge"));
762
763 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/Poisson_Solver_Convergence_History_Block_0.log", simCtx->log_dir));
764 PetscCall(CountFileOccurrences(log_path, "--- Convergence for Timestep", &headers));
765 PetscCall(PicurvAssertIntEqual(2, headers, "the convergence log should hold one header per solve"));
766
767 PetscCall(PicurvDestroyRuntimeContext(&simCtx));
768 PetscCall(PicurvRemoveTempDir(tmpdir));
769 PetscFunctionReturn(0);
770}
static PetscErrorCode CountFileOccurrences(const char *path, const char *needle, PetscInt *count)
Counts the occurrences of needle in a text file; a missing file counts zero.
PetscInt StartStep
Definition variables.h:869
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:882
PetscInt step
Definition variables.h:867
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPoissonSolverMultigridHonoursDistinctSweeps()

static PetscErrorCode TestPoissonSolverMultigridHonoursDistinctSweeps ( void  )
static

Tests that unequal pre- and post-smoothing counts give two distinct smoothers.

With pre_sweeps 1 and post_sweeps 3 every smoothed level must run one sweep before the coarse correction and three after it, the post-smoother must keep the configured smoother type, and the solve must still remove the divergence. With equal counts the shared smoother runs the configured sweeps.

Definition at line 779 of file test_poisson_rhs.c.

780{
781 const char *const configurations[2] = {
782 "-im 17\n-jm 17\n-km 17\n-mg_level 3\n-mg_pre_it 1\n-mg_post_it 3\n"
783 "-ps_mg_levels_1_ksp_type richardson\n-ps_mg_levels_2_ksp_type richardson\n"
784 "-ps_ksp_rtol 1.0e-12\n-ps_ksp_atol 1.0e-14\n-ps_ksp_max_it 200\n",
785 "-im 17\n-jm 17\n-km 17\n-mg_level 3\n-mg_pre_it 2\n-mg_post_it 2\n",
786 };
787
788 PetscFunctionBeginUser;
789 for (PetscInt c = 0; c < 2; c++) {
790 SimCtx *simCtx = NULL;
791 UserCtx *user = NULL;
792 char tmpdir[PETSC_MAX_PATH_LEN];
793 PC pc;
794 PetscReal before;
795
796 PetscCall(PicurvBuildTinyRuntimeContextWithOptions(NULL, PETSC_FALSE, configurations[c],
797 &simCtx, &user, tmpdir, sizeof(tmpdir)));
798 PetscCall(PerturbInteriorFaceFluxes(user, 0.2));
799 PetscCall(ComputeDivergence(user));
800 before = simCtx->MaxDiv;
801 PetscCall(PoissonSolver_Multigrid(&simCtx->usermg));
802 PetscCall(KSPGetPC(user->ksp, &pc));
803
804 for (PetscInt l = 1; l < simCtx->usermg.mglevels; l++) {
805 KSP pre_smoother, post_smoother;
806 PetscInt pre_its, post_its;
807 PetscBool is_richardson;
808
809 PetscCall(PCMGGetSmootherDown(pc, l, &pre_smoother));
810 PetscCall(KSPGetTolerances(pre_smoother, NULL, NULL, NULL, &pre_its));
811 if (c == 0) {
812 PetscCall(PCMGGetSmootherUp(pc, l, &post_smoother));
813 PetscCall(KSPGetTolerances(post_smoother, NULL, NULL, NULL, &post_its));
814 PetscCall(PicurvAssertBool((PetscBool)(pre_smoother != post_smoother), "unequal sweeps should give a separate post-smoother"));
815 PetscCall(PicurvAssertIntEqual(1, pre_its, "pre-smoothing should run pre_sweeps iterations"));
816 PetscCall(PicurvAssertIntEqual(3, post_its, "post-smoothing should run post_sweeps iterations"));
817 PetscCall(PetscObjectTypeCompare((PetscObject)post_smoother, KSPRICHARDSON, &is_richardson));
818 PetscCall(PicurvAssertBool(is_richardson, "the post-smoother should keep the configured smoother type"));
819 } else {
820 /* PCMGGetSmootherUp() would itself split a shared smoother, so only the
821 shared one is inspected here. */
822 PetscCall(PicurvAssertIntEqual(2, pre_its, "the shared smoother should run the configured sweeps"));
823 }
824 }
825
826 if (c == 0) {
827 PetscCall(UpdatePressure(user));
828 PetscCall(ProjectVelocity(user));
829 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCONT));
830 PetscCall(ComputeDivergence(user));
831 PetscCall(PicurvAssertBool((PetscBool)(simCtx->MaxDiv < 1.0e-9 * before),
832 "the solve with distinct sweeps should still remove the divergence"));
833 }
834 PetscCall(PicurvDestroyRuntimeContext(&simCtx));
835 PetscCall(PicurvRemoveTempDir(tmpdir));
836 }
837 PetscFunctionReturn(0);
838}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPoissonNullSpaceRemovesTheInteriorMean()

static PetscErrorCode TestPoissonNullSpaceRemovesTheInteriorMean ( void  )
static

Tests the null space attached to the operator.

Removing it from a constant must leave zero everywhere, and from a linear field must leave zero mean over the interior with zero dummy layers.

Definition at line 845 of file test_poisson_rhs.c.

846{
847 SimCtx *simCtx = NULL;
848 UserCtx *user = NULL;
849 char tmpdir[PETSC_MAX_PATH_LEN];
850 MatNullSpace nullsp = NULL;
851 Vec x = NULL;
852 PetscReal ***xa, norm, sum;
853
854 PetscFunctionBeginUser;
856 NULL, PETSC_FALSE, "-im 9\n-jm 9\n-km 9\n-mg_level 2\n", &simCtx, &user, tmpdir, sizeof(tmpdir)));
857 PetscCall(PoissonSolver_Multigrid(&simCtx->usermg));
858 PetscCall(MatGetNullSpace(user->A, &nullsp));
859 PetscCall(PicurvAssertBool((PetscBool)(nullsp != NULL), "the operator should carry the Neumann null space"));
860
861 PetscCall(VecDuplicate(user->Phi, &x));
862 PetscCall(VecSet(x, 3.0));
863 PetscCall(MatNullSpaceRemove(nullsp, x));
864 PetscCall(VecNorm(x, NORM_INFINITY, &norm));
865 PetscCall(PicurvAssertRealNear(0.0, norm, 1.0e-12, "removing the null space should annihilate a constant"));
866
867 PetscCall(DMDAVecGetArray(user->da, x, &xa));
868 for (PetscInt k = user->info.zs; k < user->info.zs + user->info.zm; k++)
869 for (PetscInt j = user->info.ys; j < user->info.ys + user->info.ym; j++)
870 for (PetscInt i = user->info.xs; i < user->info.xs + user->info.xm; i++) xa[k][j][i] = (PetscReal)i;
871 PetscCall(DMDAVecRestoreArray(user->da, x, &xa));
872 PetscCall(MatNullSpaceRemove(nullsp, x));
873 PetscCall(VecSum(x, &sum));
874 PetscCall(PicurvAssertRealNear(0.0, sum, 1.0e-10, "the interior mean should vanish"));
875 PetscCall(DMDAVecGetArray(user->da, x, &xa));
876 if (user->info.xs == 0) PetscCall(PicurvAssertRealNear(0.0, xa[user->info.zs][user->info.ys][0], 1.0e-14, "dummy layers should be zero"));
877 PetscCall(DMDAVecRestoreArray(user->da, x, &xa));
878
879 PetscCall(VecDestroy(&x));
880 PetscCall(PicurvDestroyRuntimeContext(&simCtx));
881 PetscCall(PicurvRemoveTempDir(tmpdir));
882 PetscFunctionReturn(0);
883}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestPoissonSolverMultigridRefusesAnOvercoarsenedHierarchy()

static PetscErrorCode TestPoissonSolverMultigridRefusesAnOvercoarsenedHierarchy ( void  )
static

Tests that an over-coarsened hierarchy stops the run at the Poisson solve.

Three levels on a 9-node grid leave a coarse operator the preconditioner cannot factor. The solve must return PETSC_ERR_NOT_CONVERGED rather than hand an unsolved Phi to the projection.

Definition at line 891 of file test_poisson_rhs.c.

892{
893 SimCtx *simCtx = NULL;
894 UserCtx *user = NULL;
895 char tmpdir[PETSC_MAX_PATH_LEN];
896 PetscErrorCode solve_error;
897
898 PetscFunctionBeginUser;
900 NULL, PETSC_FALSE,
901 "-im 9\n-jm 9\n-km 9\n-mg_level 3\n"
902 /* The shipped profiles solve the coarse level with a replicated direct factor. */
903 "-ps_ksp_type fgmres\n-ps_pc_type mg\n"
904 "-ps_mg_coarse_ksp_type preonly\n-ps_mg_coarse_pc_type redundant\n",
905 &simCtx, &user, tmpdir, sizeof(tmpdir)));
906 PetscCall(PerturbInteriorFaceFluxes(user, 0.2));
907
908 PetscCall(PetscPushErrorHandler(PetscReturnErrorHandler, NULL));
909 solve_error = PoissonSolver_Multigrid(&simCtx->usermg);
910 PetscCall(PetscPopErrorHandler());
911 PetscCall(PicurvAssertIntEqual(PETSC_ERR_NOT_CONVERGED, (PetscInt)solve_error,
912 "an unfactorable coarse level should stop the solve, not reach the projection"));
913
914 PetscCall(PicurvDestroyRuntimeContext(&simCtx));
915 PetscCall(PicurvRemoveTempDir(tmpdir));
916 PetscFunctionReturn(0);
917}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Runs the unit-poisson-rhs PETSc test binary.

Definition at line 922 of file test_poisson_rhs.c.

923{
924 PetscErrorCode ierr;
925 const PicurvTestCase cases[] = {
926 {"update-pressure-adds-phi", TestUpdatePressureAddsPhi},
927 {"poisson-rhs-zero-divergence", TestPoissonRHSZeroDivergence},
928 {"compute-body-forces-dispatcher", TestComputeBodyForcesDispatcher},
929 {"compute-eulerian-diffusivity-molecular-only", TestComputeEulerianDiffusivityMolecularOnly},
930 {"convection-zero-field", TestConvectionZeroField},
931 {"viscous-uniform-field", TestViscousUniformField},
932 {"clark-gradient-model-scales-with-filter-width-squared", TestClarkGradientModelScalesWithFilterWidthSquared},
933 {"compute-rhs-zero-field-no-forcing", TestComputeRHSZeroFieldNoForcing},
934 {"compute-eulerian-diffusivity-gradient-constant-field", TestComputeEulerianDiffusivityGradientConstantField},
935 {"compute-eulerian-diffusivity-verification-linear-x", TestComputeEulerianDiffusivityVerificationLinearX},
936 {"assemble-poisson-operator-populates-rows", TestAssemblePoissonOperatorPopulatesRows},
937 {"operator-and-projection-share-one-face-gradient", TestOperatorAndProjectionShareOneFaceGradient},
938 {"projection-zero-phi-leaves-velocity-unchanged", TestProjectionZeroPhiLeavesVelocityUnchanged},
939 {"projection-linear-phi-corrects-velocity", TestProjectionLinearPhiCorrectsVelocity},
940 {"poisson-solver-multigrid-projects-to-divergence-free", TestPoissonSolverMultigridProjectsToDivergenceFree},
941 {"poisson-solver-multigrid-reuses-its-solver", TestPoissonSolverMultigridReusesItsSolver},
942 {"poisson-solver-multigrid-honours-distinct-sweeps", TestPoissonSolverMultigridHonoursDistinctSweeps},
943 {"poisson-null-space-removes-the-interior-mean", TestPoissonNullSpaceRemovesTheInteriorMean},
944 {"poisson-solver-multigrid-refuses-an-overcoarsened-hierarchy", TestPoissonSolverMultigridRefusesAnOvercoarsenedHierarchy},
945 };
946
947 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv Poisson/RHS tests");
948 if (ierr) {
949 return (int)ierr;
950 }
951
952 ierr = PicurvRunTests("unit-poisson-rhs", cases, sizeof(cases) / sizeof(cases[0]));
953 if (ierr) {
954 PetscFinalize();
955 return (int)ierr;
956 }
957
958 ierr = PetscFinalize();
959 return (int)ierr;
960}
static PetscErrorCode TestPoissonSolverMultigridReusesItsSolver(void)
Tests that the multigrid solver is built once and reused on later steps.
static PetscErrorCode TestClarkGradientModelScalesWithFilterWidthSquared(void)
Tests that the Clark gradient model scales as the square of the filter width.
static PetscErrorCode TestComputeEulerianDiffusivityMolecularOnly(void)
Tests Eulerian diffusivity for the molecular-only configuration.
static PetscErrorCode TestComputeRHSZeroFieldNoForcing(void)
Tests that the full RHS remains zero without forcing on a quiescent field.
static PetscErrorCode TestViscousUniformField(void)
Tests that viscous terms vanish for a uniform field.
static PetscErrorCode TestConvectionZeroField(void)
Tests that convection vanishes for a quiescent field.
static PetscErrorCode TestComputeBodyForcesDispatcher(void)
Tests the body-force dispatcher across supported source terms.
static PetscErrorCode TestUpdatePressureAddsPhi(void)
Tests that pressure updates add the correction potential.
static PetscErrorCode TestProjectionZeroPhiLeavesVelocityUnchanged(void)
Tests that projection leaves a zero pressure-correction field unchanged.
static PetscErrorCode TestOperatorAndProjectionShareOneFaceGradient(void)
Tests that the operator is exactly the divergence of the projection's gradient.
static PetscErrorCode TestPoissonSolverMultigridRefusesAnOvercoarsenedHierarchy(void)
Tests that an over-coarsened hierarchy stops the run at the Poisson solve.
static PetscErrorCode TestPoissonSolverMultigridProjectsToDivergenceFree(void)
Tests that the production multigrid Poisson solve and projection remove a divergence.
static PetscErrorCode TestPoissonSolverMultigridHonoursDistinctSweeps(void)
Tests that unequal pre- and post-smoothing counts give two distinct smoothers.
static PetscErrorCode TestPoissonRHSZeroDivergence(void)
Tests that the Poisson RHS is zero for zero-divergence velocity.
static PetscErrorCode TestComputeEulerianDiffusivityVerificationLinearX(void)
Tests verification-driven linear diffusivity override and its gradient.
static PetscErrorCode TestPoissonNullSpaceRemovesTheInteriorMean(void)
Tests the null space attached to the operator.
static PetscErrorCode TestAssemblePoissonOperatorPopulatesRows(void)
Tests that Poisson matrix assembly produces a populated operator on a tiny Cartesian grid.
static PetscErrorCode TestProjectionLinearPhiCorrectsVelocity(void)
Tests that projection applies the expected x-direction correction for a linear pressure field.
static PetscErrorCode TestComputeEulerianDiffusivityGradientConstantField(void)
Tests diffusivity-gradient computation on a constant field.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
Named test case descriptor consumed by PicurvRunTests.
Here is the call graph for this function: