402 PetscFunctionBeginUser;
405 PetscCheck(user != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL,
"user is NULL");
406 PetscCheck(rep != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL,
"rep is NULL");
407 PetscCheck(block_number > 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"block_number must be > 0");
409 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"unsupported stability candidate enum");
410 PetscCheck(PetscIsNormalReal(dt) && dt > 0.0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
411 "dt must be finite and positive");
414 PetscCheck(simCtx != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
"user[0].simCtx is NULL");
416 const PetscBool centered = (PetscBool)(simCtx->
les || simCtx->
central);
417 const PetscBool has_nut = (PetscBool)(simCtx->
les || simCtx->
rans);
418 const PetscBool inviscid = (PetscBool)simCtx->
invicid;
419 PetscCheck(inviscid || (PetscIsNormalReal(simCtx->
ren) && simCtx->
ren > 0.0),
420 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"Reynolds number must be finite and positive when viscous");
421 const PetscReal lambda_t = a0 / dt;
422 const PetscReal nu_mol = inviscid ? 0.0 : 1.0 / simCtx->
ren;
423 const PetscInt twoD = simCtx->
TwoD;
433 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
436 PetscReal locmaxB = 0.0, locmaxC = 0.0, locmaxD = 0.0, sel_max = 0.0;
437 PetscReal sel_lc = 0.0, sel_lv = 0.0;
438 PetscInt sel_ci = -1, sel_cj = -1, sel_ck = -1, sel_blk = -1, sel_class = 0, sel_os = 0;
439 PetscInt local_active = 0;
441 for (PetscInt bi = 0; bi < block_number; bi++) {
443 DMDALocalInfo info = u->
info;
444 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
445 const PetscInt xs = info.xs, xe = xs + info.xm;
446 const PetscInt ys = info.ys, ye = ys + info.ym;
447 const PetscInt zs = info.zs, ze = zs + info.zm;
452 const PetscInt lxs = (xs==0)?xs+1:xs, lxe = (xe==mx)?xe-1:xe;
453 const PetscInt lys = (ys==0)?ys+1:ys, lye = (ye==my)?ye-1:ye;
454 const PetscInt lzs = (zs==0)?zs+1:zs, lze = (ze==mz)?ze-1:ze;
470 Cmpnts ***ucont, ***ucat = NULL;
471 Cmpnts ***icsi, ***ieta, ***izet, ***jcsi, ***jeta, ***jzet, ***kcsi, ***keta, ***kzet;
472 Cmpnts ***csi = NULL, ***eta = NULL, ***zet = NULL;
473 PetscReal ***aj, ***iaj, ***jaj, ***kaj, ***nvert, ***nut = NULL;
475 ierr = DMDAVecGetArrayRead(u->
fda, u->
lUcont, &ucont); CHKERRQ(ierr);
476 ierr = DMDAVecGetArrayRead(u->
da, u->
lAj, &aj); CHKERRQ(ierr);
477 ierr = DMDAVecGetArrayRead(u->
da, u->
lIAj, &iaj); CHKERRQ(ierr);
478 ierr = DMDAVecGetArrayRead(u->
da, u->
lJAj, &jaj); CHKERRQ(ierr);
479 ierr = DMDAVecGetArrayRead(u->
da, u->
lKAj, &kaj); CHKERRQ(ierr);
480 ierr = DMDAVecGetArrayRead(u->
fda, u->
lICsi, &icsi); CHKERRQ(ierr);
481 ierr = DMDAVecGetArrayRead(u->
fda, u->
lIEta, &ieta); CHKERRQ(ierr);
482 ierr = DMDAVecGetArrayRead(u->
fda, u->
lIZet, &izet); CHKERRQ(ierr);
483 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJCsi, &jcsi); CHKERRQ(ierr);
484 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJEta, &jeta); CHKERRQ(ierr);
485 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJZet, &jzet); CHKERRQ(ierr);
486 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKCsi, &kcsi); CHKERRQ(ierr);
487 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKEta, &keta); CHKERRQ(ierr);
488 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKZet, &kzet); CHKERRQ(ierr);
489 ierr = DMDAVecGetArrayRead(u->
da, u->
lNvert, &nvert); CHKERRQ(ierr);
490 if (has_nut) { ierr = DMDAVecGetArrayRead(u->
da, u->
lNu_t, &nut); CHKERRQ(ierr); }
494 ierr = DMDAVecGetArrayRead(u->
fda, u->
lUcat, &ucat); CHKERRQ(ierr);
495 ierr = DMDAVecGetArrayRead(u->
fda, u->
lCsi, &csi); CHKERRQ(ierr);
496 ierr = DMDAVecGetArrayRead(u->
fda, u->
lEta, &eta); CHKERRQ(ierr);
497 ierr = DMDAVecGetArrayRead(u->
fda, u->
lZet, &zet); CHKERRQ(ierr);
501 PetscErrorCode cell_err = 0;
502 PetscInt be_i = -1, be_j = -1, be_k = -1;
503 const char *be_what = NULL;
505 for (PetscInt k = lzs; k < lze; k++) {
506 for (PetscInt j = lys; j < lye; j++) {
507 for (PetscInt i = lxs; i < lxe; i++) {
510 npx1, npy1, npz1, twoD);
511 if (rows == 0)
continue;
513 const PetscReal Ajc = aj[k][j][i];
514 if (!(PetscIsNormalReal(Ajc) && Ajc > 0.0)) {
515 cell_err = PETSC_ERR_FP; be_i = i; be_j = j; be_k = k;
516 be_what =
"non-finite/non-positive cell inverse-Jacobian";
522 info.gxs, info.gxs+info.gxm,
'i');
524 info.gys, info.gys+info.gym,
'j');
526 info.gzs, info.gzs+info.gzm,
'k');
529 const PetscBool bnd = (PetscBool)((npx0 && i<=1) || (npx1 && i>=mx-2) ||
530 (npy0 && j<=1) || (npy1 && j>=my-2) ||
531 (npz0 && k<=1) || (npz1 && k>=mz-2));
533 const PetscInt cls = ib ? 2 : (bnd ? 1 : 0);
536 const PetscReal Uxp = ucont[k][j][i].
x, Uxm = ucont[k][j][i-1].
x;
537 const PetscReal Uyp = ucont[k][j][i].
y, Uym = ucont[k][j-1][i].
y;
538 const PetscReal Uzp = ucont[k][j][i].
z, Uzm = ucont[k-1][j][i].
z;
539 const PetscReal divU = PetscAbsReal((Uxp-Uxm)+(Uyp-Uym)+(Uzp-Uzm));
540 const PetscReal fx = centered ? 1.0 : (mod_x ? 2.5 : (4.0/3.0));
541 const PetscReal fy = centered ? 1.0 : (mod_y ? 2.5 : (4.0/3.0));
542 const PetscReal fz = centered ? 1.0 : (mod_z ? 2.5 : (4.0/3.0));
545 const PetscReal lcB = 0.5 * Ajc * (
546 fx * (PetscAbsReal(Uxp)+PetscAbsReal(Uxm))
547 + fy * (PetscAbsReal(Uyp)+PetscAbsReal(Uym))
548 + fz * (PetscAbsReal(Uzp)+PetscAbsReal(Uzm)) );
549 const PetscReal lcC = lcB + 0.5 * Ajc * divU;
553 const Cmpnts duc = { 0.5*(ucat[k][j][i+1].
x-ucat[k][j][i-1].
x),
554 0.5*(ucat[k][j][i+1].y-ucat[k][j][i-1].y),
555 0.5*(ucat[k][j][i+1].
z-ucat[k][j][i-1].
z) };
556 const Cmpnts due = { 0.5*(ucat[k][j+1][i].
x-ucat[k][j-1][i].
x),
557 0.5*(ucat[k][j+1][i].y-ucat[k][j-1][i].y),
558 0.5*(ucat[k][j+1][i].
z-ucat[k][j-1][i].
z) };
559 const Cmpnts duz = { 0.5*(ucat[k+1][j][i].
x-ucat[k-1][j][i].
x),
560 0.5*(ucat[k+1][j][i].y-ucat[k-1][j][i].y),
561 0.5*(ucat[k+1][j][i].
z-ucat[k-1][j][i].
z) };
562 const Cmpnts C = csi[k][j][i], E = eta[k][j][i], Z = zet[k][j][i];
563 #define MOM_ROW(cmp) ( \
564 PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
565 PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
566 PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )
569 const PetscReal lcD = lcC + lgrad;
575 for (PetscInt s = 0; s < 2; s++) {
576 const PetscInt fi = (s==0) ? i : i-1;
577 if (!(PetscIsNormalReal(iaj[k][j][fi]) && iaj[k][j][fi] > 0.0)) {
578 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
579 be_what =
"non-finite/non-positive xi-face inverse-Jacobian";
goto block_cleanup; }
580 PetscReal nuf = nu_mol;
582 PetscReal nt = 0.5*(nut[k][j][fi] + nut[k][j][fi+1]);
583 if ((wxn && fi==0) || (wxp && fi==mx-2)) nt = 0.0;
586 lv += PetscAbsReal(nuf) * Ajc * iaj[k][j][fi]
587 *
MomFaceGabs(icsi[k][j][fi], ieta[k][j][fi], izet[k][j][fi]);
590 for (PetscInt s = 0; s < 2; s++) {
591 const PetscInt fj = (s==0) ? j : j-1;
592 if (!(PetscIsNormalReal(jaj[k][fj][i]) && jaj[k][fj][i] > 0.0)) {
593 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
594 be_what =
"non-finite/non-positive eta-face inverse-Jacobian";
goto block_cleanup; }
595 PetscReal nuf = nu_mol;
597 PetscReal nt = 0.5*(nut[k][fj][i] + nut[k][fj+1][i]);
598 if ((wyn && fj==0) || (wyp && fj==my-2)) nt = 0.0;
602 lv += PetscAbsReal(nuf) * Ajc * jaj[k][fj][i]
603 *
MomFaceGabs(jeta[k][fj][i], jcsi[k][fj][i], jzet[k][fj][i]);
606 for (PetscInt s = 0; s < 2; s++) {
607 const PetscInt fk = (s==0) ? k : k-1;
608 if (!(PetscIsNormalReal(kaj[fk][j][i]) && kaj[fk][j][i] > 0.0)) {
609 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
610 be_what =
"non-finite/non-positive zeta-face inverse-Jacobian";
goto block_cleanup; }
611 PetscReal nuf = nu_mol;
613 PetscReal nt = 0.5*(nut[fk][j][i] + nut[fk+1][j][i]);
614 if ((wzn && fk==0) || (wzp && fk==mz-2)) nt = 0.0;
618 lv += PetscAbsReal(nuf) * Ajc * kaj[fk][j][i]
619 *
MomFaceGabs(kzet[fk][j][i], kcsi[fk][j][i], keta[fk][j][i]);
626 PetscInt one_sided = 0;
633 const PetscReal lB = lambda_t + lcB + lv;
634 const PetscReal lC = lambda_t + lcC + lv;
635 const PetscReal lD = lambda_t + lcD + lv;
636 if (PetscIsInfOrNanReal(lD)) {
637 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
638 be_what =
"non-finite stability estimate";
goto block_cleanup;
640 locmaxB = PetscMax(locmaxB, lB);
641 locmaxC = PetscMax(locmaxC, lC);
642 locmaxD = PetscMax(locmaxD, lD);
646 if (lsel > sel_max) {
647 sel_max = lsel; sel_lc = lcsel; sel_lv = lv;
648 sel_ci = i; sel_cj = j; sel_ck = k; sel_blk = bi;
649 sel_class = cls; sel_os = one_sided;
658 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lUcont, &ucont); CHKERRQ(ierr);
659 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lAj, &aj); CHKERRQ(ierr);
660 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lIAj, &iaj); CHKERRQ(ierr);
661 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lJAj, &jaj); CHKERRQ(ierr);
662 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lKAj, &kaj); CHKERRQ(ierr);
663 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lICsi, &icsi); CHKERRQ(ierr);
664 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lIEta, &ieta); CHKERRQ(ierr);
665 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lIZet, &izet); CHKERRQ(ierr);
666 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJCsi, &jcsi); CHKERRQ(ierr);
667 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJEta, &jeta); CHKERRQ(ierr);
668 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJZet, &jzet); CHKERRQ(ierr);
669 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKCsi, &kcsi); CHKERRQ(ierr);
670 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKEta, &keta); CHKERRQ(ierr);
671 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKZet, &kzet); CHKERRQ(ierr);
672 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lNvert, &nvert); CHKERRQ(ierr);
673 if (has_nut) { ierr = DMDAVecRestoreArrayRead(u->
da, u->
lNu_t, &nut); CHKERRQ(ierr); }
674 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lUcat, &ucat); CHKERRQ(ierr);
675 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lCsi, &csi); CHKERRQ(ierr);
676 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lEta, &eta); CHKERRQ(ierr);
677 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lZet, &zet); CHKERRQ(ierr);
680 PetscCheck(cell_err == 0, PETSC_COMM_SELF, cell_err,
"%s at (%" PetscInt_FMT
681 ",%" PetscInt_FMT
",%" PetscInt_FMT
")", be_what ? be_what :
"error", be_i, be_j, be_k);
688 PetscReal loc3[3] = { locmaxB, locmaxC, locmaxD }, glo3[3];
689 ierr = MPI_Allreduce(loc3, glo3, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
691 PetscInt global_active = 0;
692 ierr = MPI_Allreduce(&local_active, &global_active, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
696 const PetscReal sel_global = glo3[(int)candidate];
697 PetscMPIInt nproc, claim, owner;
698 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &nproc); CHKERRQ(ierr);
699 claim = (sel_max == sel_global) ? rank : nproc;
700 ierr = MPI_Allreduce(&claim, &owner, 1, MPI_INT, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
701 if (owner == nproc) owner = 0;
703 PetscReal dbuf[2] = { sel_lc, sel_lv };
704 PetscInt ibuf[6] = { sel_ci, sel_cj, sel_ck, sel_blk, sel_class, sel_os };
705 ierr = MPI_Bcast(dbuf, 2, MPIU_REAL, owner, PETSC_COMM_WORLD); CHKERRQ(ierr);
706 ierr = MPI_Bcast(ibuf, 6, MPIU_INT, owner, PETSC_COMM_WORLD); CHKERRQ(ierr);
713 rep->
ci = ibuf[0]; rep->
cj = ibuf[1]; rep->
ck = ibuf[2];
719 if (global_active == 0) {
722 PetscCheck(PetscIsNormalReal(rep->
lambda) && rep->
lambda > 0.0, PETSC_COMM_WORLD, PETSC_ERR_FP,
723 "momentum stability estimate is non-finite or non-positive with %" PetscInt_FMT
724 " active cells", global_active);
732 PetscFunctionReturn(0);
751 const PetscInt ti = simCtx->
step;
752 const PetscReal dt = simCtx->
dt;
756 const PetscReal alfa[] = {0.25, 1.0/3.0, 0.5, 1.0};
760 PetscBool force_restart = PETSC_FALSE;
764 const PetscReal tol_abs_delta = simCtx->
mom_atol;
765 const PetscReal tol_rtol_delta = simCtx->
mom_rtol;
770 PetscInt istage, pseudo_iter;
771 PetscInt accepted_iter = 0, rejected_iter = 0, recovery_streak = 0;
772 PetscReal ts, te, cput;
775 PetscReal global_norm_delta = 10.0;
776 PetscReal global_rel_delta = 1.0;
777 PetscReal global_norm_resid = 1.0;
778 PetscReal global_rel_resid = 1.0;
779 PetscReal smoothed_trial_ratio = 1.0;
788 PetscReal lambda_max = 0.0;
789 PetscReal dtau_min, dtau_max;
792 PetscReal *delta_sol_norm_init, *delta_sol_norm_prev, *delta_sol_norm_curr, *delta_sol_rel_curr;
793 PetscReal *resid_norm_init, *resid_norm_prev, *resid_norm_curr, *resid_rel_curr;
794 PetscReal *pseudo_dtau;
795 PetscReal *trial_ratio_log;
796 PetscReal last_accepted_resid;
798 PetscFunctionBeginUser;
800 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
804 ierr = PetscMalloc2(block_number, &delta_sol_norm_init, block_number, &delta_sol_norm_prev); CHKERRQ(ierr);
805 ierr = PetscMalloc2(block_number, &delta_sol_norm_curr, block_number, &delta_sol_rel_curr); CHKERRQ(ierr);
806 ierr = PetscMalloc2(block_number, &resid_norm_init, block_number, &resid_norm_prev); CHKERRQ(ierr);
807 ierr = PetscMalloc2(block_number, &resid_norm_curr, block_number, &pseudo_dtau); CHKERRQ(ierr);
808 ierr = PetscMalloc1(block_number, &resid_rel_curr); CHKERRQ(ierr);
809 ierr = PetscMalloc1(block_number, &trial_ratio_log); CHKERRQ(ierr);
810 ierr = PetscMalloc1(block_number, &pRhs); CHKERRQ(ierr);
811 last_accepted_resid = 0.0;
813 ierr = PetscTime(&ts); CHKERRQ(ierr);
817 if (block_number > 1) {
821 for (PetscInt bi = 0; bi < block_number; bi++) {
827 ierr = VecDuplicate(user[bi].Ucont, &user[bi].Rhs); CHKERRQ(ierr);
828 ierr = VecDuplicate(user[bi].Rhs, &pRhs[bi]); CHKERRQ(ierr);
829 ierr = VecDuplicate(user[bi].Ucont, &user[bi].dUcont); CHKERRQ(ierr);
830 ierr = VecDuplicate(user[bi].Ucont, &user[bi].pUcont); CHKERRQ(ierr);
833 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
839 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
842 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_init[bi]); CHKERRQ(ierr);
845 resid_norm_prev[bi] = resid_norm_init[bi];
846 delta_sol_norm_prev[bi] = 1000.0;
849 LOG_ALLOW(
GLOBAL,
LOG_INFO,
" Block %d | Max RHS = %.6f | initial pseudo-CFL = %.4f .\n", bi, resid_norm_init[bi], cfl);
866 for (PetscInt bi = 0; bi < block_number; bi++) {
867 pseudo_dtau[bi] = cfl / lambda_max;
875 PetscBool shadow = PETSC_FALSE;
876 ierr = PetscOptionsGetBool(NULL, NULL,
"-mom_stability_shadow", &shadow, NULL); CHKERRQ(ierr);
885 "Momentum scale [shadow]: legacy_dtau=%.4e new_dtau=%.4e ratio=%.4f limiter=%s | "
886 "lambda_legacy=%.4e lambda_new=%.4e (B=%.4e C=%.4e D=%.4e) | "
887 "lt=%.4e lc=%.4e lv=%.4e | cell=(%d,%d,%d) blk=%d class=%d onesided=%d\n",
888 cfl / lambda_max, cfl / rep.
lambda, rep.
lambda / lambda_max, lim,
896 "Dual-time solver: lambda_max=%.4e [1/s] dtau_init=%.4e dtau range [%.4e, %.4e] "
897 "CFL range [%.4f, %.4f] rejection_threshold=%.3f (EMA alpha=%.2f) "
898 "growth=%.3f reduction=%.3f max_accepted=%d.\n",
899 lambda_max, cfl / lambda_max, dtau_min, dtau_max,
908 PetscBool residual_convergence_enabled =
910 PetscBool converged = PETSC_FALSE;
911 PetscBool last_trial_nonfinite = PETSC_FALSE;
914 const PetscInt max_total_attempts = max_pseudo_steps * 3;
915 while (!converged && accepted_iter < max_pseudo_steps && pseudo_iter < max_total_attempts)
918 force_restart = PETSC_FALSE;
921 for (PetscInt bi = 0; bi < block_number; bi++) {
922 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
923 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
924 const char *staggered_fields[] = {
"Ucont"};
929 for (PetscInt bi = 0; bi < block_number; bi++) {
932 for (istage = 0; istage < 4; istage++) {
939 ierr = VecWAXPY(user[bi].Ucont,
940 pseudo_dtau[bi] * alfa[istage],
942 user[bi].pUcont); CHKERRQ(ierr);
945 const char *staggered_fields[] = {
"Ucont"};
960 ierr = VecWAXPY(user[bi].dUcont, -1.0, user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
963 ierr = VecNorm(user[bi].dUcont, NORM_INFINITY, &delta_sol_norm_curr[bi]); CHKERRQ(ierr);
964 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_curr[bi]); CHKERRQ(ierr);
967 if (pseudo_iter == 1) {
968 delta_sol_norm_init[bi] = delta_sol_norm_curr[bi];
969 delta_sol_rel_curr[bi] = 1.0;
970 resid_rel_curr[bi] = 1.0;
973 if (delta_sol_norm_init[bi] > 1.0e-10)
974 delta_sol_rel_curr[bi] = delta_sol_norm_curr[bi] / delta_sol_norm_init[bi];
976 delta_sol_rel_curr[bi] = 0.0;
978 if(resid_norm_init[bi] > 1.0e-10)
979 resid_rel_curr[bi] = resid_norm_curr[bi] / resid_norm_init[bi];
981 resid_rel_curr[bi] = 0.0;
986 const PetscReal resid_floor_log = 1.0e-30;
987 if (resid_norm_prev[bi] > resid_floor_log)
988 trial_ratio_log[bi] = resid_norm_curr[bi] / resid_norm_prev[bi];
989 else if (resid_norm_curr[bi] <= resid_floor_log)
990 trial_ratio_log[bi] = 0.0;
992 trial_ratio_log[bi] = PETSC_MAX_REAL;
997 global_norm_delta = -1.0e20;
998 global_rel_delta = -1.0e20;
999 global_norm_resid = -1.0e20;
1000 global_rel_resid = -1.0e20;
1002 for (PetscInt bi = 0; bi < block_number; bi++) {
1003 global_norm_delta = PetscMax(delta_sol_norm_curr[bi], global_norm_delta);
1004 global_rel_delta = PetscMax(delta_sol_rel_curr[bi], global_rel_delta);
1005 global_norm_resid = PetscMax(resid_norm_curr[bi], global_norm_resid);
1006 global_rel_resid = PetscMax(resid_rel_curr[bi], global_rel_resid);
1008 ierr = PetscTime(&te); CHKERRQ(ierr);
1011 pseudo_iter, global_norm_delta, global_rel_delta, global_rel_resid, cput);
1014 const PetscReal resid_floor = 1.0e-30;
1015 PetscReal global_trial_ratio = 0.0;
1016 PetscBool global_nonfinite = PETSC_FALSE;
1017 for (PetscInt bi = 0; bi < block_number; bi++) {
1019 if (resid_norm_prev[bi] > resid_floor) {
1020 ratio = resid_norm_curr[bi] / resid_norm_prev[bi];
1021 }
else if (resid_norm_curr[bi] <= resid_floor) {
1024 ratio = PETSC_MAX_REAL;
1026 global_trial_ratio = PetscMax(global_trial_ratio, ratio);
1027 global_nonfinite = (PetscBool)(global_nonfinite ||
1028 PetscIsInfOrNanReal(delta_sol_norm_curr[bi]) ||
1029 PetscIsInfOrNanReal(resid_norm_curr[bi]) ||
1030 PetscIsInfOrNanReal(ratio));
1033 PetscReal reduced_trial_ratio;
1034 PetscMPIInt local_nonfinite = global_nonfinite ? 1 : 0;
1035 PetscMPIInt reduced_nonfinite = 0;
1036 ierr = MPI_Allreduce(&global_trial_ratio, &reduced_trial_ratio, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
1037 ierr = MPI_Allreduce(&local_nonfinite, &reduced_nonfinite, 1, MPI_INT, MPI_LOR, PETSC_COMM_WORLD); CHKERRQ(ierr);
1038 global_trial_ratio = reduced_trial_ratio;
1039 global_nonfinite = reduced_nonfinite ? PETSC_TRUE : PETSC_FALSE;
1040 last_trial_nonfinite = global_nonfinite;
1044 if (!global_nonfinite) {
1049 " [k=%d] raw_ratio=%.4e smoothed_ratio=%.4e (threshold=%.3f) | "
1050 "|R_prev|=%.6e | |R_curr|=%.6e | CFL=%.6f\n",
1051 pseudo_iter, global_trial_ratio, smoothed_trial_ratio,
1053 resid_norm_prev[0], resid_norm_curr[0], pseudo_dtau[0]);
1057 force_restart = global_nonfinite;
1059 force_restart = (PetscBool)(global_nonfinite ||
1063 if (force_restart) {
1067 PetscReal old_dtau = pseudo_dtau[0];
1070 recovery_streak = 0;
1071 for (PetscInt bi = 0; bi < block_number; bi++) {
1072 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1073 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
1074 const char *staggered_fields[] = {
"Ucont"};
1077 pseudo_dtau[bi] = next_dtau;
1080 " Trial %d REJECTED (raw_ratio=%.4e, smoothed=%.4e, nonfinite=%d); "
1081 "dtau %.4e -> %.4e (cfl_eff %.4f -> %.4f)%s\n",
1082 pseudo_iter, global_trial_ratio, smoothed_trial_ratio, (
int)global_nonfinite,
1083 old_dtau, next_dtau, old_dtau * lambda_max, next_dtau * lambda_max,
1084 (old_dtau == next_dtau) ?
" [AT FLOOR — no dtau reduction]" :
"");
1087 for (PetscInt bi = 0; bi < block_number; bi++) {
1089 char filen[PETSC_MAX_PATH_LEN + 128];
1090 ierr = PetscSNPrintf(filen,
sizeof(filen),
1091 "%s/Momentum_Solver_DualTime_Picard_Jameson_RK_History_Block_%1d.log",
1092 simCtx->
log_dir, bi); CHKERRQ(ierr);
1094 f = fopen(filen,
"w");
1096 f = fopen(filen,
"a");
1098 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1100 PetscFPrintf(PETSC_COMM_WORLD, f,
1101 "Step: %d | PseudoIter(k): %d | dtau: %.6e | cfl_eff: %.4f | |dUk|: %le | "
1102 "|dUk|/|dU0|: %le | |Rk|: %le | |Rk|/|R0|: %le | "
1103 "trial_ratio: %le | smoothed_ratio: %le | status: rejected | "
1104 "dtau_after: %.6e | cfl_eff_after: %.4f\n",
1105 (
int)ti, (
int)pseudo_iter, old_dtau, old_dtau * lambda_max,
1106 delta_sol_norm_curr[bi], delta_sol_rel_curr[bi],
1107 resid_norm_curr[bi], resid_rel_curr[bi],
1108 trial_ratio_log[bi], smoothed_trial_ratio,
1109 next_dtau, next_dtau * lambda_max);
1113 if (old_dtau <= dtau_min) {
1114 if (global_nonfinite) {
1115 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
1116 "Momentum solver produced a non-finite trial at minimum pseudo-CFL.");
1121 " Trial %d REJECTED (ratio=%.4e) at minimum dtau (%.4e, cfl_eff=%.4f) "
1122 "with no further reduction possible; breaking retry loop.\n",
1123 pseudo_iter, global_trial_ratio, old_dtau, old_dtau * lambda_max);
1130 last_trial_nonfinite = PETSC_FALSE;
1131 last_accepted_resid = resid_norm_curr[0];
1132 for (PetscInt bi = 0; bi < block_number; bi++) {
1133 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
1134 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
1135 resid_norm_prev[bi] = resid_norm_curr[bi];
1136 delta_sol_norm_prev[bi] = delta_sol_norm_curr[bi];
1142 PetscReal old_dtau = pseudo_dtau[0];
1143 PetscReal next_dtau = old_dtau;
1144 if (global_trial_ratio < 0.90) {
1147 recovery_streak = 0;
1148 }
else if (global_trial_ratio <= 1.0) {
1151 if (recovery_streak >= 3) {
1153 recovery_streak = 0;
1158 recovery_streak = 0;
1160 next_dtau = PetscMin(next_dtau, dtau_max);
1161 next_dtau = PetscMax(next_dtau, dtau_min);
1162 for (PetscInt bi = 0; bi < block_number; bi++) pseudo_dtau[bi] = next_dtau;
1165 " Trial %d ACCEPTED (raw_ratio=%.4e, smoothed=%.4e); |dU|=%.6e | "
1166 "dtau %.4e -> %.4e (cfl_eff %.4f -> %.4f)\n",
1167 pseudo_iter, global_trial_ratio, smoothed_trial_ratio, global_norm_delta,
1168 old_dtau, next_dtau, old_dtau * lambda_max, next_dtau * lambda_max);
1172 for (PetscInt bi = 0; bi < block_number; bi++) {
1174 char filen[PETSC_MAX_PATH_LEN + 128];
1175 ierr = PetscSNPrintf(filen,
sizeof(filen),
1176 "%s/Momentum_Solver_DualTime_Picard_Jameson_RK_History_Block_%1d.log",
1177 simCtx->
log_dir, bi); CHKERRQ(ierr);
1179 f = fopen(filen,
"w");
1181 f = fopen(filen,
"a");
1183 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1185 PetscFPrintf(PETSC_COMM_WORLD, f,
1186 "Step: %d | PseudoIter(k): %d | dtau: %.6e | cfl_eff: %.4f | |dUk|: %le | "
1187 "|dUk|/|dU0|: %le | |Rk|: %le | |Rk|/|R0|: %le | "
1188 "trial_ratio: %le | smoothed_ratio: %le | status: accepted | "
1189 "dtau_after: %.6e | cfl_eff_after: %.4f\n",
1190 (
int)ti, (
int)pseudo_iter, old_dtau, old_dtau * lambda_max,
1191 delta_sol_norm_curr[bi], delta_sol_rel_curr[bi],
1192 resid_norm_curr[bi], resid_rel_curr[bi],
1193 trial_ratio_log[bi], smoothed_trial_ratio,
1194 next_dtau, next_dtau * lambda_max);
1199 PetscBool update_pass;
1200 PetscBool residual_pass = PETSC_TRUE;
1201 if (residual_convergence_enabled) {
1202 update_pass = (PetscBool)(global_norm_delta <= tol_abs_delta && global_rel_delta <= tol_rtol_delta);
1203 residual_pass = (PetscBool)(
1204 (simCtx->
mom_resid_atol > 0.0 && global_norm_resid <= simCtx->mom_resid_atol) ||
1207 update_pass = (PetscBool)(global_norm_delta <= tol_abs_delta && global_rel_delta <= tol_rtol_delta);
1209 converged = (PetscBool)(update_pass && residual_pass);
1211 if (block_number > 1) {
1216 if (last_trial_nonfinite) {
1217 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
1218 "Momentum solver exhausted its attempt limit while recovering from a non-finite trial.");
1225 PetscReal next_dtau_start = pseudo_dtau[0];
1226 PetscReal next_cfl_warmstart = next_dtau_start * lambda_max;
1230 " Step %d finished: dtau=%.4e cfl_eff=%.4f lambda_max=%.4e [1/s]. "
1231 "Next step warm-starts at cfl=%.4f.\n",
1232 simCtx->
step, next_dtau_start, next_cfl_warmstart, lambda_max, next_cfl_warmstart);
1242 if (accepted_iter == 0) {
1243 for (PetscInt bi = 0; bi < block_number; bi++) {
1244 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1245 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
1248 for (PetscInt bi = 0; bi < block_number; bi++) {
1249 const char *staggered_fields[] = {
"Ucont"};
1256 PetscPrintf(PETSC_COMM_WORLD,
1257 "[WARNING] Momentum solver step %d: reached %d total attempts (%d accepted, %d rejected) "
1258 "without convergence; continuing from last accepted finite state.\n",
1259 (
int)ti, pseudo_iter, accepted_iter, rejected_iter);
1261 if (accepted_iter == 0) {
1262 PetscPrintf(PETSC_COMM_WORLD,
1263 "[WARNING] Momentum solver step %d: no pseudo-time trials were accepted; "
1264 "retaining physical-step entry state.\n", (
int)ti);
1267 "Momentum solver finished: %d attempts (%d accepted, %d rejected) of %d max accepted / %d hard cap, "
1268 "converged=%s, last accepted |R|=%.6e, last accepted |dU|=%.6e, "
1269 "next_dtau=%.4e (cfl=%.4f).\n",
1270 pseudo_iter, accepted_iter, rejected_iter, max_pseudo_steps, max_total_attempts,
1271 converged ?
"yes" :
"no",
1272 (accepted_iter > 0) ? last_accepted_resid : resid_norm_init[0],
1273 (accepted_iter > 0) ? delta_sol_norm_prev[0] : 0.0,
1274 next_dtau_start, next_cfl_warmstart);
1277 for (PetscInt bi = 0; bi < block_number; bi++) {
1278 ierr = VecDestroy(&user[bi].Rhs); CHKERRQ(ierr);
1279 ierr = VecDestroy(&user[bi].dUcont); CHKERRQ(ierr);
1280 ierr = VecDestroy(&user[bi].pUcont); CHKERRQ(ierr);
1281 ierr = VecDestroy(&pRhs[bi]); CHKERRQ(ierr);
1283 ierr = PetscFree(pRhs); CHKERRQ(ierr);
1285 ierr = PetscFree2(delta_sol_norm_init, delta_sol_norm_prev);CHKERRQ(ierr);
1286 ierr = PetscFree2(delta_sol_norm_curr, delta_sol_rel_curr);CHKERRQ(ierr);
1287 ierr = PetscFree2(resid_norm_init, resid_norm_prev);CHKERRQ(ierr);
1288 ierr = PetscFree2(resid_norm_curr, pseudo_dtau); CHKERRQ(ierr);
1289 ierr = PetscFree(resid_rel_curr); CHKERRQ(ierr);
1290 ierr = PetscFree(trial_ratio_log); CHKERRQ(ierr);
1293 PetscFunctionReturn(0);