20 double values[3][3][3];
21 double weights[3][3][3];
23 PetscFunctionBeginUser;
24 PetscCall(PetscMemzero(&simCtx,
sizeof(simCtx)));
25 for (PetscInt k = 0; k < 3; ++k) {
26 for (PetscInt j = 0; j < 3; ++j) {
27 for (PetscInt i = 0; i < 3; ++i) {
28 values[k][j][i] = 2.0;
29 weights[k][j][i] = 1.0;
36 "Simpson-rule filter should preserve a constant field"));
40 "box filter should preserve a constant field"));
42 for (PetscInt k = 0; k < 3; ++k) {
43 for (PetscInt j = 0; j < 3; ++j) {
44 for (PetscInt i = 0; i < 3; ++i) {
45 weights[k][j][i] = 0.0;
50 "box filter should return zero when all weights are zero"));
51 PetscFunctionReturn(0);
61 PetscErrorCode ierr_grid = 0;
62 PetscErrorCode ierr_non_square = 0;
64 PetscFunctionBeginUser;
67 "TGV3D should require custom geometry"));
69 "ZERO_FLOW should not require custom geometry"));
72 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
74 PetscCall(PetscPopErrorHandler());
76 "SetAnalyticalGridInfo should reject analytical types without custom geometry"));
80 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
82 PetscCall(PetscPopErrorHandler());
84 "TGV3D multi-block setup should reject non-square block counts"));
94 PetscCall(
PicurvAssertRealNear(PETSC_PI, user->
Min_X, 1.0e-12,
"TGV3D multi-block xmin should reflect the block column"));
95 PetscCall(
PicurvAssertRealNear(2.0 * PETSC_PI, user->
Max_X, 1.0e-12,
"TGV3D multi-block xmax should reflect the block column"));
97 PetscCall(
PicurvAssertRealNear(2.0 * PETSC_PI, user->
Max_Y, 1.0e-12,
"TGV3D multi-block ymax should reflect the block row"));
98 PetscCall(
PicurvAssertRealNear(2.0 * PETSC_PI, user->
Max_Z, 1.0e-12,
"TGV3D multi-block zmax should span the full domain"));
102 PetscFunctionReturn(0);
113 PetscReal value = 0.0;
114 PetscReal ***target_arr = NULL;
115 PetscReal *positions = NULL;
116 PetscReal *psi = NULL;
118 PetscFunctionBeginUser;
132 "constant scalar profile should evaluate to the configured value"));
134 PetscCall(DMSwarmGetField(user->
swarm,
"position", NULL, NULL, (
void **)&positions));
135 positions[0] = 0.1; positions[1] = 0.2; positions[2] = 0.3;
136 positions[3] = 0.8; positions[4] = 0.6; positions[5] = 0.4;
137 PetscCall(DMSwarmRestoreField(user->
swarm,
"position", NULL, NULL, (
void **)&positions));
140 PetscCall(DMSwarmGetField(user->
swarm,
"Psi", NULL, NULL, (
void **)&psi));
142 "SetAnalyticalScalarFieldOnParticles should overwrite the first particle scalar"));
144 "SetAnalyticalScalarFieldOnParticles should overwrite the second particle scalar"));
145 PetscCall(DMSwarmRestoreField(user->
swarm,
"Psi", NULL, NULL, (
void **)&psi));
154 "linear-x scalar profile should evaluate phi0 + slope_x * x"));
156 PetscCall(VecDuplicate(user->
Psi, &target));
158 PetscCall(DMDAVecGetArrayRead(user->
da, target, &target_arr));
160 "cell-center scalar fill should use the physical x center coordinate"));
161 PetscCall(DMDAVecRestoreArrayRead(user->
da, target, &target_arr));
162 PetscCall(VecDestroy(&target));
173 "sin-product scalar profile should peak at pi/2 in each coordinate"));
176 PetscFunctionReturn(0);
186 PetscErrorCode ierr_unknown = 0;
190 PetscFunctionBeginUser;
192 PetscCall(VecSet(user->
Ucat, 3.0));
193 PetscCall(VecSet(user->
P, 5.0));
194 PetscCall(VecSet(user->
Bcs.
Ubcs, 7.0));
206 Cmpnts ***l_csi, ***l_eta, ***l_zet;
208 PetscCall(DMDAGetLocalInfo(user->
fda, &linfo));
209 PetscCall(DMDAVecGetArray(user->
fda, user->
lCsi, &l_csi));
210 PetscCall(DMDAVecGetArray(user->
fda, user->
lEta, &l_eta));
211 PetscCall(DMDAVecGetArray(user->
fda, user->
lZet, &l_zet));
212 for (PetscInt k = linfo.zs; k < linfo.zs + linfo.zm; k++)
213 for (PetscInt j = linfo.ys; j < linfo.ys + linfo.ym; j++)
214 for (PetscInt i = linfo.xs; i < linfo.xs + linfo.xm; i++) {
215 l_csi[k][j][i] = (
Cmpnts){1.0, 0.0, 0.0};
216 l_eta[k][j][i] = (
Cmpnts){0.0, 1.0, 0.0};
217 l_zet[k][j][i] = (
Cmpnts){0.0, 0.0, 1.0};
219 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lZet, &l_zet));
220 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lEta, &l_eta));
221 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lCsi, &l_csi));
232 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ucat));
233 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
234 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
235 PetscCall(
PicurvAssertRealNear(1.25, ucat[1][1][1].x, 1.0e-12,
"UNIFORM_FLOW should impose the configured x velocity"));
236 PetscCall(
PicurvAssertRealNear(-0.5, ucat[1][1][1].y, 1.0e-12,
"UNIFORM_FLOW should impose the configured y velocity"));
237 PetscCall(
PicurvAssertRealNear(0.75, ucat[1][1][1].z, 1.0e-12,
"UNIFORM_FLOW should impose the configured z velocity"));
238 PetscCall(
PicurvAssertRealNear(1.25, ucont[1][1][1].x, 1.0e-12,
"UNIFORM_FLOW should set contravariant x flux (identity metric)"));
239 PetscCall(
PicurvAssertRealNear(-0.5, ucont[1][1][1].y, 1.0e-12,
"UNIFORM_FLOW should set contravariant y flux (identity metric)"));
240 PetscCall(
PicurvAssertRealNear(0.75, ucont[1][1][1].z, 1.0e-12,
"UNIFORM_FLOW should set contravariant z flux (identity metric)"));
241 PetscCall(
PicurvAssertRealNear(1.25, ubcs[0][1][1].x, 1.0e-12,
"UNIFORM_FLOW should populate boundary x velocity"));
242 PetscCall(
PicurvAssertRealNear(-0.5, ubcs[0][1][1].y, 1.0e-12,
"UNIFORM_FLOW should populate boundary y velocity"));
243 PetscCall(
PicurvAssertRealNear(0.75, ubcs[0][1][1].z, 1.0e-12,
"UNIFORM_FLOW should populate boundary z velocity"));
244 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
245 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
246 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ucat));
249 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
251 PetscCall(PetscPopErrorHandler());
253 "AnalyticalSolutionEngine should reject unknown analytical type strings"));
256 PetscFunctionReturn(0);
271 PetscReal ***p = NULL;
272 const PetscReal vel_decay = PetscExpReal(-0.5);
274 PetscFunctionBeginUser;
280 PetscCall(DMDAVecGetArray(user->
fda, user->
Cent, ¢));
281 PetscCall(DMDAVecGetArray(user->
fda, user->
Centx, ¢_x));
282 PetscCall(DMDAVecGetArray(user->
fda, user->
Centy, ¢_y));
283 PetscCall(DMDAVecGetArray(user->
fda, user->
Centz, ¢_z));
284 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
285 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
286 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
287 cent[k][j][i].
x = 0.0;
288 cent[k][j][i].
y = 0.0;
289 cent[k][j][i].
z = 0.0;
290 cent_x[k][j][i] = cent[k][j][i];
291 cent_y[k][j][i] = cent[k][j][i];
292 cent_z[k][j][i] = cent[k][j][i];
296 cent[1][1][1].
x = 0.5 * PETSC_PI;
297 cent[1][1][1].
y = 0.0;
298 cent[1][1][1].
z = 0.0;
299 cent[1][2][1].
x = 0.0;
300 cent[1][2][1].
y = 0.5 * PETSC_PI;
301 cent[1][2][1].
z = 0.0;
302 cent_z[0][1][1].
x = 0.5 * PETSC_PI;
303 cent_z[0][1][1].
y = 0.0;
304 cent_z[0][1][1].
z = 0.0;
305 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Centz, ¢_z));
306 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Centy, ¢_y));
307 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Centx, ¢_x));
308 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Cent, ¢));
312 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ucat));
313 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
314 PetscCall(DMDAVecGetArrayRead(user->
da, user->
P, &p));
315 PetscCall(
PicurvAssertRealNear(vel_decay, ucat[1][1][1].x, 1.0e-12,
"TGV sample should set the expected interior x velocity"));
316 PetscCall(
PicurvAssertRealNear(0.0, ucat[1][1][1].y, 1.0e-12,
"TGV sample should keep the paired interior y velocity at zero"));
317 PetscCall(
PicurvAssertRealNear(-vel_decay, ucat[1][2][1].y, 1.0e-12,
"TGV sample should set the expected interior y velocity"));
318 PetscCall(
PicurvAssertRealNear(0.0, p[1][1][1], 1.0e-12,
"Chosen TGV sample should produce zero pressure"));
319 PetscCall(
PicurvAssertRealNear(vel_decay, ubcs[0][1][1].x, 1.0e-12,
"TGV sample should set the expected boundary x velocity"));
320 PetscCall(
PicurvAssertRealNear(0.0, ubcs[0][1][1].y, 1.0e-12,
"TGV boundary sample should keep the paired y velocity at zero"));
321 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
P, &p));
322 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
323 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ucat));
326 PetscFunctionReturn(0);
336 PetscReal *data = NULL;
337 const PetscReal vel_decay = PetscExpReal(-0.5);
339 PetscFunctionBeginUser;
340 PetscCall(PetscMemzero(&simCtx,
sizeof(simCtx)));
345 PetscCall(VecCreateSeq(PETSC_COMM_SELF, 6, &tempVec));
346 PetscCall(VecGetArray(tempVec, &data));
347 data[0] = 0.5 * PETSC_PI; data[1] = 0.0; data[2] = 0.0;
348 data[3] = 0.0; data[4] = 0.5 * PETSC_PI; data[5] = 0.0;
349 PetscCall(VecRestoreArray(tempVec, &data));
352 PetscCall(VecGetArray(tempVec, &data));
354 "TGV3D particle dispatch should populate the x velocity at x=pi/2"));
356 "TGV3D particle dispatch should leave the first particle y velocity at zero"));
358 "TGV3D particle dispatch should leave the first particle z velocity at zero"));
360 "TGV3D particle dispatch should leave the second particle x velocity at zero"));
362 "TGV3D particle dispatch should populate the y velocity at y=pi/2"));
364 "TGV3D particle dispatch should leave the second particle z velocity at zero"));
365 PetscCall(VecRestoreArray(tempVec, &data));
368 PetscCall(VecGetArray(tempVec, &data));
372 PetscCall(VecRestoreArray(tempVec, &data));
374 PetscCall(VecGetArray(tempVec, &data));
376 "Non-TGV particle dispatch should leave the vector untouched"));
378 "Non-TGV particle dispatch should preserve the y component"));
380 "Non-TGV particle dispatch should preserve the z component"));
381 PetscCall(VecRestoreArray(tempVec, &data));
388 PetscCall(VecGetArray(tempVec, &data));
390 "UNIFORM_FLOW particle dispatch should populate the x velocity"));
392 "UNIFORM_FLOW particle dispatch should populate the y velocity"));
394 "UNIFORM_FLOW particle dispatch should populate the z velocity"));
396 "UNIFORM_FLOW particle dispatch should use the same x velocity for each particle"));
398 "UNIFORM_FLOW particle dispatch should use the same y velocity for each particle"));
400 "UNIFORM_FLOW particle dispatch should use the same z velocity for each particle"));
401 PetscCall(VecRestoreArray(tempVec, &data));
403 PetscCall(VecDestroy(&tempVec));
404 PetscFunctionReturn(0);
415 PetscReal ***
nu_t = NULL;
416 const PetscReal expected_nu_t = 0.25 * PetscSqrtReal(2.0);
418 PetscFunctionBeginUser;
420 PetscCall(DMCreateGlobalVector(user->
da, &user->
Nu_t));
421 PetscCall(DMCreateLocalVector(user->
da, &user->
lNu_t));
422 PetscCall(DMCreateGlobalVector(user->
da, &user->
CS));
423 PetscCall(DMCreateLocalVector(user->
da, &user->
lCs));
425 PetscCall(VecSet(user->
Aj, 1.0));
426 PetscCall(VecSet(user->
Nu_t, 0.0));
427 PetscCall(VecSet(user->
CS, 0.5));
428 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &ucat));
429 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
430 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
431 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
432 ucat[k][j][i].
x = (PetscReal)i;
433 ucat[k][j][i].
y = 0.0;
434 ucat[k][j][i].
z = 0.0;
438 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &ucat));
439 PetscCall(DMGlobalToLocalBegin(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
440 PetscCall(DMGlobalToLocalEnd(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
441 PetscCall(DMGlobalToLocalBegin(user->
da, user->
Aj, INSERT_VALUES, user->
lAj));
442 PetscCall(DMGlobalToLocalEnd(user->
da, user->
Aj, INSERT_VALUES, user->
lAj));
443 PetscCall(DMGlobalToLocalBegin(user->
da, user->
CS, INSERT_VALUES, user->
lCs));
444 PetscCall(DMGlobalToLocalEnd(user->
da, user->
CS, INSERT_VALUES, user->
lCs));
447 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Nu_t, &
nu_t));
449 "linear velocity field should yield deterministic LES eddy viscosity"));
451 "boundary cells should remain untouched by the interior LES loop"));
452 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Nu_t, &
nu_t));
454 PetscCall(VecDestroy(&user->
CS));
455 PetscCall(VecDestroy(&user->
lCs));
457 PetscFunctionReturn(0);
467 PetscErrorCode ierr_flow = 0;
469 PetscFunctionBeginUser;
473 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
475 PetscCall(PetscPopErrorHandler());
477 "FlowSolver should reject unsupported momentum solver selectors"));
480 PetscFunctionReturn(0);
496 PetscFunctionBeginUser;
498 PetscCall(VecDuplicate(user->
Ucont, &rct));
499 PetscCall(VecZeroEntries(rct));
511 PetscCall(VecSet(user->
Nvert, 0.0));
512 PetscCall(DMGlobalToLocalBegin(user->
da, user->
Nvert, INSERT_VALUES, user->
lNvert));
513 PetscCall(DMGlobalToLocalEnd(user->
da, user->
Nvert, INSERT_VALUES, user->
lNvert));
514 PetscCall(DMDAVecGetArray(user->
fda, user->
lCsi, &l_csi));
515 PetscCall(DMDAVecGetArray(user->
fda, user->
lEta, &l_eta));
516 PetscCall(DMDAVecGetArray(user->
fda, user->
lZet, &l_zet));
517 l_csi[1][1][1].
x = 1.0; l_csi[1][1][1].
y = 0.0; l_csi[1][1][1].
z = 0.0;
518 l_eta[1][1][1].
x = 0.0; l_eta[1][1][1].
y = 1.0; l_eta[1][1][1].
z = 0.0;
519 l_zet[1][1][1].
x = 0.0; l_zet[1][1][1].
y = 0.0; l_zet[1][1][1].
z = 1.0;
520 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lZet, &l_zet));
521 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lEta, &l_eta));
522 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lCsi, &l_csi));
525 PetscCall(DMDAVecGetArrayRead(user->
fda, rct, &rct_arr));
527 "driven flow source should update the controller magnitude"));
529 "driven flow source should leave the y component unchanged"));
531 "driven flow source should leave the z component unchanged"));
532 PetscCall(DMDAVecRestoreArrayRead(user->
fda, rct, &rct_arr));
534 PetscCall(VecDestroy(&rct));
536 PetscFunctionReturn(0);
557 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv solver utility tests");
562 ierr =
PicurvRunTests(
"unit-solver", cases,
sizeof(cases) /
sizeof(cases[0]));
568 ierr = PetscFinalize();
PetscErrorCode SetAnalyticalScalarFieldOnParticles(UserCtx *user, const char *swarm_field_name)
Writes the configured verification scalar profile onto a particle swarm scalar field.
PetscErrorCode EvaluateAnalyticalScalarProfile(const SimCtx *simCtx, PetscReal x, PetscReal y, PetscReal z, PetscReal t, PetscReal *value)
Evaluates the configured verification scalar profile at one physical point.
PetscErrorCode SetAnalyticalScalarFieldAtCellCenters(UserCtx *user, Vec targetVec)
Writes the configured verification scalar profile at physical cell centers into a scalar Vec.
PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
Dispatches to the appropriate analytical solution function based on simulation settings.
PetscBool AnalyticalTypeRequiresCustomGeometry(const char *analytical_type)
Reports whether an analytical type requires custom geometry/decomposition logic.
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
PetscErrorCode SetAnalyticalGridInfo(UserCtx *user)
Sets the grid domain and resolution for analytical solution cases.
PetscErrorCode ComputeDrivenChannelFlowSource(UserCtx *user, Vec Rct)
Applies a momentum source term to drive flow in a periodic channel or pipe.
double ApplyLESTestFilter(const SimCtx *simCtx, double values[3][3][3], double weights[3][3][3])
Applies a numerical "test filter" to a 3x3x3 stencil of data points.
PetscErrorCode ComputeEddyViscosityLES(UserCtx *user)
Computes the turbulent eddy viscosity (Nu_t) for the LES model.
PetscErrorCode FlowSolver(SimCtx *simCtx)
Orchestrates a single time step of the Eulerian fluid solver.
static PetscErrorCode TestAnalyticalSolutionEngineTaylorGreenSamples(void)
Tests exact Taylor-Green samples on selected Eulerian interior and boundary points.
static PetscErrorCode TestComputeEddyViscosityLESDeterministicField(void)
Tests deterministic LES eddy-viscosity computation on a linear velocity field.
static PetscErrorCode TestFlowSolverRejectsUnsupportedMomentumSolverType(void)
Tests FlowSolver guardrails for unsupported momentum solver selections.
int main(int argc, char **argv)
Runs the unit-solver PETSc test binary.
static PetscErrorCode TestAnalyticalScalarVerificationHelpers(void)
Tests analytical scalar verification helper routines.
static PetscErrorCode TestDrivenChannelFlowSource(void)
Tests driven-channel flow source-term evaluation.
static PetscErrorCode TestAnalyticalGeometrySelection(void)
Tests analytical geometry selection for supported analytical solutions.
static PetscErrorCode TestAnalyticalSolutionForParticlesDispatch(void)
Tests particle analytical-solution dispatch for TGV3D, UNIFORM_FLOW, and non-analytical no-op paths.
static PetscErrorCode TestLESTestFilterPaths(void)
Tests LES test-filter helper paths for representative cases.
static PetscErrorCode TestAnalyticalSolutionEngineDispatch(void)
Tests analytical solution engine ZERO_FLOW, UNIFORM_FLOW, and unknown-type dispatch.
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 PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvCreateSwarmPair(UserCtx *user, PetscInt nlocal, const char *post_field_name)
Creates matched solver and post-processing swarms for tests.
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.
PetscErrorCode PicurvAssertVecConstant(Vec vec, PetscScalar expected, PetscReal tol, const char *context)
Asserts that a PETSc vector is spatially constant within tolerance.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
BoundaryFaceConfig boundary_faces[6]
PetscReal forceScalingFactor
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
BCHandlerType handler_type
PetscReal bulkVelocityCorrection
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
MomentumSolverType
Enumerator to identify the implemented momentum solver strategies.
VerificationScalarConfig verificationScalar
Cmpnts AnalyticalUniformVelocity
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
MomentumSolverType mom_solver_type
PetscReal drivingForceMagnitude
A 3D point or vector with PetscScalar components.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.
double nu_t(double yplus)
Computes turbulent eddy viscosity ratio (ν_t / ν)