18 PetscFunctionBeginUser;
19 PetscCheck(head != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"BC param list head cannot be NULL.");
20 PetscCall(PetscCalloc1(1, &
node));
21 PetscCall(PetscStrallocpy(key, &
node->key));
22 PetscCall(PetscStrallocpy(value, &
node->value));
24 cursor = &(*cursor)->
next;
27 PetscFunctionReturn(0);
36 PetscFunctionBeginUser;
37 if (!bc_ptr || !*bc_ptr) PetscFunctionReturn(0);
43 PetscCall(PetscFree(bc));
45 PetscFunctionReturn(0);
55 if (index >= nodes - 1) {
128 return (PetscReal)(user->
info.my - 2) * (PetscReal)(user->
info.mz - 2);
131 return (PetscReal)(user->
info.mx - 2) * (PetscReal)(user->
info.mz - 2);
134 return (PetscReal)(user->
info.mx - 2) * (PetscReal)(user->
info.my - 2);
155 PetscFunctionBeginUser;
158 *ucont_k = sample_k; *ucont_j = sample_j; *ucont_i = 0;
159 *ubcs_k = sample_k; *ubcs_j = sample_j; *ubcs_i = 0;
162 *ucont_k = sample_k; *ucont_j = sample_j; *ucont_i = user->
info.mx - 2;
163 *ubcs_k = sample_k; *ubcs_j = sample_j; *ubcs_i = user->
info.mx - 1;
166 *ucont_k = sample_k; *ucont_j = 0; *ucont_i = sample_i;
167 *ubcs_k = sample_k; *ubcs_j = 0; *ubcs_i = sample_i;
170 *ucont_k = sample_k; *ucont_j = user->
info.my - 2; *ucont_i = sample_i;
171 *ubcs_k = sample_k; *ubcs_j = user->
info.my - 1; *ubcs_i = sample_i;
174 *ucont_k = 0; *ucont_j = sample_j; *ucont_i = sample_i;
175 *ubcs_k = 0; *ubcs_j = sample_j; *ubcs_i = sample_i;
178 *ucont_k = user->
info.mz - 2; *ucont_j = sample_j; *ucont_i = sample_i;
179 *ubcs_k = user->
info.mz - 1; *ubcs_j = sample_j; *ubcs_i = sample_i;
182 PetscFunctionReturn(0);
199 PetscInt *ubcs_center_k,
200 PetscInt *ubcs_center_j,
201 PetscInt *ubcs_center_i)
203 PetscFunctionBeginUser;
206 *center_k = 3; *center_j = 3; *center_i = 0;
207 *off_k = 2; *off_j = 2; *off_i = 0;
208 *wall_k = 1; *wall_j = 1; *wall_i = 0;
209 *ubcs_center_k = 3; *ubcs_center_j = 3; *ubcs_center_i = 0;
212 *center_k = 3; *center_j = 3; *center_i = user->
info.mx - 2;
213 *off_k = 2; *off_j = 2; *off_i = user->
info.mx - 2;
214 *wall_k = 1; *wall_j = 1; *wall_i = user->
info.mx - 2;
215 *ubcs_center_k = 3; *ubcs_center_j = 3; *ubcs_center_i = user->
info.mx - 1;
218 *center_k = 3; *center_j = 0; *center_i = 3;
219 *off_k = 2; *off_j = 0; *off_i = 2;
220 *wall_k = 1; *wall_j = 0; *wall_i = 1;
221 *ubcs_center_k = 3; *ubcs_center_j = 0; *ubcs_center_i = 3;
224 *center_k = 3; *center_j = user->
info.my - 2; *center_i = 3;
225 *off_k = 2; *off_j = user->
info.my - 2; *off_i = 2;
226 *wall_k = 1; *wall_j = user->
info.my - 2; *wall_i = 1;
227 *ubcs_center_k = 3; *ubcs_center_j = user->
info.my - 1; *ubcs_center_i = 3;
230 *center_k = 0; *center_j = 3; *center_i = 3;
231 *off_k = 0; *off_j = 2; *off_i = 2;
232 *wall_k = 0; *wall_j = 1; *wall_i = 1;
233 *ubcs_center_k = 0; *ubcs_center_j = 3; *ubcs_center_i = 3;
236 *center_k = user->
info.mz - 2; *center_j = 3; *center_i = 3;
237 *off_k = user->
info.mz - 2; *off_j = 2; *off_i = 2;
238 *wall_k = user->
info.mz - 2; *wall_j = 1; *wall_i = 1;
239 *ubcs_center_k = user->
info.mz - 1; *ubcs_center_j = 3; *ubcs_center_i = 3;
242 PetscFunctionReturn(0);
266 PetscBool generic_face = PETSC_FALSE;
267 PetscBool inlet_face = PETSC_FALSE;
268 PetscBool any_face_serviceable = PETSC_FALSE;
270 PetscFunctionBeginUser;
276 any_face_serviceable = PETSC_TRUE;
282 PetscCall(
PicurvAssertBool((PetscBool)(inlet_face == generic_face),
"inlet face service check should match generic face check"));
284 PetscCall(
PicurvAssertBool(any_face_serviceable,
"at least one global face should be serviceable in a non-degenerate domain"));
287 PetscFunctionReturn(0);
297 PetscBool can_service = PETSC_FALSE;
299 PetscFunctionBeginUser;
306 PetscCall(
PicurvAssertBool((PetscBool)!can_service,
"undefined inlet face should not be serviceable"));
310 PetscFunctionReturn(0);
321 PetscFunctionBeginUser;
323 PetscCall(
PicurvAssertBool((PetscBool)(wall != NULL),
"factory should return wall handler"));
326 PetscCall(
PicurvAssertBool((PetscBool)(wall->
Destroy == NULL),
"wall handler should not require destroy hook"));
330 PetscCall(
PicurvAssertBool((PetscBool)(inlet != NULL),
"factory should return inlet handler"));
334 PetscCall(
PicurvAssertBool((PetscBool)(inlet->
Destroy != NULL),
"inlet handler should expose its destroy hook"));
337 PetscFunctionReturn(0);
345 struct HandlerExpectation {
348 PetscBool expect_apply;
349 PetscBool expect_initialize;
351 const struct HandlerExpectation expectations[] = {
358 PetscFunctionBeginUser;
359 for (
size_t i = 0; i <
sizeof(expectations) /
sizeof(expectations[0]); ++i) {
362 PetscCall(
PicurvAssertBool((PetscBool)(bc != NULL),
"factory should allocate a handler object"));
364 PetscCall(
PicurvAssertBool((PetscBool)((bc->
Apply != NULL) == expectations[i].expect_apply),
"Apply hook expectation mismatch"));
365 PetscCall(
PicurvAssertBool((PetscBool)((bc->
Initialize != NULL) == expectations[i].expect_initialize),
"Initialize hook expectation mismatch"));
368 PetscFunctionReturn(0);
377 PetscErrorCode ierr_create;
379 PetscFunctionBeginUser;
380 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
382 PetscCall(PetscPopErrorHandler());
384 PetscCall(
PicurvAssertBool((PetscBool)(ierr_create != 0),
"unsupported handler should return a non-zero error code"));
386 PetscCall(PetscFree(bc));
388 PetscFunctionReturn(0);
399 PetscFunctionBeginUser;
404 PetscInt ci = -1, cj = -1, ck = -1;
405 PetscReal xi = -1.0, eta = -1.0, zta = -1.0;
406 PetscBool placed = PETSC_FALSE;
414 &ci, &cj, &ck, &xi, &eta, &zta, &placed));
416 PetscCall(
PicurvAssertBool(placed,
"single-rank deterministic face placement should succeed"));
417 PetscCall(
PicurvAssertBool((PetscBool)(ci >= user->
info.xs && ci < user->info.xs + user->
info.xm),
"ci must map to owned node window"));
418 PetscCall(
PicurvAssertBool((PetscBool)(cj >= user->
info.ys && cj < user->info.ys + user->
info.ym),
"cj must map to owned node window"));
419 PetscCall(
PicurvAssertBool((PetscBool)(ck >= user->
info.zs && ck < user->info.zs + user->
info.zm),
"ck must map to owned node window"));
420 PetscCall(
PicurvAssertBool((PetscBool)(xi >= 0.0 && xi < 1.0),
"xi should be in [0,1)"));
421 PetscCall(
PicurvAssertBool((PetscBool)(eta >= 0.0 && eta < 1.0),
"eta should be in [0,1)"));
422 PetscCall(
PicurvAssertBool((PetscBool)(zta >= 0.0 && zta < 1.0),
"zta should be in [0,1)"));
425 PetscCall(
PicurvAssertRealNear(0.5, xi, 1.0e-10,
"deterministic x-face placement should sit halfway into boundary-adjacent cell"));
427 PetscCall(
PicurvAssertRealNear(0.5, eta, 1.0e-10,
"deterministic y-face placement should sit halfway into boundary-adjacent cell"));
429 PetscCall(
PicurvAssertRealNear(0.5, zta, 1.0e-10,
"deterministic z-face placement should sit halfway into boundary-adjacent cell"));
434 PetscFunctionReturn(0);
444 PetscRandom rand_i = NULL, rand_j = NULL, rand_k = NULL;
446 PetscFunctionBeginUser;
449 PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand_i));
450 PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand_j));
451 PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand_k));
452 PetscCall(PetscRandomSetInterval(rand_i, 0.0, 1.0));
453 PetscCall(PetscRandomSetInterval(rand_j, 0.0, 1.0));
454 PetscCall(PetscRandomSetInterval(rand_k, 0.0, 1.0));
455 PetscCall(PetscRandomSetFromOptions(rand_i));
456 PetscCall(PetscRandomSetFromOptions(rand_j));
457 PetscCall(PetscRandomSetFromOptions(rand_k));
460 PetscInt ci = -1, cj = -1, ck = -1;
461 PetscReal xi = -1.0, eta = -1.0, zta = -1.0;
462 const PetscReal boundary_eps = 5.0e-4;
469 &rand_i, &rand_j, &rand_k,
473 PetscCall(
PicurvAssertBool((PetscBool)(ci >= user->
info.xs && ci < user->info.xs + user->
info.xm),
"ci must map to owned node window"));
474 PetscCall(
PicurvAssertBool((PetscBool)(cj >= user->
info.ys && cj < user->info.ys + user->
info.ym),
"cj must map to owned node window"));
475 PetscCall(
PicurvAssertBool((PetscBool)(ck >= user->
info.zs && ck < user->info.zs + user->
info.zm),
"ck must map to owned node window"));
476 PetscCall(
PicurvAssertBool((PetscBool)(xi >= 0.0 && xi <= 1.0),
"xi should be in [0,1]"));
477 PetscCall(
PicurvAssertBool((PetscBool)(eta >= 0.0 && eta <= 1.0),
"eta should be in [0,1]"));
478 PetscCall(
PicurvAssertBool((PetscBool)(zta >= 0.0 && zta <= 1.0),
"zta should be in [0,1]"));
482 PetscCall(
PicurvAssertBool((PetscBool)(xi <= boundary_eps),
"NEG_X should pin xi near 0"));
485 PetscCall(
PicurvAssertBool((PetscBool)(xi >= 1.0 - boundary_eps),
"POS_X should pin xi near 1"));
488 PetscCall(
PicurvAssertBool((PetscBool)(eta <= boundary_eps),
"NEG_Y should pin eta near 0"));
491 PetscCall(
PicurvAssertBool((PetscBool)(eta >= 1.0 - boundary_eps),
"POS_Y should pin eta near 1"));
494 PetscCall(
PicurvAssertBool((PetscBool)(zta <= boundary_eps),
"NEG_Z should pin zta near 0"));
497 PetscCall(
PicurvAssertBool((PetscBool)(zta >= 1.0 - boundary_eps),
"POS_Z should pin zta near 1"));
502 PetscCall(PetscRandomDestroy(&rand_i));
503 PetscCall(PetscRandomDestroy(&rand_j));
504 PetscCall(PetscRandomDestroy(&rand_k));
506 PetscFunctionReturn(0);
520 PetscReal local_inflow = 0.0;
521 PetscReal local_outflow = 0.0;
522 PetscReal expected_flux = 0.0;
524 PetscFunctionBeginUser;
525 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
527 PetscCall(VecSet(user->
Ucont, 0.0));
528 PetscCall(VecSet(user->
Bcs.
Ubcs, 0.0));
540 PetscCall(bc->
PostStep(bc, &ctx, &local_inflow, &local_outflow));
542 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
543 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
544 PetscCall(
PicurvAssertRealNear(2.5, ucont[0][3][3].z, 1.0e-12,
"constant inlet should set Ucont normal component"));
545 PetscCall(
PicurvAssertRealNear(2.5, ubcs[0][3][3].z, 1.0e-12,
"constant inlet should set Ubcs normal component"));
546 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
547 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
549 expected_flux = (PetscReal)(user->
info.mx - 2) * (PetscReal)(user->
info.my - 2) * 2.5;
550 PetscCall(
PicurvAssertRealNear(expected_flux, local_inflow, 1.0e-12,
"constant inlet PostStep should sum the face flux"));
551 PetscCall(
PicurvAssertRealNear(0.0, local_outflow, 1.0e-12,
"constant inlet should not contribute to outflow accumulation"));
557 PetscFunctionReturn(0);
577 PetscFunctionBeginUser;
578 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
582 for (
size_t n = 0; n <
sizeof(faces) /
sizeof(faces[0]); ++n) {
583 const BCFace face = faces[n];
584 PetscInt ucont_k, ucont_j, ucont_i, ubcs_k, ubcs_j, ubcs_i;
586 PetscCall(VecSet(user->
Ucont, 5.0));
587 PetscCall(VecSet(user->
Bcs.
Ubcs, 7.0));
590 PetscCall(bc->
Apply(bc, &ctx));
593 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
594 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
596 PetscCall(
PicurvAssertRealNear(0.0, ubcs[ubcs_k][ubcs_j][ubcs_i].x, 1.0e-12,
"wall no-slip should zero Ubcs.x"));
597 PetscCall(
PicurvAssertRealNear(0.0, ubcs[ubcs_k][ubcs_j][ubcs_i].y, 1.0e-12,
"wall no-slip should zero Ubcs.y"));
598 PetscCall(
PicurvAssertRealNear(0.0, ubcs[ubcs_k][ubcs_j][ubcs_i].z, 1.0e-12,
"wall no-slip should zero Ubcs.z"));
599 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
600 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
605 PetscFunctionReturn(0);
613 struct ConstantInletCase {
616 const char *value_text;
618 const struct ConstantInletCase cases[] = {
632 PetscFunctionBeginUser;
633 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
637 for (
size_t n = 0; n <
sizeof(cases) /
sizeof(cases[0]); ++n) {
638 const struct ConstantInletCase *test_case = &cases[n];
640 PetscReal local_inflow = 0.0;
641 PetscReal local_outflow = 0.0;
642 PetscInt ucont_k, ucont_j, ucont_i, ubcs_k, ubcs_j, ubcs_i;
646 PetscCall(VecSet(user->
Ucont, 0.0));
647 PetscCall(VecSet(user->
Bcs.
Ubcs, 0.0));
654 test_case->value_text));
659 PetscCall(bc->
PreStep(bc, &ctx, &local_inflow, &local_outflow));
660 PetscCall(
PicurvAssertRealNear(0.0, local_inflow, 1.0e-12,
"constant inlet PreStep should leave inflow unchanged"));
661 PetscCall(
PicurvAssertRealNear(0.0, local_outflow, 1.0e-12,
"constant inlet PreStep should leave outflow unchanged"));
663 PetscCall(bc->
PostStep(bc, &ctx, &local_inflow, &local_outflow));
666 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
667 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
673 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
674 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
675 PetscCall(
PicurvAssertRealNear(expected_flux, local_inflow, 1.0e-12,
"constant inlet PostStep should integrate the face flux with orientation"));
676 PetscCall(
PicurvAssertRealNear(0.0, local_outflow, 1.0e-12,
"constant inlet should not add to outflow"));
683 PetscFunctionReturn(0);
697 PetscFunctionBeginUser;
698 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
712 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
713 PetscCall(
PicurvAssertRealNear(4.0, ucont[0][3][3].z, 1.0e-12,
"parabolic inlet should peak at the face centerline"));
714 PetscCall(
PicurvAssertRealNear(0.0, ucont[0][1][1].z, 1.0e-12,
"parabolic inlet should vanish at wall-adjacent locations"));
715 PetscCall(
PicurvAssertBool((PetscBool)(ucont[0][3][3].z > ucont[0][2][2].z),
"parabolic inlet centerline should exceed off-center velocity"));
716 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
722 PetscFunctionReturn(0);
741 PetscFunctionBeginUser;
742 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
746 for (
size_t n = 0; n <
sizeof(faces) /
sizeof(faces[0]); ++n) {
747 const BCFace face = faces[n];
749 PetscReal local_inflow = 0.0;
750 PetscReal local_outflow = 0.0;
751 PetscInt center_k, center_j, center_i;
752 PetscInt off_k, off_j, off_i;
753 PetscInt wall_k, wall_j, wall_i;
754 PetscInt ubcs_center_k, ubcs_center_j, ubcs_center_i;
757 PetscCall(VecSet(user->
Ucont, 0.0));
758 PetscCall(VecSet(user->
Bcs.
Ubcs, 0.0));
768 PetscCall(bc->
PreStep(bc, &ctx, &local_inflow, &local_outflow));
769 PetscCall(
PicurvAssertRealNear(0.0, local_inflow, 1.0e-12,
"parabolic inlet PreStep should leave inflow unchanged"));
770 PetscCall(
PicurvAssertRealNear(0.0, local_outflow, 1.0e-12,
"parabolic inlet PreStep should leave outflow unchanged"));
772 PetscCall(bc->
PostStep(bc, &ctx, &local_inflow, &local_outflow));
775 ¢er_k, ¢er_j, ¢er_i,
776 &off_k, &off_j, &off_i,
777 &wall_k, &wall_j, &wall_i,
778 &ubcs_center_k, &ubcs_center_j, &ubcs_center_i));
779 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
780 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
786 "parabolic inlet centerline magnitude should exceed the off-center magnitude"));
787 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
788 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
789 PetscCall(
PicurvAssertBool((PetscBool)(PetscAbsReal(local_inflow) > 0.0),
"parabolic inlet PostStep should accumulate a non-zero flux"));
791 "parabolic inlet PostStep should preserve the face orientation"));
792 PetscCall(
PicurvAssertRealNear(0.0, local_outflow, 1.0e-12,
"parabolic inlet should not add to outflow"));
799 PetscFunctionReturn(0);
811 PetscReal global_inflow = 30.0;
812 PetscReal global_farfield_in = 0.0;
813 PetscReal global_farfield_out = 0.0;
814 PetscReal global_outflow = 25.0;
815 PetscReal local_inflow = 0.0;
816 PetscReal local_outflow = 0.0;
820 PetscFunctionBeginUser;
821 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
824 PetscCall(VecSet(user->
Ucat, 1.0));
825 PetscCall(DMGlobalToLocalBegin(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
826 PetscCall(DMGlobalToLocalEnd(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
841 PetscCall(bc->
Apply(bc, &ctx));
842 PetscCall(bc->
PostStep(bc, &ctx, &local_inflow, &local_outflow));
844 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
845 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lUcat, &ucat));
846 PetscCall(
PicurvAssertRealNear(1.2, ucont[5][3][3].z, 1.0e-12,
"outlet correction should add the expected flux trim"));
847 PetscCall(
PicurvAssertRealNear(1.0, ucat[5][3][3].z, 1.0e-12,
"outlet handler should preserve the interior Ucat reference"));
848 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
849 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lUcat, &ucat));
851 PetscCall(
PicurvAssertRealNear(30.0, local_outflow, 1.0e-12,
"outlet PostStep should report corrected flux"));
852 PetscCall(
PicurvAssertRealNear(0.0, local_inflow, 1.0e-12,
"outlet handler should not accumulate inflow"));
856 PetscFunctionReturn(0);
875 PetscFunctionBeginUser;
876 PetscCall(PetscMemzero(&ctx,
sizeof(ctx)));
879 PetscCall(VecSet(user->
Ucat, 1.0));
880 PetscCall(DMGlobalToLocalBegin(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
881 PetscCall(DMGlobalToLocalEnd(user->
fda, user->
Ucat, INSERT_VALUES, user->
lUcat));
883 for (
size_t n = 0; n <
sizeof(faces) /
sizeof(faces[0]); ++n) {
884 const BCFace face = faces[n];
886 PetscReal global_inflow = 0.0;
887 PetscReal global_farfield_in = 0.0;
888 PetscReal global_farfield_out = 0.0;
889 PetscReal global_outflow = 0.0;
890 PetscReal local_inflow = 0.0;
891 PetscReal local_outflow = 0.0;
893 PetscInt ucont_k, ucont_j, ucont_i, ubcs_k, ubcs_j, ubcs_i;
895 PetscCall(VecSet(user->
Ucont, 0.0));
896 PetscCall(VecSet(user->
Bcs.
Ubcs, 0.0));
911 PetscCall(bc->
PreStep(bc, &ctx, &local_inflow, &local_outflow));
912 PetscCall(
PicurvAssertRealNear(area, local_outflow, 1.0e-12,
"outlet PreStep should measure the uncorrected face flux"));
914 global_inflow = area + 0.2 * area;
915 global_outflow = local_outflow;
917 PetscCall(bc->
Apply(bc, &ctx));
918 PetscCall(bc->
PostStep(bc, &ctx, &local_inflow, &local_outflow));
921 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &ucont));
922 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
924 PetscCall(
PicurvAssertRealNear(1.0, ubcs[ubcs_k][ubcs_j][ubcs_i].x, 1.0e-12,
"outlet handler should copy Ucat into Ubcs.x"));
925 PetscCall(
PicurvAssertRealNear(1.0, ubcs[ubcs_k][ubcs_j][ubcs_i].y, 1.0e-12,
"outlet handler should copy Ucat into Ubcs.y"));
926 PetscCall(
PicurvAssertRealNear(1.0, ubcs[ubcs_k][ubcs_j][ubcs_i].z, 1.0e-12,
"outlet handler should copy Ucat into Ubcs.z"));
927 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &ucont));
928 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Bcs.
Ubcs, &ubcs));
929 PetscCall(
PicurvAssertRealNear(0.0, local_inflow, 1.0e-12,
"outlet handler should not add to inflow"));
930 PetscCall(
PicurvAssertRealNear(1.2 * area, local_outflow, 1.0e-12,
"outlet PostStep should report the corrected flux"));
937 PetscFunctionReturn(0);
963 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv boundary tests");
968 ierr =
PicurvRunTests(
"unit-boundaries", cases,
sizeof(cases) /
sizeof(cases[0]));
974 ierr = PetscFinalize();
PetscErrorCode GetRandomCellAndLogicalCoordsOnInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out)
Assuming the current rank services the inlet face, this function selects a random cell (owned by this...
PetscErrorCode BoundaryCondition_Create(BCHandlerType handler_type, BoundaryCondition **new_bc_ptr)
(Private) Creates and configures a specific BoundaryCondition handler object.
PetscErrorCode CanRankServiceInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscBool *can_service_inlet_out)
Determines if the current MPI rank owns any part of the globally defined inlet face,...
PetscErrorCode CanRankServiceFace(const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, BCFace face_id, PetscBool *can_service_out)
Determines if the current MPI rank owns any part of a specified global face.
PetscErrorCode GetDeterministicFaceGridLocation(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_cells_global, PetscInt JM_cells_global, PetscInt KM_cells_global, PetscInt64 particle_global_id, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out, PetscBool *placement_successful_out)
Places particles in a deterministic grid/raster pattern on a specified domain face.
void FreeBC_ParamList(BC_Param *head)
Frees an entire linked list of boundary-condition parameters.
The "virtual table" struct for a boundary condition handler object.
PetscErrorCode(* PostStep)(BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow, PetscReal *local_outflow)
PetscErrorCode(* PreStep)(BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow, PetscReal *local_outflow)
PetscErrorCode(* Destroy)(BoundaryCondition *self)
PetscErrorCode(* Initialize)(BoundaryCondition *self, BCContext *ctx)
PetscErrorCode(* Apply)(BoundaryCondition *self, BCContext *ctx)
static PetscErrorCode TestOutletConservationHandlerFaceMatrix(void)
Tests outlet-conservation correction and flux accounting across all outlet faces.
static PetscErrorCode TestCanRankServiceFaceMatchesInletWhenDefined(void)
Tests that face-service detection matches a defined inlet face.
static PetscErrorCode TestBoundaryConditionFactoryAssignments(void)
Tests the boundary-condition factory assignments for representative handlers.
static PetscErrorCode AppendBCParam(BC_Param **head, const char *key, const char *value)
Appends one key/value pair to a linked list of boundary-condition parameters.
static PetscReal GetFaceInteriorPointCount(const UserCtx *user, BCFace face)
Computes the number of face-interior sample points for a given boundary face.
int main(int argc, char **argv)
Runs the unit-boundaries PETSc test binary.
static PetscErrorCode TestInletParabolicProfileHandlerBehavior(void)
Tests parabolic inlet handler shape on a tiny Z-face.
static PetscReal GetFaceOrientationSign(BCFace face)
Returns the sign convention used for face-normal flux expectations.
static PetscErrorCode TestGetDeterministicFaceGridLocationFaceMatrix(void)
Tests deterministic inlet-face grid-location helpers across all faces.
static PetscErrorCode TestInletConstantVelocityHandlerBehavior(void)
Tests constant inlet handler initialization and face writes on a Z inlet.
static PetscErrorCode TestBoundaryConditionFactoryRejectsUnsupportedHandler(void)
Tests that unsupported handler types are rejected by the factory.
static PetscErrorCode TestGetRandomCellAndLogicalCoordsOnInletFaceMatrix(void)
Tests random inlet-face cell selection across all supported faces.
static PetscErrorCode TestBoundaryConditionFactoryImplementedHandlerMatrix(void)
Tests the implemented-handler matrix exposed by the factory.
static PetscErrorCode TestCanRankServiceInletFaceRequiresDefinition(void)
Tests that inlet-face service requires an inlet face to be defined.
static PetscErrorCode TestInletParabolicProfileHandlerFaceMatrix(void)
Tests parabolic-inlet centerline, wall, and flux behavior across all faces.
static PetscErrorCode TestWallNoSlipHandlerFaceMatrix(void)
Tests wall no-slip application across the full face matrix.
static PetscErrorCode TestInletConstantVelocityHandlerFaceMatrix(void)
Tests constant-inlet initialization, flux accounting, and face writes across all faces.
static const char * GetInletParamKey(BCFace face)
Maps an inlet face to the matching configuration key used by the handler parser.
static PetscErrorCode DestroyBoundaryHandler(BoundaryCondition **bc_ptr)
Destroys one boundary-condition handler allocated by a boundary test.
static PetscErrorCode TestOutletConservationHandlerBehavior(void)
Tests outlet conservation handler correction and post-step flux accounting.
static void ResetBoundaryFaceConfig(BoundaryFaceConfig *cfg)
Resets one boundary-face configuration entry to a neutral test-local baseline.
static PetscReal GetFaceNormalComponent(Cmpnts value, BCFace face)
Extracts the velocity component aligned with the supplied boundary-face normal.
static PetscInt InteriorSampleIndex(PetscInt nodes)
Chooses a stable interior node index for face-sample assertions on tiny test grids.
static PetscErrorCode GetRepresentativeFaceSlots(const UserCtx *user, BCFace face, PetscInt *ucont_k, PetscInt *ucont_j, PetscInt *ucont_i, PetscInt *ubcs_k, PetscInt *ubcs_j, PetscInt *ubcs_i)
Selects representative Ucont and Ubcs slots for face-matrix assertions.
static PetscErrorCode GetParabolicSampleSlots(const UserCtx *user, BCFace face, PetscInt *center_k, PetscInt *center_j, PetscInt *center_i, PetscInt *off_k, PetscInt *off_j, PetscInt *off_i, PetscInt *wall_k, PetscInt *wall_j, PetscInt *wall_i, PetscInt *ubcs_center_k, PetscInt *ubcs_center_j, PetscInt *ubcs_center_i)
Selects center, off-center, and wall-adjacent slots for parabolic-face checks.
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 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 PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvPopulateIdentityMetrics(UserCtx *user)
Populates identity metric vectors on the minimal grid fixture.
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.
const PetscReal * global_outflow_sum
PetscBool inletFaceDefined
BoundaryFaceConfig boundary_faces[6]
BCFace identifiedInletBCFace
SimCtx * simCtx
Back-pointer to the master simulation context.
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
@ BC_HANDLER_INLET_PARABOLIC
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
@ BC_HANDLER_OUTLET_CONSERVATION
@ BC_HANDLER_OUTLET_PRESSURE
BCHandlerType handler_type
const PetscReal * global_farfield_outflow_sum
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
const PetscReal * global_inflow_sum
const PetscReal * global_farfield_inflow_sum
BCFace
Identifies the six logical faces of a structured computational block.
Provides execution context for a boundary condition handler.
A node in a linked list for storing key-value parameters from the bcs.dat file.
Holds the complete configuration for one of the six boundary faces.
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.
A generic C-style linked list node for integers.