36 PetscErrorCode (*AssembleInterior)(
UserCtx *, Vec, Mat);
67 PetscReal norm,
void *ctx);
69 PetscReal norm,
void *ctx);
72 SNESConvergedReason reason,
73 PetscInt nonlinear_its,
74 PetscInt function_evals,
83 Mat jacobian_operator, Mat preconditioning_matrix,
void *vctx);
85 UserCtx *user, Vec current_solution, Mat preconditioning_matrix);
87 UserCtx *user, Mat *preconditioning_matrix);
96 PetscReal norm,
void *vctx)
102 PetscFunctionBeginUser;
115 PetscFunctionReturn(PETSC_SUCCESS);
125 PetscReal norm,
void *vctx)
128 PetscInt newton_iteration = -1;
129 PetscReal relative_tolerance = 0.0;
131 PetscFunctionBeginUser;
134 PetscCall(SNESGetIterationNumber(ctx->
snes, &newton_iteration));
135 PetscCall(KSPGetTolerances(ksp, &relative_tolerance, NULL, NULL, NULL));
138 (
int)newton_iteration, (int)iteration,
139 (
double)relative_tolerance, (double)norm);
142 PetscFunctionReturn(PETSC_SUCCESS);
159 if (PetscSNPrintf(name,
sizeof(name),
"Momentum_Solver_Newton_Krylov_%s_Block_%d.csv", kind, (
int)ctx->
user->
_this) ||
177 "step,block,newton,krylov,requested_rtol,reported_residual_norm");
187 SNESConvergedReason reason,
188 PetscInt nonlinear_its,
189 PetscInt function_evals,
191 PetscReal final_norm,
196 const char *reason_name;
201 "step,block,solver,jacobian,preconditioner,reason,reason_code,newton,evals,krylov,"
202 "initial_norm,final_norm,state");
204 reason_name = reason == SNES_CONVERGED_ITERATING
205 ?
"SNES_CONVERGED_ITERATING" : SNESConvergedReasons[reason];
206 (void)fprintf(file,
"%d,%d,Newton Krylov,finite_difference / matrix_free,%s,%s,%d,%d,%d,%d,",
209 "none" :
"frozen_momentum_jacobian / point_block",
210 reason_name, (int)reason,
211 (
int)nonlinear_its, (int)function_evals, (
int)linear_its);
213 (void)fprintf(file,
",%.16e,%s\n", (
double)final_norm,
214 !committed ?
"rolled_back" :
228 PetscReal mask_max = 0.0;
229 PetscInt velocity_dof = 0;
231 PetscFunctionBeginUser;
233 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
234 "Newton Krylov requires a non-NULL UserCtx.");
236 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
237 "Newton Krylov requires UserCtx::simCtx.");
238 PetscCall(DMDAGetInfo(user->
fda, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
239 &velocity_dof, NULL, NULL, NULL, NULL, NULL));
240 PetscCheck(velocity_dof == 3, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
241 "Newton Krylov requires a three-component velocity DMDA (got dof=%" PetscInt_FMT
").",
243 PetscCheck(simCtx->
block_number == 1, PETSC_COMM_WORLD, PETSC_ERR_SUP,
244 "Newton Krylov version one supports exactly one block (got %" PetscInt_FMT
").",
246 PetscCheck(!simCtx->
immersed, PETSC_COMM_WORLD, PETSC_ERR_SUP,
247 "Newton Krylov version one does not support immersed boundaries.");
248 PetscCheck(!simCtx->
movefsi && !simCtx->
rotatefsi, PETSC_COMM_WORLD, PETSC_ERR_SUP,
249 "Newton Krylov version one does not support moving or rotating bodies/FSI.");
251 "Newton Krylov version one does not support moving or rotating reference frames.");
252 for (PetscInt face = 0; face < 6; ++face) {
254 PetscBool supported = PETSC_FALSE;
281 supported = PETSC_FALSE;
284 PetscCheck(supported, PETSC_COMM_WORLD, PETSC_ERR_SUP,
285 "Newton Krylov version one does not support boundary face %" PetscInt_FMT
" with mathematical type %" PetscInt_FMT
" and handler %" PetscInt_FMT
".",
291 PETSC_COMM_WORLD, PETSC_ERR_SUP,
"Newton Krylov requires paired x-periodic faces.");
294 PETSC_COMM_WORLD, PETSC_ERR_SUP,
"Newton Krylov requires paired y-periodic faces.");
297 PETSC_COMM_WORLD, PETSC_ERR_SUP,
"Newton Krylov requires paired z-periodic faces.");
299 PetscCheck(user->
Nvert != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
300 "Newton Krylov requires the cell-mask vector Nvert.");
305 PetscCall(VecMax(user->
Nvert, NULL, &mask_max));
309 PetscFunctionReturn(PETSC_SUCCESS);
318 char type[48] =
"finite_difference";
319 char finite_difference_mode[32] =
"matrix_free";
320 char model[48] =
"none";
321 char structure[32] =
"none";
322 PetscBool set = PETSC_FALSE, match = PETSC_FALSE;
324 PetscFunctionBeginUser;
326 PetscCheck(jacobian != NULL && description != NULL, PETSC_COMM_SELF,
327 PETSC_ERR_ARG_NULL,
"Newton Krylov linearization configuration is NULL.");
328 PetscCall(PetscOptionsGetString(NULL, NULL,
"-mom_nk_jacobian_type",
329 type,
sizeof(type), &set));
330 PetscCall(PetscStrcasecmp(type,
"finite_difference", &match));
331 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
332 "-mom_nk_jacobian_type must be 'finite_difference' (got '%s').", type);
334 PetscCall(PetscOptionsGetString(NULL, NULL,
"-mom_nk_jacobian_fd_mode",
335 finite_difference_mode,
336 sizeof(finite_difference_mode), &set));
337 PetscCall(PetscStrcasecmp(finite_difference_mode,
"matrix_free", &match));
338 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
339 "-mom_nk_jacobian_fd_mode must be 'matrix_free' (got '%s').",
340 finite_difference_mode);
343 PetscCall(PetscOptionsGetString(NULL, NULL,
"-mom_nk_preconditioner_model",
344 model,
sizeof(model), &set));
345 PetscCall(PetscStrcasecmp(model,
"none", &match));
348 PetscCall(PetscStrcasecmp(model,
"frozen_momentum_jacobian", &match));
351 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
352 "-mom_nk_preconditioner_model must be 'none' or "
353 "'frozen_momentum_jacobian' (got '%s').", model);
354 PetscCall(PetscOptionsGetString(NULL, NULL,
"-mom_nk_preconditioner_structure",
355 structure,
sizeof(structure), &set));
356 PetscCall(PetscStrcasecmp(structure,
"none", &match));
359 PetscCall(PetscStrcasecmp(structure,
"point_block", &match));
362 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
363 "-mom_nk_preconditioner_structure must be 'none' or 'point_block' "
364 "(got '%s').", structure);
369 PETSC_COMM_WORLD, PETSC_ERR_SUP,
370 "Unsupported Newton Krylov preconditioner model/structure combination: "
371 "model='%s', structure='%s'.", model, structure);
373 PetscFunctionReturn(PETSC_SUCCESS);
385 UserCtx *user,
const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k,
386 PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
400 return metric.
x * metric.
x + metric.
y * metric.
y + metric.
z * metric.
z;
429 const UserCtx *user,
const PetscReal ***
nu_t, PetscInt axis,
430 PetscInt i, PetscInt j, PetscInt k)
435 const PetscInt coord[3] = {i, j, k};
436 const PetscInt size[3] = {user->
info.mx, user->
info.my, user->
info.mz};
444 neighbour = (axis == 0) ?
nu_t[k][j][i + 1]
445 : (axis == 1) ?
nu_t[k][j + 1][i]
448 return 0.5 * (
nu_t[k][j][i] + neighbour);
454 const Cmpnts ***zet,
const PetscReal ***aj,
const PetscReal ***
nu_t,
455 PetscInt i, PetscInt j, PetscInt k, PetscScalar block[9])
460 const PetscReal molecular = simCtx->
ren > 0.0 ? 1.0 / simCtx->
ren : 0.0;
468 const PetscReal AJip = 0.5 * (aj[k][j][i] + aj[k][j][i + 1]);
469 const PetscReal AJjp = 0.5 * (aj[k][j][i] + aj[k][j + 1][i]);
470 const PetscReal AJkp = 0.5 * (aj[k][j][i] + aj[k + 1][j][i]);
471 const PetscReal g11ip = csi[k][j][i].
x * csi[k][j][i].
x +
472 csi[k][j][i].
y * csi[k][j][i].
y +
473 csi[k][j][i].
z * csi[k][j][i].
z;
474 const PetscReal g22ip = 0.25 * (
479 const PetscReal g33ip = 0.25 * (
484 const PetscReal g11jp = 0.25 * (
489 const PetscReal g22jp = eta[k][j][i].
x * eta[k][j][i].
x +
490 eta[k][j][i].
y * eta[k][j][i].
y +
491 eta[k][j][i].
z * eta[k][j][i].
z;
492 const PetscReal g33jp = 0.25 * (
497 const PetscReal g11kp = 0.25 * (
502 const PetscReal g22kp = 0.25 * (
507 const PetscReal g33kp = zet[k][j][i].
x * zet[k][j][i].
x +
508 zet[k][j][i].
y * zet[k][j][i].
y +
509 zet[k][j][i].
z * zet[k][j][i].
z;
510 const PetscReal U0jp = 0.25 * (ucont[k][j][i].
x + ucont[k][j][i - 1].
x +
511 ucont[k][j + 1][i].
x + ucont[k][j + 1][i - 1].
x);
512 const PetscReal U0kp = 0.25 * (ucont[k][j][i].
x + ucont[k][j][i - 1].
x +
513 ucont[k + 1][j][i].
x + ucont[k + 1][j][i - 1].
x);
514 const PetscReal U1ip = 0.25 * (ucont[k][j][i].
y + ucont[k][j - 1][i].
y +
515 ucont[k][j][i + 1].
y + ucont[k][j - 1][i + 1].
y);
516 const PetscReal U1kp = 0.25 * (ucont[k][j][i].
y + ucont[k][j - 1][i].
y +
517 ucont[k + 1][j][i].
y + ucont[k + 1][j - 1][i].
y);
518 const PetscReal U2ip = 0.25 * (ucont[k][j][i].
z + ucont[k - 1][j][i].
z +
519 ucont[k][j][i + 1].
z + ucont[k - 1][j][i + 1].
z);
520 const PetscReal U2jp = 0.25 * (ucont[k][j][i].
z + ucont[k - 1][j][i].
z +
521 ucont[k][j + 1][i].
z + ucont[k - 1][j + 1][i].
z);
522 PetscReal A[6][4] = {{0.0}};
523 PetscReal Su, Sv, Sw, nui, nuj, nuk;
525 A[0][0] = 0.125 * aj[k][j][i] * ucont[k][j][i].
y;
526 A[0][1] = -0.125 * aj[k][j - 1][i] * ucont[k][j - 1][i].
y;
527 A[0][2] = 0.125 * aj[k][j][i + 1] * ucont[k][j][i + 1].
y;
528 A[0][3] = -0.125 * aj[k][j - 1][i + 1] * ucont[k][j - 1][i + 1].
y;
529 A[1][0] = 0.125 * aj[k][j][i] * ucont[k][j][i].
z;
530 A[1][1] = -0.125 * aj[k - 1][j][i] * ucont[k - 1][j][i].
z;
531 A[1][2] = 0.125 * aj[k][j][i + 1] * ucont[k][j][i + 1].
z;
532 A[1][3] = -0.125 * aj[k - 1][j][i + 1] * ucont[k - 1][j][i + 1].
z;
533 A[2][0] = -0.125 * aj[k][j + 1][i - 1] * ucont[k][j + 1][i - 1].
x;
534 A[2][1] = -0.125 * aj[k][j][i - 1] * ucont[k][j][i - 1].
x;
535 A[2][2] = 0.125 * aj[k][j + 1][i] * ucont[k][j + 1][i].
x;
536 A[2][3] = 0.125 * aj[k][j][i] * ucont[k][j][i].
x;
537 A[3][0] = 0.125 * aj[k][j][i] * ucont[k][j][i].
z;
538 A[3][1] = -0.125 * aj[k - 1][j][i] * ucont[k - 1][j][i].
z;
539 A[3][2] = 0.125 * aj[k][j + 1][i] * ucont[k][j + 1][i].
z;
540 A[3][3] = -0.125 * aj[k - 1][j + 1][i] * ucont[k - 1][j + 1][i].
z;
541 A[4][0] = -0.125 * aj[k + 1][j][i - 1] * ucont[k + 1][j][i - 1].
x;
542 A[4][1] = -0.125 * aj[k][j][i - 1] * ucont[k][j][i - 1].
x;
543 A[4][2] = 0.125 * aj[k + 1][j][i] * ucont[k + 1][j][i].
x;
544 A[4][3] = 0.125 * aj[k][j][i] * ucont[k][j][i].
x;
545 A[5][0] = -0.125 * aj[k + 1][j - 1][i] * ucont[k + 1][j - 1][i].
y;
546 A[5][1] = -0.125 * aj[k][j - 1][i] * ucont[k][j - 1][i].
y;
547 A[5][2] = 0.125 * aj[k + 1][j][i] * ucont[k + 1][j][i].
y;
548 A[5][3] = 0.125 * aj[k][j][i] * ucont[k][j][i].
y;
549 Su = A[0][0] + A[0][1] + A[0][2] + A[0][3] +
550 A[1][0] + A[1][1] + A[1][2] + A[1][3];
551 Sv = A[2][0] + A[2][1] + A[2][2] + A[2][3] +
552 A[3][0] + A[3][1] + A[3][2] + A[3][3];
553 Sw = A[4][0] + A[4][1] + A[4][2] + A[4][3] +
554 A[5][0] + A[5][1] + A[5][2] + A[5][3];
555 nui = AJip * AJip * (g11ip + g22ip + g33ip) * nu_eff_i;
556 nuj = AJjp * AJjp * (g11jp + g22jp + g33jp) * nu_eff_j;
557 nuk = AJkp * AJkp * (g11kp + g22kp + g33kp) * nu_eff_k;
562 block[0] = dtc + nui + Su; block[1] = 0.5 * AJjp * U0jp; block[2] = 0.5 * AJkp * U0kp;
563 block[3] = 0.5 * AJip * U1ip; block[4] = dtc + nuj + Sv; block[5] = 0.5 * AJkp * U1kp;
564 block[6] = 0.5 * AJip * U2ip; block[7] = 0.5 * AJjp * U2jp; block[8] = dtc + nuk + Sw;
572 PetscFunctionBeginUser;
575 PetscCheck(description != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
576 "Preconditioner description is NULL.");
582 PetscFunctionReturn(PETSC_SUCCESS);
587 UserCtx *user, Vec current_solution, Mat preconditioning_matrix)
589 DMDALocalInfo info = user->
info;
590 Cmpnts ***ucont = NULL, ***csi = NULL, ***eta = NULL, ***zet = NULL;
591 PetscReal ***aj = NULL, ***nvert = NULL, ***
nu_t = NULL;
595 const PetscBool has_eddy_viscosity =
596 (PetscBool)(simCtx->
les && user->
lNu_t != NULL);
597 PetscErrorCode ierr = PETSC_SUCCESS, cleanup_ierr;
599 PetscFunctionBeginUser;
613 ierr = DMGlobalToLocalBegin(user->
fda, current_solution, INSERT_VALUES, user->
lUcont);
614 if (ierr)
goto cleanup;
615 ierr = DMGlobalToLocalEnd(user->
fda, current_solution, INSERT_VALUES, user->
lUcont);
616 if (ierr)
goto cleanup;
617 ierr = DMDAVecGetArrayRead(user->
fda, user->
lUcont, &ucont);
if (ierr)
goto cleanup;
618 ierr = DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi);
if (ierr)
goto cleanup;
619 ierr = DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta);
if (ierr)
goto cleanup;
620 ierr = DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet);
if (ierr)
goto cleanup;
621 ierr = DMDAVecGetArrayRead(user->
da, user->
lAj, &aj);
if (ierr)
goto cleanup;
622 ierr = DMDAVecGetArrayRead(user->
da, user->
lNvert, &nvert);
if (ierr)
goto cleanup;
623 if (has_eddy_viscosity) {
624 ierr = DMDAVecGetArrayRead(user->
da, user->
lNu_t, &
nu_t);
if (ierr)
goto cleanup;
626 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
627 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
628 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
629 for (PetscInt component = 0; component < 3; ++component) {
630 MatStencil row = {.i = i, .j = j, .k = k, .c = component};
633 user, (
const PetscReal ***)nvert, i, j, k, component, &ri, &rj, &rk);
635 PetscScalar block[9];
636 MatStencil cols[3] = {
637 {.i = i, .j = j, .k = k, .c = 0},
638 {.i = i, .j = j, .k = k, .c = 1},
639 {.i = i, .j = j, .k = k, .c = 2}
643 (
const PetscReal ***)aj, (
const PetscReal ***)
nu_t, i, j, k, block);
646 if (simCtx->
TwoD == component + 1) {
647 for (PetscInt c = 0; c < 3; ++c)
648 block[3 * component + c] = (c == component)
651 ierr = MatSetValuesStencil(preconditioning_matrix, 1, &row, 3, cols,
652 &block[3 * component], INSERT_VALUES);
653 if (ierr)
goto cleanup;
660 if (
nu_t) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
da, user->
lNu_t, &
nu_t);
if (!ierr) ierr = cleanup_ierr; }
661 if (nvert) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
da, user->
lNvert, &nvert);
if (!ierr) ierr = cleanup_ierr; }
662 if (aj) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj);
if (!ierr) ierr = cleanup_ierr; }
663 if (zet) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet);
if (!ierr) ierr = cleanup_ierr; }
664 if (eta) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta);
if (!ierr) ierr = cleanup_ierr; }
665 if (csi) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi);
if (!ierr) ierr = cleanup_ierr; }
666 if (ucont) { cleanup_ierr = DMDAVecRestoreArrayRead(user->
fda, user->
lUcont, &ucont);
if (!ierr) ierr = cleanup_ierr; }
668 PetscFunctionReturn(ierr);
673 UserCtx *user, Mat preconditioning_matrix)
675 DMDALocalInfo info = user->
info;
676 const PetscReal ***nvert = NULL;
678 PetscFunctionBeginUser;
680 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, &nvert));
681 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
682 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
683 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
684 for (PetscInt component = 0; component < 3; ++component) {
687 user, nvert, i, j, k, component, &ri, &rj, &rk);
689 MatStencil row = {.i = i, .j = j, .k = k, .c = component};
690 MatStencil columns[2] = {row, row};
691 PetscScalar values[2] = {1.0, -1.0};
692 PetscInt column_count = 1;
694 columns[column_count++] = (MatStencil){
695 .i = ri, .j = rj, .k = rk, .c = component
698 PetscCall(MatSetValuesStencil(preconditioning_matrix, 1, &row,
699 column_count, columns, values,
706 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, &nvert));
708 PetscFunctionReturn(PETSC_SUCCESS);
720 PetscFunctionBeginUser;
724 PETSC_COMM_WORLD, PETSC_ERR_SUP,
725 "Unsupported Newton Krylov Jacobian type/finite-difference-mode combination.");
729 "momentum_jacobian_finite_difference_matrix_free"));
731 PetscFunctionReturn(PETSC_SUCCESS);
738 PetscFunctionBeginUser;
740 PetscCall(MatMFFDComputeJacobian(snes, current_solution, jacobian->
jacobian_operator,
743 PetscFunctionReturn(PETSC_SUCCESS);
751 PetscFunctionBeginUser;
757 PetscFunctionReturn(PETSC_SUCCESS);
763 PetscFunctionBeginUser;
767 PetscFunctionReturn(PETSC_SUCCESS);
775 PetscFunctionBeginUser;
794 "momentum_preconditioner_frozen_point_block"));
798 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP,
799 "Unsupported Newton Krylov preconditioner model/structure combination.");
802 PetscFunctionReturn(PETSC_SUCCESS);
809 PetscFunctionBeginUser;
820 PetscFunctionReturn(PETSC_SUCCESS);
827 PetscFunctionBeginUser;
831 PetscFunctionReturn(PETSC_SUCCESS);
838 const char *actual_type = NULL;
839 PetscBool matches = PETSC_FALSE;
841 PetscFunctionBeginUser;
843 PetscCall(PCGetType(pc, &actual_type));
844 PetscCall(PetscStrcmp(actual_type, engine->
petsc_pc_type, &matches));
845 PetscCheck(matches, PETSC_COMM_WORLD, PETSC_ERR_SUP,
846 "Newton Krylov preconditioner model/structure requires internal PETSc PC "
847 "type '%s', but raw option processing selected '%s'.",
848 engine->
petsc_pc_type, actual_type ? actual_type :
"(unset)");
850 PetscFunctionReturn(PETSC_SUCCESS);
857 PetscFunctionBeginUser;
864 PetscFunctionReturn(PETSC_SUCCESS);
869 Mat jacobian_operator, Mat preconditioning_matrix,
void *vctx)
872 PetscFunctionBeginUser;
874 (void)jacobian_operator;
875 (void)preconditioning_matrix;
880 PetscFunctionReturn(PETSC_SUCCESS);
892 UserCtx *user, Mat *preconditioning_matrix)
895 ISLocalToGlobalMapping local_to_global = NULL;
898 PetscInt local_size, global_size, ownership_start, ownership_end;
899 PetscInt *diagonal_nnz = NULL, *offdiagonal_nnz = NULL;
900 PetscInt ghost_starts[4] = {0, 0, 0, 0}, ghost_sizes[3] = {0, 0, 0};
901 const PetscReal ***nvert = NULL;
902 PetscErrorCode ierr = PETSC_SUCCESS, cleanup_ierr;
904 PetscFunctionBeginUser;
906 PetscCheck(preconditioning_matrix != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
907 "Point-block matrix output is NULL.");
908 *preconditioning_matrix = NULL;
909 comm = PetscObjectComm((PetscObject)user->
fda);
911 PetscCall(VecGetLocalSize(user->
Ucont, &local_size));
912 PetscCall(VecGetSize(user->
Ucont, &global_size));
913 PetscCall(VecGetOwnershipRange(user->
Ucont, &ownership_start, &ownership_end));
914 PetscCheck(local_size == ownership_end - ownership_start, comm, PETSC_ERR_PLIB,
915 "Velocity ownership range does not match its local size.");
916 ierr = PetscCalloc2(local_size, &diagonal_nnz,
917 local_size, &offdiagonal_nnz);
if (ierr)
goto cleanup;
918 ierr = DMGetLocalToGlobalMapping(user->
fda, &local_to_global);
if (ierr)
goto cleanup;
919 ghost_starts[0] = info.gxs; ghost_starts[1] = info.gys; ghost_starts[2] = info.gzs;
920 ghost_sizes[0] = info.gxm; ghost_sizes[1] = info.gym; ghost_sizes[2] = info.gzm;
921 ierr = DMDAVecGetArrayRead(user->
da, user->
lNvert, &nvert);
if (ierr)
goto cleanup;
923 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
924 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
925 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
926 for (PetscInt component = 0; component < 3; ++component) {
927 PetscInt ri, rj, rk, column_count;
928 MatStencil row_stencil = {.i = i, .j = j, .k = k, .c = component};
929 MatStencil column_stencils[3];
930 PetscInt row_local, row, column_locals[3], columns[3];
932 user, nvert, i, j, k, component, &ri, &rj, &rk);
936 for (PetscInt column_component = 0; column_component < 3;
937 ++column_component) {
938 column_stencils[column_component] = (MatStencil){
939 .i = i, .j = j, .k = k, .c = column_component
944 column_stencils[0] = row_stencil;
946 column_stencils[column_count++] = (MatStencil){
947 .i = ri, .j = rj, .k = rk, .c = component
951 row_local = component + 3 * (
952 (i - ghost_starts[0]) + ghost_sizes[0] * (
953 (j - ghost_starts[1]) + ghost_sizes[1] *
954 (k - ghost_starts[2])));
955 for (PetscInt column_index = 0; column_index < column_count;
957 const MatStencil column = column_stencils[column_index];
958 if (!(column.i >= ghost_starts[0] &&
959 column.i < ghost_starts[0] + ghost_sizes[0] &&
960 column.j >= ghost_starts[1] &&
961 column.j < ghost_starts[1] + ghost_sizes[1] &&
962 column.k >= ghost_starts[2] &&
963 column.k < ghost_starts[2] + ghost_sizes[2])) {
964 ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__,
965 PETSC_ERR_ARG_OUTOFRANGE,
967 "Point-block column lies outside the DMDA ghost stencil.");
970 column_locals[column_index] = column.c + 3 * (
971 (column.i - ghost_starts[0]) + ghost_sizes[0] * (
972 (column.j - ghost_starts[1]) + ghost_sizes[1] *
973 (column.k - ghost_starts[2])));
975 ierr = ISLocalToGlobalMappingApply(local_to_global, 1,
977 if (ierr)
goto cleanup;
978 ierr = ISLocalToGlobalMappingApply(local_to_global, column_count,
979 column_locals, columns);
980 if (ierr)
goto cleanup;
981 if (!(row >= ownership_start && row < ownership_end)) {
982 ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__,
983 PETSC_ERR_PLIB, PETSC_ERROR_INITIAL,
984 "DMDA-mapped point-block row is not locally owned.");
987 for (PetscInt column_index = 0; column_index < column_count;
989 PetscBool duplicate = PETSC_FALSE;
990 for (PetscInt previous = 0; previous < column_index; ++previous)
991 if (columns[previous] == columns[column_index]) duplicate = PETSC_TRUE;
992 if (columns[column_index] < 0) {
993 ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__,
994 PETSC_ERR_PLIB, PETSC_ERROR_INITIAL,
995 "DMDA-mapped point-block column is invalid.");
998 if (duplicate)
continue;
999 if (columns[column_index] >= ownership_start &&
1000 columns[column_index] < ownership_end)
1001 ++diagonal_nnz[row - ownership_start];
1003 ++offdiagonal_nnz[row - ownership_start];
1010 ierr = MatCreateAIJ(comm, local_size, local_size, global_size, global_size,
1011 0, diagonal_nnz, 0, offdiagonal_nnz, &matrix);
1012 if (ierr)
goto cleanup;
1013 ierr = MatSetBlockSize(matrix, 3);
if (ierr)
goto cleanup;
1014 ierr = MatSetLocalToGlobalMapping(matrix, local_to_global, local_to_global);
1015 if (ierr)
goto cleanup;
1016 ierr = MatSetStencil(matrix, 3, ghost_sizes, ghost_starts, 3);
1017 if (ierr)
goto cleanup;
1018 ierr = MatSetDM(matrix, user->
fda);
if (ierr)
goto cleanup;
1019 ierr = MatSetOption(matrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
1020 if (ierr)
goto cleanup;
1021 ierr = PetscFree2(diagonal_nnz, offdiagonal_nnz);
if (ierr)
goto cleanup;
1023 *preconditioning_matrix = matrix;
1028 cleanup_ierr = DMDAVecRestoreArrayRead(user->
da, user->
lNvert, &nvert);
1029 if (!ierr) ierr = cleanup_ierr;
1031 cleanup_ierr = MatDestroy(&matrix);
if (!ierr) ierr = cleanup_ierr;
1032 cleanup_ierr = PetscFree2(diagonal_nnz, offdiagonal_nnz);
1033 if (!ierr) ierr = cleanup_ierr;
1035 PetscFunctionReturn(ierr);
1059 DMDALocalInfo info = user->
info;
1061 Cmpnts ***x = NULL, ***conditioned = NULL, ***f = NULL, ***lx = NULL;
1062 const PetscInt xs = info.xs, xe = info.xs + info.xm;
1063 const PetscInt ys = info.ys, ye = info.ys + info.ym;
1064 const PetscInt zs = info.zs, ze = info.zs + info.zm;
1066 PetscFunctionBeginUser;
1068 PetscCall(DMGetLocalVector(user->
fda, &local_x));
1069 PetscCall(DMGlobalToLocalBegin(user->
fda, X, INSERT_VALUES, local_x));
1070 PetscCall(DMGlobalToLocalEnd(user->
fda, X, INSERT_VALUES, local_x));
1071 PetscCall(DMDAVecGetArrayRead(user->
fda, X, &x));
1072 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &conditioned));
1073 PetscCall(DMDAVecGetArray(user->
fda, F, &f));
1074 PetscCall(DMDAVecGetArrayRead(user->
fda, local_x, &lx));
1076 for (PetscInt k = zs; k < ze; ++k) {
1077 for (PetscInt j = ys; j < ye; ++j) {
1078 for (PetscInt i = xs; i < xe; ++i) {
1079 PetscScalar *fv = &f[k][j][i].x;
1080 const PetscScalar *xv = &x[k][j][i].
x;
1081 const PetscScalar *cv = &conditioned[k][j][i].x;
1083 for (PetscInt component = 0; component < 3; ++component) {
1084 PetscInt ri, rj, rk;
1086 user, i, j, k, component, &ri, &rj, &rk);
1087 const PetscScalar *rv = &lx[rk][rj][ri].x;
1097 PetscCall(DMDAVecRestoreArrayRead(user->
fda, local_x, &lx));
1098 PetscCall(DMDAVecRestoreArray(user->
fda, F, &f));
1099 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &conditioned));
1100 PetscCall(DMDAVecRestoreArrayRead(user->
fda, X, &x));
1101 PetscCall(DMRestoreLocalVector(user->
fda, &local_x));
1103 PetscFunctionReturn(PETSC_SUCCESS);
1142 PetscFunctionBeginUser;
1145 PetscCall(VecCopy(X, user->
Ucont));
1188 PetscCall(VecCopy(user->
Rhs, F));
1189 PetscCall(VecScale(F, -1.0));
1192 PetscFunctionReturn(PETSC_SUCCESS);
1203 PetscFunctionBeginUser;
1210 PetscCall(SNESCreate(PetscObjectComm((PetscObject)user->
Ucont), &ctx->
snes));
1212 PetscCall(SNESSetOptionsPrefix(ctx->
snes,
"mom_nk_"));
1213 PetscCall(SNESSetType(ctx->
snes, SNESNEWTONLS));
1214 PetscCall(SNESSetDM(ctx->
snes, user->
fda));
1219 &preconditioner_description,
1221 PetscCall(SNESGetKSP(ctx->
snes, &ksp));
1222 PetscCall(KSPSetType(ksp, KSPGMRES));
1223 PetscCall(KSPGetPC(ksp, &pc));
1225 PetscCall(SNESSetFromOptions(ctx->
snes));
1230 PetscFunctionReturn(PETSC_SUCCESS);
1243 PetscFunctionBeginUser;
1247 PetscCall(VecDestroy(&ctx->
solution));
1250 PetscCall(SNESDestroy(&ctx->
snes));
1254 PetscFunctionReturn(PETSC_SUCCESS);
1277 PetscReal *residual, PetscReal *residual_2,
1278 PetscReal *reference, PetscBool *satisfied)
1282 PetscReal ucont_inf;
1284 PetscFunctionBeginUser;
1286 PetscCall(SNESGetFunction(ctx->
snes, &F, NULL, NULL));
1287 PetscCall(SNESComputeFunction(ctx->
snes, solution, F));
1288 PetscCall(VecNorm(F, NORM_INFINITY, residual));
1289 PetscCall(VecNorm(F, NORM_2, residual_2));
1290 PetscCall(VecNorm(solution, NORM_INFINITY, &ucont_inf));
1292 *satisfied = (PetscBool)(simCtx->
mom_resid_atol > 0.0 && *reference > 0.0 &&
1293 *residual <= simCtx->mom_resid_atol * *reference);
1295 PetscFunctionReturn(PETSC_SUCCESS);
1305 PetscErrorCode ierr = PETSC_SUCCESS, cleanup_ierr;
1308 Vec solution = NULL, entry_backup = NULL;
1310 PetscBool restore_entry = PETSC_FALSE;
1311 PetscBool solve_started = PETSC_FALSE;
1312 PetscBool committed = PETSC_FALSE;
1313 PetscBool converged = PETSC_FALSE;
1314 SNESConvergedReason reason = SNES_CONVERGED_ITERATING;
1315 PetscInt nonlinear_its = 0, function_evals = 0, linear_its = 0;
1316 PetscReal final_norm = PETSC_MAX_REAL;
1319 PetscFunctionBeginUser;
1322 PetscCheck(ibm == NULL && fsi == NULL, PETSC_COMM_WORLD, PETSC_ERR_SUP,
1323 "Newton Krylov version one does not accept IBM or FSI objects.");
1327 if (!user->
Rhs) { ierr = VecDuplicate(user->
Ucont, &user->
Rhs);
if (ierr)
goto cleanup; }
1328 ierr = VecZeroEntries(user->
Rhs);
if (ierr)
goto cleanup;
1344 ierr = VecCopy(user->
Ucont, entry_backup);
if (ierr)
goto cleanup;
1345 restore_entry = PETSC_TRUE;
1346 ierr = VecCopy(user->
Ucont, solution);
if (ierr)
goto cleanup;
1349 "Newton Krylov Jacobian: finite_difference / matrix_free; "
1350 "Preconditioner: %s; PETSc Jacobian matrix type: MATMFFD; "
1351 "PETSc PC type: %s.\n",
1353 "none" :
"frozen_momentum_jacobian / point_block",
1357 solve_started = PETSC_TRUE;
1358 ierr = SNESSolve(snes, NULL, solution);
1359 if (ierr)
goto cleanup;
1360 ierr = SNESGetConvergedReason(snes, &reason);
if (ierr)
goto cleanup;
1361 ierr = SNESGetIterationNumber(snes, &nonlinear_its);
if (ierr)
goto cleanup;
1362 ierr = SNESGetNumberFunctionEvals(snes, &function_evals);
if (ierr)
goto cleanup;
1363 ierr = SNESGetLinearSolveIterations(snes, &linear_its);
if (ierr)
goto cleanup;
1364 ierr = SNESGetFunctionNorm(snes, &final_norm);
if (ierr)
goto cleanup;
1371 committed = PETSC_TRUE;
1372 converged = PETSC_TRUE;
1374 PetscReal held_residual = 0.0, held_residual_2 = 0.0, held_reference = 0.0;
1376 &held_reference, &converged);
if (ierr)
goto cleanup;
1377 committed = (PetscBool)(!PetscIsInfOrNanReal(held_residual_2) && ctx->
have_initial_norm &&
1379 if (!committed) converged = PETSC_FALSE;
1382 "Newton Krylov step %" PetscInt_FMT
": SNES reported %s, but |R|_inf = %.3e is within "
1383 "residual_absolute_tol (%.1e) x a0|U|/dt = %.3e; the step is committed as converged.\n",
1384 simCtx->
step, SNESConvergedReasons[reason], (
double)held_residual,
1386 }
else if (committed) {
1388 "Newton Krylov step %" PetscInt_FMT
": SNES reported %s with |R|_inf = %.3e, above "
1389 "residual_absolute_tol (%.1e) x a0|U|/dt = %.3e; |R|_2 = %.3e is no larger than %.3e at "
1390 "entry, so the step continues from the SNES iterate, not converged.\n",
1391 simCtx->
step, SNESConvergedReasons[reason], (
double)held_residual,
1397 "Newton Krylov step %" PetscInt_FMT
": SNES reported %s and |R|_2 at its iterate is "
1398 "%.3e against %.3e at entry; the step is rolled back.\n",
1399 simCtx->
step, SNESConvergedReasons[reason], (
double)held_residual_2,
1403 "Newton Krylov step %" PetscInt_FMT
": SNES reported %s before an entry residual norm "
1404 "was available (|R|_2 at its iterate is %.3e); the step is rolled back.\n",
1405 simCtx->
step, SNESConvergedReasons[reason], (
double)held_residual_2);
1410 ierr = VecCopy(committed ? solution : entry_backup, user->
Ucont);
if (ierr)
goto cleanup;
1414 restore_entry = PETSC_FALSE;
1417 "Newton Krylov momentum solve: reason=%s (%" PetscInt_FMT
"), Newton iterations=%" PetscInt_FMT
", residual evaluations=%" PetscInt_FMT
", Krylov iterations=%" PetscInt_FMT
", final norm=%.6e, state=%s.\n",
1418 SNESConvergedReasons[reason], (PetscInt)reason, nonlinear_its, function_evals,
1419 linear_its, (
double)final_norm,
1420 !committed ?
"rolled back" : converged ?
"committed" :
"committed, not converged");
1421 if (!committed) ierr = PETSC_ERR_CONV_FAILED;
1427 if (solve_started && snes) {
1428 (void)SNESGetConvergedReason(snes, &reason);
1429 (void)SNESGetIterationNumber(snes, &nonlinear_its);
1430 (void)SNESGetNumberFunctionEvals(snes, &function_evals);
1431 (void)SNESGetLinearSolveIterations(snes, &linear_its);
1432 (void)SNESGetFunctionNorm(snes, &final_norm);
1434 if (restore_entry && entry_backup) {
1435 cleanup_ierr = VecCopy(entry_backup, user->
Ucont);
1436 if (!ierr) ierr = cleanup_ierr;
1438 if (!ierr) ierr = cleanup_ierr;
1440 if (!ierr) ierr = cleanup_ierr;
1442 committed = PETSC_FALSE;
1452 if (solve_started) {
1454 linear_its, final_norm, committed);
1459 cleanup_ierr = VecDestroy(&user->
Rhs);
if (!ierr) ierr = cleanup_ierr;
1463 PetscFunctionReturn(ierr);
MomentumRowType
Classification of one staggered momentum row (location + component).
@ MOM_ROW_FIXED_HOMOGENEOUS
Dummy/tangential row carrying no unknown at all.
@ MOM_ROW_PHYSICAL
Independent unknown governed by the momentum equation.
@ MOM_ROW_PERIODIC_DUPLICATE
Duplicate of a wrapped representative row (see ri, rj, rk).
@ MOM_ROW_FIXED_CONDITIONED
Strong Dirichlet row; the value comes from ApplyBoundaryConditions().
MomentumRowType ClassifyMomentumRow(UserCtx *user, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
Single source of truth for "which staggered momentum rows are unknowns".
PetscBool BoundaryFaceHasWallShear(const BoundaryFaceConfig *face)
Reports whether a boundary face is a wall that exerts shear on the flow.
PetscBool MomentumRowIsSolidMasked(const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k, PetscInt component)
Reports whether a momentum row is masked out by the solid-cell field.
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode ApplyBoundaryConditions(UserCtx *user)
Main boundary-condition orchestrator executed during solver timestepping.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
FieldId
Compile-time identity for a catalogued Eulerian field.
PetscErrorCode PicurvOpenRunCsv(SimCtx *simCtx, const char *dir, const char *filename, const char *header, PicurvCsvLifecycle lifecycle, PetscBool required, FILE **file)
Opens one of the run's CSV records (diagnostics, solver history, profiling) for writing.
@ PICURV_CSV_TRUNCATE_ON_FRESH
A fresh run's first write empties the file; a continued run appends.
#define GLOBAL
Scope for global logging across all processes.
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
#define PROFILE_HELPER_BEGIN
Marks the beginning of a profiled helper: timed only when enabled by name.
#define PROFILE_HELPER_END
Alias of PROFILE_FUNCTION_END for a function that began with PROFILE_HELPER_BEGIN.
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
@ LOG_ERROR
Critical errors that may halt the program.
@ LOG_INFO
Informational messages about program execution.
@ LOG_WARNING
Non-critical issues that warrant attention.
@ LOG_DEBUG
Detailed debugging information.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled function: an always-on aggregate timer.
static PetscReal FrozenMomentumJacobian_FaceEddyViscosity(const UserCtx *user, const PetscReal ***nu_t, PetscInt axis, PetscInt i, PetscInt j, PetscInt k)
Returns the face-averaged eddy viscosity the residual uses on one face.
static PetscErrorCode MomentumNewtonJacobian_Register(SNES snes, MomentumNewtonJacobian *jacobian, MomentumPreconditionerEngine *engine, MomentumNewtonKrylovContext *ctx)
Registers the application orchestration callback and both SNES matrices.
static const MomentumPreconditionerModelOps frozen_momentum_point_block_ops
PetscBool aliases_jacobian_operator
const MomentumPreconditionerModelOps * model_ops
static PetscErrorCode MomentumNewtonKrylov_AssessIterate(MomentumNewtonKrylovContext *ctx, Vec solution, PetscReal *residual, PetscReal *residual_2, PetscReal *reference, PetscBool *satisfied)
Measure the residual at the iterate a failed SNES solve holds, for the failure policy in MomentumSolv...
static PetscErrorCode MomentumPreconditionerEngine_ConfigurePetscPC(MomentumPreconditionerEngine *engine, PC pc)
Applies the validated model/structure-to-PETSc-PC mapping.
static PetscErrorCode FrozenMomentumJacobian_DescribePointBlock(UserCtx *user, MomentumPreconditionerDescription *description)
Describes the audited frozen-coefficient point-block model.
static PetscErrorCode MomentumNewtonKrylov_ApplyConstraints(MomentumNewtonKrylovContext *ctx, Vec X, Vec F)
Replaces every non-independent residual row with an explicit equation.
static PetscErrorCode MomentumPreconditionerEngine_CreateExactPointBlockMatrix(UserCtx *user, Mat *preconditioning_matrix)
Creates the frozen point-block P matrix with its exact scalar pattern.
static PetscErrorCode MomentumPreconditionerEngine_ValidatePetscPC(MomentumPreconditionerEngine *engine, PC pc)
Rejects raw options that select an unvalidated PETSc PC backend.
static PetscReal FrozenMomentumJacobian_MetricNormSquared(Cmpnts metric)
Returns the squared Euclidean norm of one metric vector.
MomentumPreconditionerStructure
@ MOM_NK_PC_STRUCTURE_POINT_BLOCK
@ MOM_NK_PC_STRUCTURE_NONE
static PetscErrorCode MomentumNewtonKrylov_FormJacobian(SNES snes, Vec current_solution, Mat jacobian_operator, Mat preconditioning_matrix, void *vctx)
Updates the Jacobian and then assembles any separate preconditioning matrix.
MomentumPreconditionerDescription description
static PetscErrorCode MomentumPreconditionerEngine_Create(UserCtx *user, Mat jacobian_operator, const MomentumPreconditionerDescription *requested, MomentumPreconditionerEngine *engine)
Validates a model/structure and creates or aliases its matrix.
const char * petsc_pc_type
static void MomentumNewtonKrylov_WriteSummary(const MomentumNewtonKrylovContext *ctx, SNESConvergedReason reason, PetscInt nonlinear_its, PetscInt function_evals, PetscInt linear_its, PetscReal final_norm, PetscBool committed)
Appends one rank-zero structured Newton result for a physical step.
MomentumNewtonFiniteDifferenceMode finite_difference_mode
MomentumNewtonJacobianType type
static PetscErrorCode MomentumNewtonKrylov_ReadLinearizationConfig(MomentumNewtonJacobian *jacobian, MomentumPreconditionerDescription *description)
Reads application-owned Jacobian and preconditioner mathematics.
static PetscErrorCode MomentumPreconditionerEngine_Assemble(MomentumPreconditionerEngine *engine, UserCtx *user, Vec current_solution)
Runs model insertion, common row handling, and final assembly.
static PetscErrorCode MomentumNewtonJacobian_Destroy(MomentumNewtonJacobian *jacobian)
Destroys a partially or fully created Jacobian operator.
MomentumNewtonJacobian jacobian
static void FrozenMomentumJacobian_PointBlock(const UserCtx *user, const Cmpnts ***ucont, const Cmpnts ***csi, const Cmpnts ***eta, const Cmpnts ***zet, const PetscReal ***aj, const PetscReal ***nu_t, PetscInt i, PetscInt j, PetscInt k, PetscScalar block[9])
Returns the frozen-momentum point block for the current residual convention.
static void MomentumNewtonKrylov_OpenHistory(MomentumNewtonKrylovContext *ctx)
Opens the optional rank-zero Newton iteration-history files (per Newton and per Krylov iteration).
MomentumPreconditionerModel model
static PetscErrorCode MomentumNewtonKrylov_LinearMonitor(KSP ksp, PetscInt iteration, PetscReal norm, void *ctx)
Writes the effective KSP tolerance and PETSc-reported norm for each inner iteration.
static PetscErrorCode MomentumNewtonJacobian_Create(SNES snes, MomentumNewtonJacobian *jacobian)
Creates the selected Jacobian operator; currently PETSc MFFD only.
MomentumPreconditionerStructure structure
static PetscErrorCode FrozenMomentumJacobian_AssemblePointBlocks(UserCtx *user, Vec current_solution, Mat preconditioning_matrix)
Inserts only the audited interior frozen-momentum point blocks.
MomentumNewtonJacobianType
@ MOM_NK_JACOBIAN_FINITE_DIFFERENCE
Mat preconditioning_matrix
static PetscErrorCode MomentumNewtonKrylov_Build(UserCtx *user)
Builds the solve context MomentumSolver_NewtonKrylov() keeps for the run.
static FILE * MomentumNewtonKrylov_OpenCsv(const MomentumNewtonKrylovContext *ctx, const char *kind, const char *header)
Opens one of the block's Newton CSV records on rank 0, or returns NULL.
static PetscErrorCode MomentumNewtonJacobian_Update(SNES snes, Vec current_solution, MomentumNewtonJacobian *jacobian)
Updates the matrix-free finite-difference operator base.
PetscBool have_initial_norm
PetscBool owns_preconditioning_matrix
static PetscErrorCode MomentumNewtonKrylov_Validate(UserCtx *user)
Rejects configurations outside the audited version-one feature set.
static PetscErrorCode MomentumPreconditionerEngine_Destroy(MomentumPreconditionerEngine *engine)
Destroys only a separately owned preconditioning matrix.
FILE * linear_history_file
MomentumPreconditionerEngine preconditioning_engine
static PetscErrorCode MomentumNewtonKrylov_FormResidual(SNES snes, Vec X, Vec F, void *ctx)
Adapts a PETSc trial vector to the existing momentum residual path.
static MomentumRowType MomentumNewtonKrylov_ClassifyRow(UserCtx *user, const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
Row classification with solid-cell masking folded in.
MomentumNewtonFiniteDifferenceMode
@ MOM_NK_FD_MODE_MATRIX_FREE
static PetscErrorCode MomentumNewtonKrylov_Monitor(SNES snes, PetscInt iteration, PetscReal norm, void *ctx)
Captures SNES iteration norms and optionally writes PICurv history rows.
static PetscErrorCode MomentumPreconditionerEngine_ApplyConstraintRows(UserCtx *user, Mat preconditioning_matrix)
Inserts all common fixed, homogeneous, and periodic-duplicate rows.
MomentumPreconditionerModel
@ MOM_NK_PC_MODEL_FROZEN_MOMENTUM_JACOBIAN
PetscReal MomentumBDFCoefficient(SimCtx *simCtx)
Returns the BDF physical-time coefficient a0 for the current step.
PetscErrorCode ComputeTotalResidual(UserCtx *user)
Computes the shared spatial-plus-BDF momentum residual in user->Rhs.
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
PetscErrorCode(* Describe)(UserCtx *, MomentumPreconditionerDescription *)
PetscErrorCode(* AssembleInterior)(UserCtx *, Vec, Mat)
#define MomentumSolver_NewtonKrylov_Destroy
#define MomentumSolver_NewtonKrylov
PetscBool mom_nk_monitor_history
BoundaryFaceConfig boundary_faces[6]
SimCtx * simCtx
Back-pointer to the master simulation context.
PetscBool mom_last_converged
@ BC_HANDLER_PERIODIC_GEOMETRIC
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
@ BC_HANDLER_INLET_PRESCRIBED_VELOCITY
@ BC_HANDLER_OUTLET_CONSERVATION
@ BC_HANDLER_WALL_FREE_SLIP
BCHandlerType handler_type
PetscInt rotatefsi
Refused at setup: immersed boundaries and moving bodies are not implemented.
char log_dir[PETSC_MAX_PATH_LEN]
struct MomentumNewtonKrylovContext * momentumNewtonKrylov
PetscInt les
Active LES closure; an LESModelType value.
PetscInt rotateframe
moveframe/rotateframe are refused at setup.
BCFace
Identifies the six logical faces of a structured computational block.
Holds the complete configuration for one of the six boundary faces.
A 3D point or vector with PetscScalar components.
Holds all data related to the state and motion of a body in FSI.
Represents a collection of nodes forming a surface for the IBM.
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 / ν)