428 PetscFunctionBeginUser;
431 PetscCheck(user != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL,
"user is NULL");
432 PetscCheck(rep != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL,
"rep is NULL");
433 PetscCheck(block_number > 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"block_number must be > 0");
435 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"unsupported stability candidate enum");
436 PetscCheck(PetscIsNormalReal(dt) && dt > 0.0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
437 "dt must be finite and positive");
440 PetscCheck(simCtx != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
"user[0].simCtx is NULL");
442 const PetscBool centered = (PetscBool)(simCtx->
les || simCtx->
central);
444 const PetscBool inviscid = (PetscBool)simCtx->
invicid;
445 PetscCheck(inviscid || (PetscIsNormalReal(simCtx->
ren) && simCtx->
ren > 0.0),
446 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"Reynolds number must be finite and positive when viscous");
447 const PetscReal lambda_t = a0 / dt;
448 const PetscReal nu_mol = inviscid ? 0.0 : 1.0 / simCtx->
ren;
449 const PetscInt twoD = simCtx->
TwoD;
459 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
462 PetscReal locmaxB = 0.0, locmaxC = 0.0, locmaxD = 0.0, sel_max = 0.0;
463 PetscReal sel_lc = 0.0, sel_lv = 0.0;
464 PetscInt sel_ci = -1, sel_cj = -1, sel_ck = -1, sel_blk = -1, sel_class = 0, sel_os = 0;
465 PetscInt local_active = 0;
467 for (PetscInt bi = 0; bi < block_number; bi++) {
469 DMDALocalInfo info = u->
info;
470 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
471 const PetscInt xs = info.xs, xe = xs + info.xm;
472 const PetscInt ys = info.ys, ye = ys + info.ym;
473 const PetscInt zs = info.zs, ze = zs + info.zm;
478 const PetscInt lxs = (xs==0)?xs+1:xs, lxe = (xe==mx)?xe-1:xe;
479 const PetscInt lys = (ys==0)?ys+1:ys, lye = (ye==my)?ye-1:ye;
480 const PetscInt lzs = (zs==0)?zs+1:zs, lze = (ze==mz)?ze-1:ze;
496 Cmpnts ***ucont, ***ucat = NULL;
497 Cmpnts ***icsi, ***ieta, ***izet, ***jcsi, ***jeta, ***jzet, ***kcsi, ***keta, ***kzet;
498 Cmpnts ***csi = NULL, ***eta = NULL, ***zet = NULL;
499 PetscReal ***aj, ***iaj, ***jaj, ***kaj, ***nvert, ***nut = NULL;
501 ierr = DMDAVecGetArrayRead(u->
fda, u->
lUcont, &ucont); CHKERRQ(ierr);
502 ierr = DMDAVecGetArrayRead(u->
da, u->
lAj, &aj); CHKERRQ(ierr);
503 ierr = DMDAVecGetArrayRead(u->
da, u->
lIAj, &iaj); CHKERRQ(ierr);
504 ierr = DMDAVecGetArrayRead(u->
da, u->
lJAj, &jaj); CHKERRQ(ierr);
505 ierr = DMDAVecGetArrayRead(u->
da, u->
lKAj, &kaj); CHKERRQ(ierr);
506 ierr = DMDAVecGetArrayRead(u->
fda, u->
lICsi, &icsi); CHKERRQ(ierr);
507 ierr = DMDAVecGetArrayRead(u->
fda, u->
lIEta, &ieta); CHKERRQ(ierr);
508 ierr = DMDAVecGetArrayRead(u->
fda, u->
lIZet, &izet); CHKERRQ(ierr);
509 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJCsi, &jcsi); CHKERRQ(ierr);
510 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJEta, &jeta); CHKERRQ(ierr);
511 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJZet, &jzet); CHKERRQ(ierr);
512 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKCsi, &kcsi); CHKERRQ(ierr);
513 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKEta, &keta); CHKERRQ(ierr);
514 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKZet, &kzet); CHKERRQ(ierr);
515 ierr = DMDAVecGetArrayRead(u->
da, u->
lNvert, &nvert); CHKERRQ(ierr);
516 if (has_nut) { ierr = DMDAVecGetArrayRead(u->
da, u->
lNu_t, &nut); CHKERRQ(ierr); }
520 ierr = DMDAVecGetArrayRead(u->
fda, u->
lUcat, &ucat); CHKERRQ(ierr);
521 ierr = DMDAVecGetArrayRead(u->
fda, u->
lCsi, &csi); CHKERRQ(ierr);
522 ierr = DMDAVecGetArrayRead(u->
fda, u->
lEta, &eta); CHKERRQ(ierr);
523 ierr = DMDAVecGetArrayRead(u->
fda, u->
lZet, &zet); CHKERRQ(ierr);
527 PetscErrorCode cell_err = 0;
528 PetscInt be_i = -1, be_j = -1, be_k = -1;
529 const char *be_what = NULL;
531 for (PetscInt k = lzs; k < lze; k++) {
532 for (PetscInt j = lys; j < lye; j++) {
533 for (PetscInt i = lxs; i < lxe; i++) {
536 npx1, npy1, npz1, twoD);
537 if (rows == 0)
continue;
539 const PetscReal Ajc = aj[k][j][i];
540 if (!(PetscIsNormalReal(Ajc) && Ajc > 0.0)) {
541 cell_err = PETSC_ERR_FP; be_i = i; be_j = j; be_k = k;
542 be_what =
"non-finite/non-positive cell inverse-Jacobian";
548 info.gxs, info.gxs+info.gxm,
'i');
550 info.gys, info.gys+info.gym,
'j');
552 info.gzs, info.gzs+info.gzm,
'k');
555 const PetscBool bnd = (PetscBool)((npx0 && i<=1) || (npx1 && i>=mx-2) ||
556 (npy0 && j<=1) || (npy1 && j>=my-2) ||
557 (npz0 && k<=1) || (npz1 && k>=mz-2));
559 const PetscInt cls = ib ? 2 : (bnd ? 1 : 0);
562 const PetscReal Uxp = ucont[k][j][i].
x, Uxm = ucont[k][j][i-1].
x;
563 const PetscReal Uyp = ucont[k][j][i].
y, Uym = ucont[k][j-1][i].
y;
564 const PetscReal Uzp = ucont[k][j][i].
z, Uzm = ucont[k-1][j][i].
z;
565 const PetscReal divU = PetscAbsReal((Uxp-Uxm)+(Uyp-Uym)+(Uzp-Uzm));
566 const PetscReal fx = centered ? 1.0 : (mod_x ? 2.5 : (4.0/3.0));
567 const PetscReal fy = centered ? 1.0 : (mod_y ? 2.5 : (4.0/3.0));
568 const PetscReal fz = centered ? 1.0 : (mod_z ? 2.5 : (4.0/3.0));
571 const PetscReal lcB = 0.5 * Ajc * (
572 fx * (PetscAbsReal(Uxp)+PetscAbsReal(Uxm))
573 + fy * (PetscAbsReal(Uyp)+PetscAbsReal(Uym))
574 + fz * (PetscAbsReal(Uzp)+PetscAbsReal(Uzm)) );
575 const PetscReal lcC = lcB + 0.5 * Ajc * divU;
579 const Cmpnts duc = { 0.5*(ucat[k][j][i+1].
x-ucat[k][j][i-1].
x),
580 0.5*(ucat[k][j][i+1].y-ucat[k][j][i-1].y),
581 0.5*(ucat[k][j][i+1].
z-ucat[k][j][i-1].
z) };
582 const Cmpnts due = { 0.5*(ucat[k][j+1][i].
x-ucat[k][j-1][i].
x),
583 0.5*(ucat[k][j+1][i].y-ucat[k][j-1][i].y),
584 0.5*(ucat[k][j+1][i].
z-ucat[k][j-1][i].
z) };
585 const Cmpnts duz = { 0.5*(ucat[k+1][j][i].
x-ucat[k-1][j][i].
x),
586 0.5*(ucat[k+1][j][i].y-ucat[k-1][j][i].y),
587 0.5*(ucat[k+1][j][i].
z-ucat[k-1][j][i].
z) };
588 const Cmpnts C = csi[k][j][i], E = eta[k][j][i], Z = zet[k][j][i];
589 #define MOM_ROW(cmp) ( \
590 PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
591 PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
592 PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )
595 const PetscReal lcD = lcC + lgrad;
601 for (PetscInt s = 0; s < 2; s++) {
602 const PetscInt fi = (s==0) ? i : i-1;
603 if (!(PetscIsNormalReal(iaj[k][j][fi]) && iaj[k][j][fi] > 0.0)) {
604 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
605 be_what =
"non-finite/non-positive xi-face inverse-Jacobian";
goto block_cleanup; }
606 PetscReal nuf = nu_mol;
608 PetscReal nt = 0.5*(nut[k][j][fi] + nut[k][j][fi+1]);
609 if ((wxn && fi==0) || (wxp && fi==mx-2)) nt = 0.0;
612 lv += PetscAbsReal(nuf) * Ajc * iaj[k][j][fi]
613 *
MomFaceGabs(icsi[k][j][fi], ieta[k][j][fi], izet[k][j][fi]);
616 for (PetscInt s = 0; s < 2; s++) {
617 const PetscInt fj = (s==0) ? j : j-1;
618 if (!(PetscIsNormalReal(jaj[k][fj][i]) && jaj[k][fj][i] > 0.0)) {
619 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
620 be_what =
"non-finite/non-positive eta-face inverse-Jacobian";
goto block_cleanup; }
621 PetscReal nuf = nu_mol;
623 PetscReal nt = 0.5*(nut[k][fj][i] + nut[k][fj+1][i]);
624 if ((wyn && fj==0) || (wyp && fj==my-2)) nt = 0.0;
628 lv += PetscAbsReal(nuf) * Ajc * jaj[k][fj][i]
629 *
MomFaceGabs(jeta[k][fj][i], jcsi[k][fj][i], jzet[k][fj][i]);
632 for (PetscInt s = 0; s < 2; s++) {
633 const PetscInt fk = (s==0) ? k : k-1;
634 if (!(PetscIsNormalReal(kaj[fk][j][i]) && kaj[fk][j][i] > 0.0)) {
635 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
636 be_what =
"non-finite/non-positive zeta-face inverse-Jacobian";
goto block_cleanup; }
637 PetscReal nuf = nu_mol;
639 PetscReal nt = 0.5*(nut[fk][j][i] + nut[fk+1][j][i]);
640 if ((wzn && fk==0) || (wzp && fk==mz-2)) nt = 0.0;
644 lv += PetscAbsReal(nuf) * Ajc * kaj[fk][j][i]
645 *
MomFaceGabs(kzet[fk][j][i], kcsi[fk][j][i], keta[fk][j][i]);
652 PetscInt one_sided = 0;
659 const PetscReal lB = lambda_t + lcB + lv;
660 const PetscReal lC = lambda_t + lcC + lv;
661 const PetscReal lD = lambda_t + lcD + lv;
662 if (PetscIsInfOrNanReal(lD)) {
663 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
664 be_what =
"non-finite stability estimate";
goto block_cleanup;
666 locmaxB = PetscMax(locmaxB, lB);
667 locmaxC = PetscMax(locmaxC, lC);
668 locmaxD = PetscMax(locmaxD, lD);
672 if (lsel > sel_max) {
673 sel_max = lsel; sel_lc = lcsel; sel_lv = lv;
674 sel_ci = i; sel_cj = j; sel_ck = k; sel_blk = bi;
675 sel_class = cls; sel_os = one_sided;
684 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lUcont, &ucont); CHKERRQ(ierr);
685 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lAj, &aj); CHKERRQ(ierr);
686 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lIAj, &iaj); CHKERRQ(ierr);
687 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lJAj, &jaj); CHKERRQ(ierr);
688 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lKAj, &kaj); CHKERRQ(ierr);
689 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lICsi, &icsi); CHKERRQ(ierr);
690 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lIEta, &ieta); CHKERRQ(ierr);
691 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lIZet, &izet); CHKERRQ(ierr);
692 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJCsi, &jcsi); CHKERRQ(ierr);
693 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJEta, &jeta); CHKERRQ(ierr);
694 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJZet, &jzet); CHKERRQ(ierr);
695 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKCsi, &kcsi); CHKERRQ(ierr);
696 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKEta, &keta); CHKERRQ(ierr);
697 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKZet, &kzet); CHKERRQ(ierr);
698 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lNvert, &nvert); CHKERRQ(ierr);
699 if (has_nut) { ierr = DMDAVecRestoreArrayRead(u->
da, u->
lNu_t, &nut); CHKERRQ(ierr); }
700 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lUcat, &ucat); CHKERRQ(ierr);
701 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lCsi, &csi); CHKERRQ(ierr);
702 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lEta, &eta); CHKERRQ(ierr);
703 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lZet, &zet); CHKERRQ(ierr);
706 PetscCheck(cell_err == 0, PETSC_COMM_SELF, cell_err,
"%s at (%" PetscInt_FMT
707 ",%" PetscInt_FMT
",%" PetscInt_FMT
")", be_what ? be_what :
"error", be_i, be_j, be_k);
714 PetscReal loc3[3] = { locmaxB, locmaxC, locmaxD }, glo3[3];
715 ierr = MPI_Allreduce(loc3, glo3, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
717 PetscInt global_active = 0;
718 ierr = MPI_Allreduce(&local_active, &global_active, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
722 const PetscReal sel_global = glo3[(int)candidate];
723 PetscMPIInt nproc, claim, owner;
724 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &nproc); CHKERRQ(ierr);
725 claim = (sel_max == sel_global) ? rank : nproc;
726 ierr = MPI_Allreduce(&claim, &owner, 1, MPI_INT, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
727 if (owner == nproc) owner = 0;
729 PetscReal dbuf[2] = { sel_lc, sel_lv };
730 PetscInt ibuf[6] = { sel_ci, sel_cj, sel_ck, sel_blk, sel_class, sel_os };
731 ierr = MPI_Bcast(dbuf, 2, MPIU_REAL, owner, PETSC_COMM_WORLD); CHKERRQ(ierr);
732 ierr = MPI_Bcast(ibuf, 6, MPIU_INT, owner, PETSC_COMM_WORLD); CHKERRQ(ierr);
739 rep->
ci = ibuf[0]; rep->
cj = ibuf[1]; rep->
ck = ibuf[2];
745 if (global_active == 0) {
748 PetscCheck(PetscIsNormalReal(rep->
lambda) && rep->
lambda > 0.0, PETSC_COMM_WORLD, PETSC_ERR_FP,
749 "momentum stability estimate is non-finite or non-positive with %" PetscInt_FMT
750 " active cells", global_active);
758 PetscFunctionReturn(0);
777 const PetscInt ti = simCtx->
step;
778 const PetscReal dt = simCtx->
dt;
782 const PetscReal alfa[] = {0.25, 1.0/3.0, 0.5, 1.0};
786 PetscBool force_restart = PETSC_FALSE;
790 const PetscReal tol_abs_delta = simCtx->
mom_atol;
791 const PetscReal tol_rtol_delta = simCtx->
mom_rtol;
796 PetscInt istage, pseudo_iter;
797 PetscInt accepted_iter = 0, rejected_iter = 0, recovery_streak = 0;
798 PetscReal ts, te, cput;
801 PetscReal global_norm_delta = 10.0;
802 PetscReal global_rel_delta = 1.0;
803 PetscReal global_norm_resid = 1.0;
804 PetscReal global_rel_resid = 1.0;
805 PetscReal smoothed_trial_ratio = 1.0;
814 PetscReal lambda_max = 0.0;
824 PetscReal resid_ref = 0.0;
825 PetscReal dtau_min, dtau_max;
828 PetscReal *delta_sol_norm_init, *delta_sol_norm_prev, *delta_sol_norm_curr, *delta_sol_rel_curr;
829 PetscReal *resid_norm_init, *resid_norm_prev, *resid_norm_curr, *resid_rel_curr;
830 PetscReal *pseudo_dtau;
831 PetscReal *trial_ratio_log;
832 PetscReal last_accepted_resid;
834 PetscFunctionBeginUser;
836 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
840 ierr = PetscMalloc2(block_number, &delta_sol_norm_init, block_number, &delta_sol_norm_prev); CHKERRQ(ierr);
841 ierr = PetscMalloc2(block_number, &delta_sol_norm_curr, block_number, &delta_sol_rel_curr); CHKERRQ(ierr);
842 ierr = PetscMalloc2(block_number, &resid_norm_init, block_number, &resid_norm_prev); CHKERRQ(ierr);
843 ierr = PetscMalloc2(block_number, &resid_norm_curr, block_number, &pseudo_dtau); CHKERRQ(ierr);
844 ierr = PetscMalloc1(block_number, &resid_rel_curr); CHKERRQ(ierr);
845 ierr = PetscMalloc1(block_number, &trial_ratio_log); CHKERRQ(ierr);
846 ierr = PetscMalloc1(block_number, &pRhs); CHKERRQ(ierr);
847 last_accepted_resid = 0.0;
849 ierr = PetscTime(&ts); CHKERRQ(ierr);
853 if (block_number > 1) {
857 for (PetscInt bi = 0; bi < block_number; bi++) {
863 ierr = VecDuplicate(user[bi].Ucont, &user[bi].Rhs); CHKERRQ(ierr);
864 ierr = VecDuplicate(user[bi].Rhs, &pRhs[bi]); CHKERRQ(ierr);
865 ierr = VecDuplicate(user[bi].Ucont, &user[bi].dUcont); CHKERRQ(ierr);
866 ierr = VecDuplicate(user[bi].Ucont, &user[bi].pUcont); CHKERRQ(ierr);
869 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
875 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
878 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_init[bi]); CHKERRQ(ierr);
884 ierr = VecNorm(user[bi].Ucont, NORM_INFINITY, &ucont_inf); CHKERRQ(ierr);
889 resid_norm_prev[bi] = resid_norm_init[bi];
890 delta_sol_norm_prev[bi] = 1000.0;
893 LOG_ALLOW(
GLOBAL,
LOG_INFO,
" Block %d | Max RHS = %.6f | initial pseudo-CFL = %.4f .\n", bi, resid_norm_init[bi], cfl);
910 for (PetscInt bi = 0; bi < block_number; bi++) {
911 pseudo_dtau[bi] = cfl / lambda_max;
919 PetscBool shadow = PETSC_FALSE;
920 ierr = PetscOptionsGetBool(NULL, NULL,
"-mom_stability_shadow", &shadow, NULL); CHKERRQ(ierr);
929 "Momentum scale [shadow]: legacy_dtau=%.4e new_dtau=%.4e ratio=%.4f limiter=%s | "
930 "lambda_legacy=%.4e lambda_new=%.4e (B=%.4e C=%.4e D=%.4e) | "
931 "lt=%.4e lc=%.4e lv=%.4e | cell=(%d,%d,%d) blk=%d class=%d onesided=%d\n",
932 cfl / lambda_max, cfl / rep.
lambda, rep.
lambda / lambda_max, lim,
940 "Dual-time solver: lambda_max=%.4e [1/s] resid_ref=%.4e dtau_init=%.4e dtau range [%.4e, %.4e] "
941 "CFL range [%.4f, %.4f] rejection_threshold=%.3f (EMA alpha=%.2f) "
942 "growth=%.3f reduction=%.3f max_accepted=%d.\n",
943 lambda_max, resid_ref, cfl / lambda_max, dtau_min, dtau_max,
952 PetscBool residual_convergence_enabled =
954 PetscBool converged = PETSC_FALSE;
955 PetscBool last_trial_nonfinite = PETSC_FALSE;
958 const PetscInt max_total_attempts = max_pseudo_steps * 3;
959 while (!converged && accepted_iter < max_pseudo_steps && pseudo_iter < max_total_attempts)
962 force_restart = PETSC_FALSE;
965 for (PetscInt bi = 0; bi < block_number; bi++) {
966 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
967 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
973 for (PetscInt bi = 0; bi < block_number; bi++) {
976 for (istage = 0; istage < 4; istage++) {
983 ierr = VecWAXPY(user[bi].Ucont,
984 pseudo_dtau[bi] * alfa[istage],
986 user[bi].pUcont); CHKERRQ(ierr);
1004 ierr = VecWAXPY(user[bi].dUcont, -1.0, user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1007 ierr = VecNorm(user[bi].dUcont, NORM_INFINITY, &delta_sol_norm_curr[bi]); CHKERRQ(ierr);
1008 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_curr[bi]); CHKERRQ(ierr);
1011 if (pseudo_iter == 1) {
1012 delta_sol_norm_init[bi] = delta_sol_norm_curr[bi];
1013 delta_sol_rel_curr[bi] = 1.0;
1014 resid_rel_curr[bi] = 1.0;
1017 if (delta_sol_norm_init[bi] > 1.0e-10)
1018 delta_sol_rel_curr[bi] = delta_sol_norm_curr[bi] / delta_sol_norm_init[bi];
1020 delta_sol_rel_curr[bi] = 0.0;
1022 if(resid_norm_init[bi] > 1.0e-10)
1023 resid_rel_curr[bi] = resid_norm_curr[bi] / resid_norm_init[bi];
1025 resid_rel_curr[bi] = 0.0;
1030 const PetscReal resid_floor_log = 1.0e-30;
1031 if (resid_norm_prev[bi] > resid_floor_log)
1032 trial_ratio_log[bi] = resid_norm_curr[bi] / resid_norm_prev[bi];
1033 else if (resid_norm_curr[bi] <= resid_floor_log)
1034 trial_ratio_log[bi] = 0.0;
1036 trial_ratio_log[bi] = PETSC_MAX_REAL;
1041 global_norm_delta = -1.0e20;
1042 global_rel_delta = -1.0e20;
1043 global_norm_resid = -1.0e20;
1044 global_rel_resid = -1.0e20;
1046 for (PetscInt bi = 0; bi < block_number; bi++) {
1047 global_norm_delta = PetscMax(delta_sol_norm_curr[bi], global_norm_delta);
1048 global_rel_delta = PetscMax(delta_sol_rel_curr[bi], global_rel_delta);
1049 global_norm_resid = PetscMax(resid_norm_curr[bi], global_norm_resid);
1050 global_rel_resid = PetscMax(resid_rel_curr[bi], global_rel_resid);
1052 ierr = PetscTime(&te); CHKERRQ(ierr);
1055 pseudo_iter, global_norm_delta, global_rel_delta, global_rel_resid, cput);
1058 const PetscReal resid_floor = 1.0e-30;
1059 PetscReal global_trial_ratio = 0.0;
1060 PetscBool global_nonfinite = PETSC_FALSE;
1061 for (PetscInt bi = 0; bi < block_number; bi++) {
1063 if (resid_norm_prev[bi] > resid_floor) {
1064 ratio = resid_norm_curr[bi] / resid_norm_prev[bi];
1065 }
else if (resid_norm_curr[bi] <= resid_floor) {
1068 ratio = PETSC_MAX_REAL;
1070 global_trial_ratio = PetscMax(global_trial_ratio, ratio);
1071 global_nonfinite = (PetscBool)(global_nonfinite ||
1072 PetscIsInfOrNanReal(delta_sol_norm_curr[bi]) ||
1073 PetscIsInfOrNanReal(resid_norm_curr[bi]) ||
1074 PetscIsInfOrNanReal(ratio));
1077 PetscReal reduced_trial_ratio;
1078 PetscMPIInt local_nonfinite = global_nonfinite ? 1 : 0;
1079 PetscMPIInt reduced_nonfinite = 0;
1080 ierr = MPI_Allreduce(&global_trial_ratio, &reduced_trial_ratio, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
1081 ierr = MPI_Allreduce(&local_nonfinite, &reduced_nonfinite, 1, MPI_INT, MPI_LOR, PETSC_COMM_WORLD); CHKERRQ(ierr);
1082 global_trial_ratio = reduced_trial_ratio;
1083 global_nonfinite = reduced_nonfinite ? PETSC_TRUE : PETSC_FALSE;
1084 last_trial_nonfinite = global_nonfinite;
1098 PetscReal trial_smoothed = smoothed_trial_ratio;
1099 if (!global_nonfinite) {
1104 " [k=%d] raw_ratio=%.4e smoothed_ratio=%.4e (threshold=%.3f) | "
1105 "|R_prev|=%.6e | |R_curr|=%.6e | CFL=%.6f\n",
1106 pseudo_iter, global_trial_ratio, trial_smoothed,
1108 resid_norm_prev[0], resid_norm_curr[0], pseudo_dtau[0]);
1112 force_restart = global_nonfinite;
1114 force_restart = (PetscBool)(global_nonfinite ||
1118 if (force_restart) {
1122 PetscReal old_dtau = pseudo_dtau[0];
1129 recovery_streak = 0;
1130 for (PetscInt bi = 0; bi < block_number; bi++) {
1131 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1132 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
1136 pseudo_dtau[bi] = next_dtau;
1139 " Trial %d REJECTED (raw_ratio=%.4e, smoothed=%.4e, nonfinite=%d); "
1140 "dtau %.4e -> %.4e (cfl_eff %.4f -> %.4f)%s\n",
1141 pseudo_iter, global_trial_ratio, trial_smoothed, (
int)global_nonfinite,
1142 old_dtau, next_dtau, old_dtau * lambda_max, next_dtau * lambda_max,
1143 (old_dtau == next_dtau) ?
" [AT FLOOR — no dtau reduction]" :
"");
1146 for (PetscInt bi = 0; bi < block_number; bi++) {
1148 char filen[PETSC_MAX_PATH_LEN + 128];
1149 ierr = PetscSNPrintf(filen,
sizeof(filen),
1150 "%s/Momentum_Solver_DualTime_Picard_Jameson_RK_History_Block_%1d.log",
1151 simCtx->
log_dir, bi); CHKERRQ(ierr);
1153 f = fopen(filen,
"w");
1155 f = fopen(filen,
"a");
1157 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1159 PetscFPrintf(PETSC_COMM_WORLD, f,
1160 "Step: %d | PseudoIter(k): %d | dtau: %.6e | cfl_eff: %.4f | |dUk|: %le | "
1161 "|dUk|/|dU0|: %le | |Rk|: %le | |Rk|/|R0|: %le | "
1162 "trial_ratio: %le | smoothed_ratio: %le | status: rejected | "
1163 "dtau_after: %.6e | cfl_eff_after: %.4f\n",
1164 (
int)ti, (
int)pseudo_iter, old_dtau, old_dtau * lambda_max,
1165 delta_sol_norm_curr[bi], delta_sol_rel_curr[bi],
1166 resid_norm_curr[bi], resid_rel_curr[bi],
1167 trial_ratio_log[bi], trial_smoothed,
1168 next_dtau, next_dtau * lambda_max);
1172 if (old_dtau <= dtau_min) {
1173 if (global_nonfinite) {
1174 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
1175 "Momentum solver produced a non-finite trial at minimum pseudo-CFL.");
1180 " Trial %d REJECTED (ratio=%.4e) at minimum dtau (%.4e, cfl_eff=%.4f) "
1181 "with no further reduction possible; breaking retry loop.\n",
1182 pseudo_iter, global_trial_ratio, old_dtau, old_dtau * lambda_max);
1189 smoothed_trial_ratio = trial_smoothed;
1190 last_trial_nonfinite = PETSC_FALSE;
1191 last_accepted_resid = resid_norm_curr[0];
1192 for (PetscInt bi = 0; bi < block_number; bi++) {
1193 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
1194 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
1195 resid_norm_prev[bi] = resid_norm_curr[bi];
1196 delta_sol_norm_prev[bi] = delta_sol_norm_curr[bi];
1202 PetscReal old_dtau = pseudo_dtau[0];
1203 PetscReal next_dtau = old_dtau;
1204 if (global_trial_ratio < 0.90) {
1207 recovery_streak = 0;
1208 }
else if (global_trial_ratio <= 1.0) {
1211 if (recovery_streak >= 3) {
1213 recovery_streak = 0;
1218 recovery_streak = 0;
1224 next_dtau = PetscMin(next_dtau, dtau_max);
1225 next_dtau = PetscMin(next_dtau, cfl_cap / lambda_max);
1226 next_dtau = PetscMax(next_dtau, dtau_min);
1227 for (PetscInt bi = 0; bi < block_number; bi++) pseudo_dtau[bi] = next_dtau;
1230 " Trial %d ACCEPTED (raw_ratio=%.4e, smoothed=%.4e); |dU|=%.6e | "
1231 "dtau %.4e -> %.4e (cfl_eff %.4f -> %.4f)\n",
1232 pseudo_iter, global_trial_ratio, trial_smoothed, global_norm_delta,
1233 old_dtau, next_dtau, old_dtau * lambda_max, next_dtau * lambda_max);
1237 for (PetscInt bi = 0; bi < block_number; bi++) {
1239 char filen[PETSC_MAX_PATH_LEN + 128];
1240 ierr = PetscSNPrintf(filen,
sizeof(filen),
1241 "%s/Momentum_Solver_DualTime_Picard_Jameson_RK_History_Block_%1d.log",
1242 simCtx->
log_dir, bi); CHKERRQ(ierr);
1244 f = fopen(filen,
"w");
1246 f = fopen(filen,
"a");
1248 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1250 PetscFPrintf(PETSC_COMM_WORLD, f,
1251 "Step: %d | PseudoIter(k): %d | dtau: %.6e | cfl_eff: %.4f | |dUk|: %le | "
1252 "|dUk|/|dU0|: %le | |Rk|: %le | |Rk|/|R0|: %le | "
1253 "trial_ratio: %le | smoothed_ratio: %le | status: accepted | "
1254 "dtau_after: %.6e | cfl_eff_after: %.4f\n",
1255 (
int)ti, (
int)pseudo_iter, old_dtau, old_dtau * lambda_max,
1256 delta_sol_norm_curr[bi], delta_sol_rel_curr[bi],
1257 resid_norm_curr[bi], resid_rel_curr[bi],
1258 trial_ratio_log[bi], trial_smoothed,
1259 next_dtau, next_dtau * lambda_max);
1297 if (residual_convergence_enabled) {
1298 const PetscBool residual_abs_pass = (PetscBool)(
1300 global_norm_resid <= simCtx->mom_resid_atol * resid_ref);
1301 const PetscBool residual_rel_pass = (PetscBool)(
1302 simCtx->
mom_resid_rtol > 0.0 && global_rel_resid <= simCtx->mom_resid_rtol);
1303 const PetscBool update_pass = (PetscBool)(
1304 tol_rtol_delta <= 0.0 || global_rel_delta <= tol_rtol_delta);
1305 converged = (PetscBool)(residual_abs_pass || (residual_rel_pass && update_pass));
1307 converged = (PetscBool)(global_norm_delta <= tol_abs_delta &&
1308 global_rel_delta <= tol_rtol_delta);
1311 if (block_number > 1) {
1316 if (last_trial_nonfinite) {
1317 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
1318 "Momentum solver exhausted its attempt limit while recovering from a non-finite trial.");
1325 PetscReal next_dtau_start = pseudo_dtau[0];
1326 PetscReal next_cfl_warmstart = next_dtau_start * lambda_max;
1330 " Step %d finished: dtau=%.4e cfl_eff=%.4f lambda_max=%.4e [1/s]. "
1331 "Next step warm-starts at cfl=%.4f.\n",
1332 simCtx->
step, next_dtau_start, next_cfl_warmstart, lambda_max, next_cfl_warmstart);
1342 if (accepted_iter == 0) {
1343 for (PetscInt bi = 0; bi < block_number; bi++) {
1344 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1345 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
1348 for (PetscInt bi = 0; bi < block_number; bi++) {
1356 PetscPrintf(PETSC_COMM_WORLD,
1357 "[WARNING] Momentum solver step %d: reached %d total attempts (%d accepted, %d rejected) "
1358 "without convergence; continuing from last accepted finite state.\n",
1359 (
int)ti, pseudo_iter, accepted_iter, rejected_iter);
1361 if (accepted_iter == 0) {
1362 PetscPrintf(PETSC_COMM_WORLD,
1363 "[WARNING] Momentum solver step %d: no pseudo-time trials were accepted; "
1364 "retaining physical-step entry state.\n", (
int)ti);
1367 "Momentum solver finished: %d attempts (%d accepted, %d rejected) of %d max accepted / %d hard cap, "
1368 "converged=%s, last accepted |R|=%.6e, last accepted |dU|=%.6e, "
1369 "next_dtau=%.4e (cfl=%.4f).\n",
1370 pseudo_iter, accepted_iter, rejected_iter, max_pseudo_steps, max_total_attempts,
1371 converged ?
"yes" :
"no",
1372 (accepted_iter > 0) ? last_accepted_resid : resid_norm_init[0],
1373 (accepted_iter > 0) ? delta_sol_norm_prev[0] : 0.0,
1374 next_dtau_start, next_cfl_warmstart);
1377 for (PetscInt bi = 0; bi < block_number; bi++) {
1378 ierr = VecDestroy(&user[bi].Rhs); CHKERRQ(ierr);
1379 ierr = VecDestroy(&user[bi].dUcont); CHKERRQ(ierr);
1380 ierr = VecDestroy(&user[bi].pUcont); CHKERRQ(ierr);
1381 ierr = VecDestroy(&pRhs[bi]); CHKERRQ(ierr);
1383 ierr = PetscFree(pRhs); CHKERRQ(ierr);
1385 ierr = PetscFree2(delta_sol_norm_init, delta_sol_norm_prev);CHKERRQ(ierr);
1386 ierr = PetscFree2(delta_sol_norm_curr, delta_sol_rel_curr);CHKERRQ(ierr);
1387 ierr = PetscFree2(resid_norm_init, resid_norm_prev);CHKERRQ(ierr);
1388 ierr = PetscFree2(resid_norm_curr, pseudo_dtau); CHKERRQ(ierr);
1389 ierr = PetscFree(resid_rel_curr); CHKERRQ(ierr);
1390 ierr = PetscFree(trial_ratio_log); CHKERRQ(ierr);
1393 PetscFunctionReturn(0);