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"));
101 PetscFunctionReturn(0);
112 PetscReal value = 0.0;
113 PetscReal ***target_arr = NULL;
114 PetscReal *positions = NULL;
115 PetscReal *psi = NULL;
117 PetscFunctionBeginUser;
131 "constant scalar profile should evaluate to the configured value"));
133 PetscCall(DMSwarmGetField(user->
swarm,
"position", NULL, NULL, (
void **)&positions));
134 positions[0] = 0.1; positions[1] = 0.2; positions[2] = 0.3;
135 positions[3] = 0.8; positions[4] = 0.6; positions[5] = 0.4;
136 PetscCall(DMSwarmRestoreField(user->
swarm,
"position", NULL, NULL, (
void **)&positions));
139 PetscCall(DMSwarmGetField(user->
swarm,
"Psi", NULL, NULL, (
void **)&psi));
141 "SetAnalyticalScalarFieldOnParticles should overwrite the first particle scalar"));
143 "SetAnalyticalScalarFieldOnParticles should overwrite the second particle scalar"));
144 PetscCall(DMSwarmRestoreField(user->
swarm,
"Psi", NULL, NULL, (
void **)&psi));
153 "linear-x scalar profile should evaluate phi0 + slope_x * x"));
155 PetscCall(VecDuplicate(user->
Psi, &target));
157 PetscCall(DMDAVecGetArrayRead(user->
da, target, &target_arr));
159 "cell-center scalar fill should use the physical x center coordinate"));
160 PetscCall(DMDAVecRestoreArrayRead(user->
da, target, &target_arr));
161 PetscCall(VecDestroy(&target));
172 "sin-product scalar profile should peak at pi/2 in each coordinate"));
175 PetscFunctionReturn(0);
185 PetscErrorCode ierr_unknown = 0;
189 PetscFunctionBeginUser;
191 PetscCall(VecSet(user->
Ucat, 3.0));
192 PetscCall(VecSet(user->
P, 5.0));
193 PetscCall(VecSet(user->
Bcs.
Ubcs, 7.0));
205 Cmpnts ***l_csi, ***l_eta, ***l_zet;
207 PetscCall(DMDAGetLocalInfo(user->
fda, &linfo));
208 PetscCall(DMDAVecGetArray(user->
fda, user->
lCsi, &l_csi));
209 PetscCall(DMDAVecGetArray(user->
fda, user->
lEta, &l_eta));
210 PetscCall(DMDAVecGetArray(user->
fda, user->
lZet, &l_zet));
211 for (PetscInt k = linfo.zs; k < linfo.zs + linfo.zm; k++)
212 for (PetscInt j = linfo.ys; j < linfo.ys + linfo.ym; j++)
213 for (PetscInt i = linfo.xs; i < linfo.xs + linfo.xm; i++) {
214 l_csi[k][j][i] = (
Cmpnts){1.0, 0.0, 0.0};
215 l_eta[k][j][i] = (
Cmpnts){0.0, 1.0, 0.0};
216 l_zet[k][j][i] = (
Cmpnts){0.0, 0.0, 1.0};
218 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lZet, &l_zet));
219 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lEta, &l_eta));
220 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lCsi, &l_csi));
231 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ucat));
232 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
233 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
234 PetscCall(
PicurvAssertRealNear(1.25, ucat[1][1][1].x, 1.0e-12,
"UNIFORM_FLOW should impose the configured x velocity"));
235 PetscCall(
PicurvAssertRealNear(-0.5, ucat[1][1][1].y, 1.0e-12,
"UNIFORM_FLOW should impose the configured y velocity"));
236 PetscCall(
PicurvAssertRealNear(0.75, ucat[1][1][1].z, 1.0e-12,
"UNIFORM_FLOW should impose the configured z velocity"));
237 PetscCall(
PicurvAssertRealNear(1.25, ucont[1][1][1].x, 1.0e-12,
"UNIFORM_FLOW should set contravariant x flux (identity metric)"));
238 PetscCall(
PicurvAssertRealNear(-0.5, ucont[1][1][1].y, 1.0e-12,
"UNIFORM_FLOW should set contravariant y flux (identity metric)"));
239 PetscCall(
PicurvAssertRealNear(0.75, ucont[1][1][1].z, 1.0e-12,
"UNIFORM_FLOW should set contravariant z flux (identity metric)"));
240 PetscCall(
PicurvAssertRealNear(1.25, ubcs[0][1][1].x, 1.0e-12,
"UNIFORM_FLOW should populate boundary x velocity"));
241 PetscCall(
PicurvAssertRealNear(-0.5, ubcs[0][1][1].y, 1.0e-12,
"UNIFORM_FLOW should populate boundary y velocity"));
242 PetscCall(
PicurvAssertRealNear(0.75, ubcs[0][1][1].z, 1.0e-12,
"UNIFORM_FLOW should populate boundary z velocity"));
243 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
244 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
245 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ucat));
248 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
250 PetscCall(PetscPopErrorHandler());
252 "AnalyticalSolutionEngine should reject unknown analytical type strings"));
255 PetscFunctionReturn(0);
270 PetscReal ***p = NULL;
271 const PetscReal vel_decay = PetscExpReal(-0.5);
273 PetscFunctionBeginUser;
279 PetscCall(DMDAVecGetArray(user->
fda, user->
Cent, ¢));
280 PetscCall(DMDAVecGetArray(user->
fda, user->
Centx, ¢_x));
281 PetscCall(DMDAVecGetArray(user->
fda, user->
Centy, ¢_y));
282 PetscCall(DMDAVecGetArray(user->
fda, user->
Centz, ¢_z));
283 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
284 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
285 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
286 cent[k][j][i].
x = 0.0;
287 cent[k][j][i].
y = 0.0;
288 cent[k][j][i].
z = 0.0;
289 cent_x[k][j][i] = cent[k][j][i];
290 cent_y[k][j][i] = cent[k][j][i];
291 cent_z[k][j][i] = cent[k][j][i];
295 cent[1][1][1].
x = 0.5 * PETSC_PI;
296 cent[1][1][1].
y = 0.0;
297 cent[1][1][1].
z = 0.0;
298 cent[1][2][1].
x = 0.0;
299 cent[1][2][1].
y = 0.5 * PETSC_PI;
300 cent[1][2][1].
z = 0.0;
301 cent_z[0][1][1].
x = 0.5 * PETSC_PI;
302 cent_z[0][1][1].
y = 0.0;
303 cent_z[0][1][1].
z = 0.0;
304 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Centz, ¢_z));
305 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Centy, ¢_y));
306 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Centx, ¢_x));
307 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Cent, ¢));
311 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ucat));
312 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
313 PetscCall(DMDAVecGetArrayRead(user->
da, user->
P, &p));
314 PetscCall(
PicurvAssertRealNear(vel_decay, ucat[1][1][1].x, 1.0e-12,
"TGV sample should set the expected interior x velocity"));
315 PetscCall(
PicurvAssertRealNear(0.0, ucat[1][1][1].y, 1.0e-12,
"TGV sample should keep the paired interior y velocity at zero"));
316 PetscCall(
PicurvAssertRealNear(-vel_decay, ucat[1][2][1].y, 1.0e-12,
"TGV sample should set the expected interior y velocity"));
317 PetscCall(
PicurvAssertRealNear(0.0, p[1][1][1], 1.0e-12,
"Chosen TGV sample should produce zero pressure"));
318 PetscCall(
PicurvAssertRealNear(vel_decay, ubcs[0][1][1].x, 1.0e-12,
"TGV sample should set the expected boundary x velocity"));
319 PetscCall(
PicurvAssertRealNear(0.0, ubcs[0][1][1].y, 1.0e-12,
"TGV boundary sample should keep the paired y velocity at zero"));
320 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
P, &p));
321 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
322 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ucat));
325 PetscFunctionReturn(0);
335 PetscReal *data = NULL;
336 const PetscReal vel_decay = PetscExpReal(-0.5);
338 PetscFunctionBeginUser;
339 PetscCall(PetscMemzero(&simCtx,
sizeof(simCtx)));
344 PetscCall(VecCreateSeq(PETSC_COMM_SELF, 6, &tempVec));
345 PetscCall(VecGetArray(tempVec, &data));
346 data[0] = 0.5 * PETSC_PI; data[1] = 0.0; data[2] = 0.0;
347 data[3] = 0.0; data[4] = 0.5 * PETSC_PI; data[5] = 0.0;
348 PetscCall(VecRestoreArray(tempVec, &data));
351 PetscCall(VecGetArray(tempVec, &data));
353 "TGV3D particle dispatch should populate the x velocity at x=pi/2"));
355 "TGV3D particle dispatch should leave the first particle y velocity at zero"));
357 "TGV3D particle dispatch should leave the first particle z velocity at zero"));
359 "TGV3D particle dispatch should leave the second particle x velocity at zero"));
361 "TGV3D particle dispatch should populate the y velocity at y=pi/2"));
363 "TGV3D particle dispatch should leave the second particle z velocity at zero"));
364 PetscCall(VecRestoreArray(tempVec, &data));
367 PetscCall(VecGetArray(tempVec, &data));
371 PetscCall(VecRestoreArray(tempVec, &data));
373 PetscCall(VecGetArray(tempVec, &data));
375 "Non-TGV particle dispatch should leave the vector untouched"));
377 "Non-TGV particle dispatch should preserve the y component"));
379 "Non-TGV particle dispatch should preserve the z component"));
380 PetscCall(VecRestoreArray(tempVec, &data));
387 PetscCall(VecGetArray(tempVec, &data));
389 "UNIFORM_FLOW particle dispatch should populate the x velocity"));
391 "UNIFORM_FLOW particle dispatch should populate the y velocity"));
393 "UNIFORM_FLOW particle dispatch should populate the z velocity"));
395 "UNIFORM_FLOW particle dispatch should use the same x velocity for each particle"));
397 "UNIFORM_FLOW particle dispatch should use the same y velocity for each particle"));
399 "UNIFORM_FLOW particle dispatch should use the same z velocity for each particle"));
400 PetscCall(VecRestoreArray(tempVec, &data));
402 PetscCall(VecDestroy(&tempVec));
403 PetscFunctionReturn(0);
414 PetscReal ***
nu_t = NULL;
415 const PetscReal expected_nu_t = 0.25 * PetscSqrtReal(2.0);
417 PetscFunctionBeginUser;
419 PetscCall(DMCreateGlobalVector(user->
da, &user->
Nu_t));
420 PetscCall(DMCreateLocalVector(user->
da, &user->
lNu_t));
421 PetscCall(DMCreateGlobalVector(user->
da, &user->
CS));
422 PetscCall(DMCreateLocalVector(user->
da, &user->
lCs));
424 PetscCall(VecSet(user->
Aj, 1.0));
425 PetscCall(VecSet(user->
Nu_t, 0.0));
426 PetscCall(VecSet(user->
CS, 0.5));
427 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &ucat));
428 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
429 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
430 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
431 ucat[k][j][i].
x = (PetscReal)i;
432 ucat[k][j][i].
y = 0.0;
433 ucat[k][j][i].
z = 0.0;
437 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &ucat));
438 PetscCall(DMGlobalToLocalBegin(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
439 PetscCall(DMGlobalToLocalEnd(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
440 PetscCall(DMGlobalToLocalBegin(user->
da, user->
Aj, INSERT_VALUES, user->
lAj));
441 PetscCall(DMGlobalToLocalEnd(user->
da, user->
Aj, INSERT_VALUES, user->
lAj));
442 PetscCall(DMGlobalToLocalBegin(user->
da, user->
CS, INSERT_VALUES, user->
lCs));
443 PetscCall(DMGlobalToLocalEnd(user->
da, user->
CS, INSERT_VALUES, user->
lCs));
446 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Nu_t, &
nu_t));
448 "linear velocity field should yield deterministic LES eddy viscosity"));
450 "boundary cells should remain untouched by the interior LES loop"));
451 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Nu_t, &
nu_t));
453 PetscCall(VecDestroy(&user->
CS));
454 PetscCall(VecDestroy(&user->
lCs));
456 PetscFunctionReturn(0);
466 PetscErrorCode ierr_flow = 0;
468 PetscFunctionBeginUser;
472 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
474 PetscCall(PetscPopErrorHandler());
476 "FlowSolver should reject unsupported momentum solver selectors"));
479 PetscFunctionReturn(0);
495 PetscFunctionBeginUser;
497 PetscCall(VecDuplicate(user->
Ucont, &rct));
498 PetscCall(VecZeroEntries(rct));
510 PetscCall(VecSet(user->
Nvert, 0.0));
511 PetscCall(DMGlobalToLocalBegin(user->
da, user->
Nvert, INSERT_VALUES, user->
lNvert));
512 PetscCall(DMGlobalToLocalEnd(user->
da, user->
Nvert, INSERT_VALUES, user->
lNvert));
513 PetscCall(DMDAVecGetArray(user->
fda, user->
lCsi, &l_csi));
514 PetscCall(DMDAVecGetArray(user->
fda, user->
lEta, &l_eta));
515 PetscCall(DMDAVecGetArray(user->
fda, user->
lZet, &l_zet));
516 l_csi[1][1][1].
x = 1.0; l_csi[1][1][1].
y = 0.0; l_csi[1][1][1].
z = 0.0;
517 l_eta[1][1][1].
x = 0.0; l_eta[1][1][1].
y = 1.0; l_eta[1][1][1].
z = 0.0;
518 l_zet[1][1][1].
x = 0.0; l_zet[1][1][1].
y = 0.0; l_zet[1][1][1].
z = 1.0;
519 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lZet, &l_zet));
520 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lEta, &l_eta));
521 PetscCall(DMDAVecRestoreArray(user->
fda, user->
lCsi, &l_csi));
524 PetscCall(DMDAVecGetArrayRead(user->
fda, rct, &rct_arr));
526 "driven flow source should update the controller magnitude"));
528 "driven flow source should leave the y component unchanged"));
530 "driven flow source should leave the z component unchanged"));
531 PetscCall(DMDAVecRestoreArrayRead(user->
fda, rct, &rct_arr));
533 PetscCall(VecDestroy(&rct));
535 PetscFunctionReturn(0);
556 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv solver utility tests");
561 ierr =
PicurvRunTests(
"unit-solver", cases,
sizeof(cases) /
sizeof(cases[0]));
567 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 / ν)