408 PetscFunctionBeginUser;
411 PetscCheck(user != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL,
"user is NULL");
412 PetscCheck(rep != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_NULL,
"rep is NULL");
413 PetscCheck(block_number > 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"block_number must be > 0");
415 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"unsupported stability candidate enum");
416 PetscCheck(PetscIsNormalReal(dt) && dt > 0.0, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
417 "dt must be finite and positive");
420 PetscCheck(simCtx != NULL, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
"user[0].simCtx is NULL");
422 const PetscBool centered = (PetscBool)(simCtx->
les || simCtx->
central);
423 const PetscBool has_nut = (PetscBool)(simCtx->
les || simCtx->
rans);
424 const PetscBool inviscid = (PetscBool)simCtx->
invicid;
425 PetscCheck(inviscid || (PetscIsNormalReal(simCtx->
ren) && simCtx->
ren > 0.0),
426 PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE,
"Reynolds number must be finite and positive when viscous");
427 const PetscReal lambda_t = a0 / dt;
428 const PetscReal nu_mol = inviscid ? 0.0 : 1.0 / simCtx->
ren;
429 const PetscInt twoD = simCtx->
TwoD;
439 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
442 PetscReal locmaxB = 0.0, locmaxC = 0.0, locmaxD = 0.0, sel_max = 0.0;
443 PetscReal sel_lc = 0.0, sel_lv = 0.0;
444 PetscInt sel_ci = -1, sel_cj = -1, sel_ck = -1, sel_blk = -1, sel_class = 0, sel_os = 0;
445 PetscInt local_active = 0;
447 for (PetscInt bi = 0; bi < block_number; bi++) {
449 DMDALocalInfo info = u->
info;
450 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
451 const PetscInt xs = info.xs, xe = xs + info.xm;
452 const PetscInt ys = info.ys, ye = ys + info.ym;
453 const PetscInt zs = info.zs, ze = zs + info.zm;
458 const PetscInt lxs = (xs==0)?xs+1:xs, lxe = (xe==mx)?xe-1:xe;
459 const PetscInt lys = (ys==0)?ys+1:ys, lye = (ye==my)?ye-1:ye;
460 const PetscInt lzs = (zs==0)?zs+1:zs, lze = (ze==mz)?ze-1:ze;
476 Cmpnts ***ucont, ***ucat = NULL;
477 Cmpnts ***icsi, ***ieta, ***izet, ***jcsi, ***jeta, ***jzet, ***kcsi, ***keta, ***kzet;
478 Cmpnts ***csi = NULL, ***eta = NULL, ***zet = NULL;
479 PetscReal ***aj, ***iaj, ***jaj, ***kaj, ***nvert, ***nut = NULL;
481 ierr = DMDAVecGetArrayRead(u->
fda, u->
lUcont, &ucont); CHKERRQ(ierr);
482 ierr = DMDAVecGetArrayRead(u->
da, u->
lAj, &aj); CHKERRQ(ierr);
483 ierr = DMDAVecGetArrayRead(u->
da, u->
lIAj, &iaj); CHKERRQ(ierr);
484 ierr = DMDAVecGetArrayRead(u->
da, u->
lJAj, &jaj); CHKERRQ(ierr);
485 ierr = DMDAVecGetArrayRead(u->
da, u->
lKAj, &kaj); CHKERRQ(ierr);
486 ierr = DMDAVecGetArrayRead(u->
fda, u->
lICsi, &icsi); CHKERRQ(ierr);
487 ierr = DMDAVecGetArrayRead(u->
fda, u->
lIEta, &ieta); CHKERRQ(ierr);
488 ierr = DMDAVecGetArrayRead(u->
fda, u->
lIZet, &izet); CHKERRQ(ierr);
489 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJCsi, &jcsi); CHKERRQ(ierr);
490 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJEta, &jeta); CHKERRQ(ierr);
491 ierr = DMDAVecGetArrayRead(u->
fda, u->
lJZet, &jzet); CHKERRQ(ierr);
492 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKCsi, &kcsi); CHKERRQ(ierr);
493 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKEta, &keta); CHKERRQ(ierr);
494 ierr = DMDAVecGetArrayRead(u->
fda, u->
lKZet, &kzet); CHKERRQ(ierr);
495 ierr = DMDAVecGetArrayRead(u->
da, u->
lNvert, &nvert); CHKERRQ(ierr);
496 if (has_nut) { ierr = DMDAVecGetArrayRead(u->
da, u->
lNu_t, &nut); CHKERRQ(ierr); }
500 ierr = DMDAVecGetArrayRead(u->
fda, u->
lUcat, &ucat); CHKERRQ(ierr);
501 ierr = DMDAVecGetArrayRead(u->
fda, u->
lCsi, &csi); CHKERRQ(ierr);
502 ierr = DMDAVecGetArrayRead(u->
fda, u->
lEta, &eta); CHKERRQ(ierr);
503 ierr = DMDAVecGetArrayRead(u->
fda, u->
lZet, &zet); CHKERRQ(ierr);
507 PetscErrorCode cell_err = 0;
508 PetscInt be_i = -1, be_j = -1, be_k = -1;
509 const char *be_what = NULL;
511 for (PetscInt k = lzs; k < lze; k++) {
512 for (PetscInt j = lys; j < lye; j++) {
513 for (PetscInt i = lxs; i < lxe; i++) {
516 npx1, npy1, npz1, twoD);
517 if (rows == 0)
continue;
519 const PetscReal Ajc = aj[k][j][i];
520 if (!(PetscIsNormalReal(Ajc) && Ajc > 0.0)) {
521 cell_err = PETSC_ERR_FP; be_i = i; be_j = j; be_k = k;
522 be_what =
"non-finite/non-positive cell inverse-Jacobian";
528 info.gxs, info.gxs+info.gxm,
'i');
530 info.gys, info.gys+info.gym,
'j');
532 info.gzs, info.gzs+info.gzm,
'k');
535 const PetscBool bnd = (PetscBool)((npx0 && i<=1) || (npx1 && i>=mx-2) ||
536 (npy0 && j<=1) || (npy1 && j>=my-2) ||
537 (npz0 && k<=1) || (npz1 && k>=mz-2));
539 const PetscInt cls = ib ? 2 : (bnd ? 1 : 0);
542 const PetscReal Uxp = ucont[k][j][i].
x, Uxm = ucont[k][j][i-1].
x;
543 const PetscReal Uyp = ucont[k][j][i].
y, Uym = ucont[k][j-1][i].
y;
544 const PetscReal Uzp = ucont[k][j][i].
z, Uzm = ucont[k-1][j][i].
z;
545 const PetscReal divU = PetscAbsReal((Uxp-Uxm)+(Uyp-Uym)+(Uzp-Uzm));
546 const PetscReal fx = centered ? 1.0 : (mod_x ? 2.5 : (4.0/3.0));
547 const PetscReal fy = centered ? 1.0 : (mod_y ? 2.5 : (4.0/3.0));
548 const PetscReal fz = centered ? 1.0 : (mod_z ? 2.5 : (4.0/3.0));
551 const PetscReal lcB = 0.5 * Ajc * (
552 fx * (PetscAbsReal(Uxp)+PetscAbsReal(Uxm))
553 + fy * (PetscAbsReal(Uyp)+PetscAbsReal(Uym))
554 + fz * (PetscAbsReal(Uzp)+PetscAbsReal(Uzm)) );
555 const PetscReal lcC = lcB + 0.5 * Ajc * divU;
559 const Cmpnts duc = { 0.5*(ucat[k][j][i+1].
x-ucat[k][j][i-1].
x),
560 0.5*(ucat[k][j][i+1].y-ucat[k][j][i-1].y),
561 0.5*(ucat[k][j][i+1].
z-ucat[k][j][i-1].
z) };
562 const Cmpnts due = { 0.5*(ucat[k][j+1][i].
x-ucat[k][j-1][i].
x),
563 0.5*(ucat[k][j+1][i].y-ucat[k][j-1][i].y),
564 0.5*(ucat[k][j+1][i].
z-ucat[k][j-1][i].
z) };
565 const Cmpnts duz = { 0.5*(ucat[k+1][j][i].
x-ucat[k-1][j][i].
x),
566 0.5*(ucat[k+1][j][i].y-ucat[k-1][j][i].y),
567 0.5*(ucat[k+1][j][i].
z-ucat[k-1][j][i].
z) };
568 const Cmpnts C = csi[k][j][i], E = eta[k][j][i], Z = zet[k][j][i];
569 #define MOM_ROW(cmp) ( \
570 PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
571 PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
572 PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )
575 const PetscReal lcD = lcC + lgrad;
581 for (PetscInt s = 0; s < 2; s++) {
582 const PetscInt fi = (s==0) ? i : i-1;
583 if (!(PetscIsNormalReal(iaj[k][j][fi]) && iaj[k][j][fi] > 0.0)) {
584 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
585 be_what =
"non-finite/non-positive xi-face inverse-Jacobian";
goto block_cleanup; }
586 PetscReal nuf = nu_mol;
588 PetscReal nt = 0.5*(nut[k][j][fi] + nut[k][j][fi+1]);
589 if ((wxn && fi==0) || (wxp && fi==mx-2)) nt = 0.0;
592 lv += PetscAbsReal(nuf) * Ajc * iaj[k][j][fi]
593 *
MomFaceGabs(icsi[k][j][fi], ieta[k][j][fi], izet[k][j][fi]);
596 for (PetscInt s = 0; s < 2; s++) {
597 const PetscInt fj = (s==0) ? j : j-1;
598 if (!(PetscIsNormalReal(jaj[k][fj][i]) && jaj[k][fj][i] > 0.0)) {
599 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
600 be_what =
"non-finite/non-positive eta-face inverse-Jacobian";
goto block_cleanup; }
601 PetscReal nuf = nu_mol;
603 PetscReal nt = 0.5*(nut[k][fj][i] + nut[k][fj+1][i]);
604 if ((wyn && fj==0) || (wyp && fj==my-2)) nt = 0.0;
608 lv += PetscAbsReal(nuf) * Ajc * jaj[k][fj][i]
609 *
MomFaceGabs(jeta[k][fj][i], jcsi[k][fj][i], jzet[k][fj][i]);
612 for (PetscInt s = 0; s < 2; s++) {
613 const PetscInt fk = (s==0) ? k : k-1;
614 if (!(PetscIsNormalReal(kaj[fk][j][i]) && kaj[fk][j][i] > 0.0)) {
615 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
616 be_what =
"non-finite/non-positive zeta-face inverse-Jacobian";
goto block_cleanup; }
617 PetscReal nuf = nu_mol;
619 PetscReal nt = 0.5*(nut[fk][j][i] + nut[fk+1][j][i]);
620 if ((wzn && fk==0) || (wzp && fk==mz-2)) nt = 0.0;
624 lv += PetscAbsReal(nuf) * Ajc * kaj[fk][j][i]
625 *
MomFaceGabs(kzet[fk][j][i], kcsi[fk][j][i], keta[fk][j][i]);
632 PetscInt one_sided = 0;
639 const PetscReal lB = lambda_t + lcB + lv;
640 const PetscReal lC = lambda_t + lcC + lv;
641 const PetscReal lD = lambda_t + lcD + lv;
642 if (PetscIsInfOrNanReal(lD)) {
643 cell_err = PETSC_ERR_FP; be_i=i; be_j=j; be_k=k;
644 be_what =
"non-finite stability estimate";
goto block_cleanup;
646 locmaxB = PetscMax(locmaxB, lB);
647 locmaxC = PetscMax(locmaxC, lC);
648 locmaxD = PetscMax(locmaxD, lD);
652 if (lsel > sel_max) {
653 sel_max = lsel; sel_lc = lcsel; sel_lv = lv;
654 sel_ci = i; sel_cj = j; sel_ck = k; sel_blk = bi;
655 sel_class = cls; sel_os = one_sided;
664 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lUcont, &ucont); CHKERRQ(ierr);
665 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lAj, &aj); CHKERRQ(ierr);
666 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lIAj, &iaj); CHKERRQ(ierr);
667 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lJAj, &jaj); CHKERRQ(ierr);
668 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lKAj, &kaj); CHKERRQ(ierr);
669 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lICsi, &icsi); CHKERRQ(ierr);
670 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lIEta, &ieta); CHKERRQ(ierr);
671 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lIZet, &izet); CHKERRQ(ierr);
672 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJCsi, &jcsi); CHKERRQ(ierr);
673 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJEta, &jeta); CHKERRQ(ierr);
674 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lJZet, &jzet); CHKERRQ(ierr);
675 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKCsi, &kcsi); CHKERRQ(ierr);
676 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKEta, &keta); CHKERRQ(ierr);
677 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lKZet, &kzet); CHKERRQ(ierr);
678 ierr = DMDAVecRestoreArrayRead(u->
da, u->
lNvert, &nvert); CHKERRQ(ierr);
679 if (has_nut) { ierr = DMDAVecRestoreArrayRead(u->
da, u->
lNu_t, &nut); CHKERRQ(ierr); }
680 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lUcat, &ucat); CHKERRQ(ierr);
681 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lCsi, &csi); CHKERRQ(ierr);
682 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lEta, &eta); CHKERRQ(ierr);
683 ierr = DMDAVecRestoreArrayRead(u->
fda, u->
lZet, &zet); CHKERRQ(ierr);
686 PetscCheck(cell_err == 0, PETSC_COMM_SELF, cell_err,
"%s at (%" PetscInt_FMT
687 ",%" PetscInt_FMT
",%" PetscInt_FMT
")", be_what ? be_what :
"error", be_i, be_j, be_k);
694 PetscReal loc3[3] = { locmaxB, locmaxC, locmaxD }, glo3[3];
695 ierr = MPI_Allreduce(loc3, glo3, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
697 PetscInt global_active = 0;
698 ierr = MPI_Allreduce(&local_active, &global_active, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
702 const PetscReal sel_global = glo3[(int)candidate];
703 PetscMPIInt nproc, claim, owner;
704 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &nproc); CHKERRQ(ierr);
705 claim = (sel_max == sel_global) ? rank : nproc;
706 ierr = MPI_Allreduce(&claim, &owner, 1, MPI_INT, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
707 if (owner == nproc) owner = 0;
709 PetscReal dbuf[2] = { sel_lc, sel_lv };
710 PetscInt ibuf[6] = { sel_ci, sel_cj, sel_ck, sel_blk, sel_class, sel_os };
711 ierr = MPI_Bcast(dbuf, 2, MPIU_REAL, owner, PETSC_COMM_WORLD); CHKERRQ(ierr);
712 ierr = MPI_Bcast(ibuf, 6, MPIU_INT, owner, PETSC_COMM_WORLD); CHKERRQ(ierr);
719 rep->
ci = ibuf[0]; rep->
cj = ibuf[1]; rep->
ck = ibuf[2];
725 if (global_active == 0) {
728 PetscCheck(PetscIsNormalReal(rep->
lambda) && rep->
lambda > 0.0, PETSC_COMM_WORLD, PETSC_ERR_FP,
729 "momentum stability estimate is non-finite or non-positive with %" PetscInt_FMT
730 " active cells", global_active);
738 PetscFunctionReturn(0);
757 const PetscInt ti = simCtx->
step;
758 const PetscReal dt = simCtx->
dt;
762 const PetscReal alfa[] = {0.25, 1.0/3.0, 0.5, 1.0};
766 PetscBool force_restart = PETSC_FALSE;
770 const PetscReal tol_abs_delta = simCtx->
mom_atol;
771 const PetscReal tol_rtol_delta = simCtx->
mom_rtol;
776 PetscInt istage, pseudo_iter;
777 PetscInt accepted_iter = 0, rejected_iter = 0, recovery_streak = 0;
778 PetscReal ts, te, cput;
781 PetscReal global_norm_delta = 10.0;
782 PetscReal global_rel_delta = 1.0;
783 PetscReal global_norm_resid = 1.0;
784 PetscReal global_rel_resid = 1.0;
785 PetscReal smoothed_trial_ratio = 1.0;
794 PetscReal lambda_max = 0.0;
804 PetscReal resid_ref = 0.0;
805 PetscReal dtau_min, dtau_max;
808 PetscReal *delta_sol_norm_init, *delta_sol_norm_prev, *delta_sol_norm_curr, *delta_sol_rel_curr;
809 PetscReal *resid_norm_init, *resid_norm_prev, *resid_norm_curr, *resid_rel_curr;
810 PetscReal *pseudo_dtau;
811 PetscReal *trial_ratio_log;
812 PetscReal last_accepted_resid;
814 PetscFunctionBeginUser;
816 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
820 ierr = PetscMalloc2(block_number, &delta_sol_norm_init, block_number, &delta_sol_norm_prev); CHKERRQ(ierr);
821 ierr = PetscMalloc2(block_number, &delta_sol_norm_curr, block_number, &delta_sol_rel_curr); CHKERRQ(ierr);
822 ierr = PetscMalloc2(block_number, &resid_norm_init, block_number, &resid_norm_prev); CHKERRQ(ierr);
823 ierr = PetscMalloc2(block_number, &resid_norm_curr, block_number, &pseudo_dtau); CHKERRQ(ierr);
824 ierr = PetscMalloc1(block_number, &resid_rel_curr); CHKERRQ(ierr);
825 ierr = PetscMalloc1(block_number, &trial_ratio_log); CHKERRQ(ierr);
826 ierr = PetscMalloc1(block_number, &pRhs); CHKERRQ(ierr);
827 last_accepted_resid = 0.0;
829 ierr = PetscTime(&ts); CHKERRQ(ierr);
833 if (block_number > 1) {
837 for (PetscInt bi = 0; bi < block_number; bi++) {
843 ierr = VecDuplicate(user[bi].Ucont, &user[bi].Rhs); CHKERRQ(ierr);
844 ierr = VecDuplicate(user[bi].Rhs, &pRhs[bi]); CHKERRQ(ierr);
845 ierr = VecDuplicate(user[bi].Ucont, &user[bi].dUcont); CHKERRQ(ierr);
846 ierr = VecDuplicate(user[bi].Ucont, &user[bi].pUcont); CHKERRQ(ierr);
849 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
855 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
858 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_init[bi]); CHKERRQ(ierr);
864 ierr = VecNorm(user[bi].Ucont, NORM_INFINITY, &ucont_inf); CHKERRQ(ierr);
869 resid_norm_prev[bi] = resid_norm_init[bi];
870 delta_sol_norm_prev[bi] = 1000.0;
873 LOG_ALLOW(
GLOBAL,
LOG_INFO,
" Block %d | Max RHS = %.6f | initial pseudo-CFL = %.4f .\n", bi, resid_norm_init[bi], cfl);
890 for (PetscInt bi = 0; bi < block_number; bi++) {
891 pseudo_dtau[bi] = cfl / lambda_max;
899 PetscBool shadow = PETSC_FALSE;
900 ierr = PetscOptionsGetBool(NULL, NULL,
"-mom_stability_shadow", &shadow, NULL); CHKERRQ(ierr);
909 "Momentum scale [shadow]: legacy_dtau=%.4e new_dtau=%.4e ratio=%.4f limiter=%s | "
910 "lambda_legacy=%.4e lambda_new=%.4e (B=%.4e C=%.4e D=%.4e) | "
911 "lt=%.4e lc=%.4e lv=%.4e | cell=(%d,%d,%d) blk=%d class=%d onesided=%d\n",
912 cfl / lambda_max, cfl / rep.
lambda, rep.
lambda / lambda_max, lim,
920 "Dual-time solver: lambda_max=%.4e [1/s] resid_ref=%.4e dtau_init=%.4e dtau range [%.4e, %.4e] "
921 "CFL range [%.4f, %.4f] rejection_threshold=%.3f (EMA alpha=%.2f) "
922 "growth=%.3f reduction=%.3f max_accepted=%d.\n",
923 lambda_max, resid_ref, cfl / lambda_max, dtau_min, dtau_max,
932 PetscBool residual_convergence_enabled =
934 PetscBool converged = PETSC_FALSE;
935 PetscBool last_trial_nonfinite = PETSC_FALSE;
938 const PetscInt max_total_attempts = max_pseudo_steps * 3;
939 while (!converged && accepted_iter < max_pseudo_steps && pseudo_iter < max_total_attempts)
942 force_restart = PETSC_FALSE;
945 for (PetscInt bi = 0; bi < block_number; bi++) {
946 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
947 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
953 for (PetscInt bi = 0; bi < block_number; bi++) {
956 for (istage = 0; istage < 4; istage++) {
963 ierr = VecWAXPY(user[bi].Ucont,
964 pseudo_dtau[bi] * alfa[istage],
966 user[bi].pUcont); CHKERRQ(ierr);
984 ierr = VecWAXPY(user[bi].dUcont, -1.0, user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
987 ierr = VecNorm(user[bi].dUcont, NORM_INFINITY, &delta_sol_norm_curr[bi]); CHKERRQ(ierr);
988 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_curr[bi]); CHKERRQ(ierr);
991 if (pseudo_iter == 1) {
992 delta_sol_norm_init[bi] = delta_sol_norm_curr[bi];
993 delta_sol_rel_curr[bi] = 1.0;
994 resid_rel_curr[bi] = 1.0;
997 if (delta_sol_norm_init[bi] > 1.0e-10)
998 delta_sol_rel_curr[bi] = delta_sol_norm_curr[bi] / delta_sol_norm_init[bi];
1000 delta_sol_rel_curr[bi] = 0.0;
1002 if(resid_norm_init[bi] > 1.0e-10)
1003 resid_rel_curr[bi] = resid_norm_curr[bi] / resid_norm_init[bi];
1005 resid_rel_curr[bi] = 0.0;
1010 const PetscReal resid_floor_log = 1.0e-30;
1011 if (resid_norm_prev[bi] > resid_floor_log)
1012 trial_ratio_log[bi] = resid_norm_curr[bi] / resid_norm_prev[bi];
1013 else if (resid_norm_curr[bi] <= resid_floor_log)
1014 trial_ratio_log[bi] = 0.0;
1016 trial_ratio_log[bi] = PETSC_MAX_REAL;
1021 global_norm_delta = -1.0e20;
1022 global_rel_delta = -1.0e20;
1023 global_norm_resid = -1.0e20;
1024 global_rel_resid = -1.0e20;
1026 for (PetscInt bi = 0; bi < block_number; bi++) {
1027 global_norm_delta = PetscMax(delta_sol_norm_curr[bi], global_norm_delta);
1028 global_rel_delta = PetscMax(delta_sol_rel_curr[bi], global_rel_delta);
1029 global_norm_resid = PetscMax(resid_norm_curr[bi], global_norm_resid);
1030 global_rel_resid = PetscMax(resid_rel_curr[bi], global_rel_resid);
1032 ierr = PetscTime(&te); CHKERRQ(ierr);
1035 pseudo_iter, global_norm_delta, global_rel_delta, global_rel_resid, cput);
1038 const PetscReal resid_floor = 1.0e-30;
1039 PetscReal global_trial_ratio = 0.0;
1040 PetscBool global_nonfinite = PETSC_FALSE;
1041 for (PetscInt bi = 0; bi < block_number; bi++) {
1043 if (resid_norm_prev[bi] > resid_floor) {
1044 ratio = resid_norm_curr[bi] / resid_norm_prev[bi];
1045 }
else if (resid_norm_curr[bi] <= resid_floor) {
1048 ratio = PETSC_MAX_REAL;
1050 global_trial_ratio = PetscMax(global_trial_ratio, ratio);
1051 global_nonfinite = (PetscBool)(global_nonfinite ||
1052 PetscIsInfOrNanReal(delta_sol_norm_curr[bi]) ||
1053 PetscIsInfOrNanReal(resid_norm_curr[bi]) ||
1054 PetscIsInfOrNanReal(ratio));
1057 PetscReal reduced_trial_ratio;
1058 PetscMPIInt local_nonfinite = global_nonfinite ? 1 : 0;
1059 PetscMPIInt reduced_nonfinite = 0;
1060 ierr = MPI_Allreduce(&global_trial_ratio, &reduced_trial_ratio, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
1061 ierr = MPI_Allreduce(&local_nonfinite, &reduced_nonfinite, 1, MPI_INT, MPI_LOR, PETSC_COMM_WORLD); CHKERRQ(ierr);
1062 global_trial_ratio = reduced_trial_ratio;
1063 global_nonfinite = reduced_nonfinite ? PETSC_TRUE : PETSC_FALSE;
1064 last_trial_nonfinite = global_nonfinite;
1078 PetscReal trial_smoothed = smoothed_trial_ratio;
1079 if (!global_nonfinite) {
1084 " [k=%d] raw_ratio=%.4e smoothed_ratio=%.4e (threshold=%.3f) | "
1085 "|R_prev|=%.6e | |R_curr|=%.6e | CFL=%.6f\n",
1086 pseudo_iter, global_trial_ratio, trial_smoothed,
1088 resid_norm_prev[0], resid_norm_curr[0], pseudo_dtau[0]);
1092 force_restart = global_nonfinite;
1094 force_restart = (PetscBool)(global_nonfinite ||
1098 if (force_restart) {
1102 PetscReal old_dtau = pseudo_dtau[0];
1109 recovery_streak = 0;
1110 for (PetscInt bi = 0; bi < block_number; bi++) {
1111 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1112 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
1116 pseudo_dtau[bi] = next_dtau;
1119 " Trial %d REJECTED (raw_ratio=%.4e, smoothed=%.4e, nonfinite=%d); "
1120 "dtau %.4e -> %.4e (cfl_eff %.4f -> %.4f)%s\n",
1121 pseudo_iter, global_trial_ratio, trial_smoothed, (
int)global_nonfinite,
1122 old_dtau, next_dtau, old_dtau * lambda_max, next_dtau * lambda_max,
1123 (old_dtau == next_dtau) ?
" [AT FLOOR — no dtau reduction]" :
"");
1126 for (PetscInt bi = 0; bi < block_number; bi++) {
1128 char filen[PETSC_MAX_PATH_LEN + 128];
1129 ierr = PetscSNPrintf(filen,
sizeof(filen),
1130 "%s/Momentum_Solver_DualTime_Picard_Jameson_RK_History_Block_%1d.log",
1131 simCtx->
log_dir, bi); CHKERRQ(ierr);
1133 f = fopen(filen,
"w");
1135 f = fopen(filen,
"a");
1137 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1139 PetscFPrintf(PETSC_COMM_WORLD, f,
1140 "Step: %d | PseudoIter(k): %d | dtau: %.6e | cfl_eff: %.4f | |dUk|: %le | "
1141 "|dUk|/|dU0|: %le | |Rk|: %le | |Rk|/|R0|: %le | "
1142 "trial_ratio: %le | smoothed_ratio: %le | status: rejected | "
1143 "dtau_after: %.6e | cfl_eff_after: %.4f\n",
1144 (
int)ti, (
int)pseudo_iter, old_dtau, old_dtau * lambda_max,
1145 delta_sol_norm_curr[bi], delta_sol_rel_curr[bi],
1146 resid_norm_curr[bi], resid_rel_curr[bi],
1147 trial_ratio_log[bi], trial_smoothed,
1148 next_dtau, next_dtau * lambda_max);
1152 if (old_dtau <= dtau_min) {
1153 if (global_nonfinite) {
1154 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
1155 "Momentum solver produced a non-finite trial at minimum pseudo-CFL.");
1160 " Trial %d REJECTED (ratio=%.4e) at minimum dtau (%.4e, cfl_eff=%.4f) "
1161 "with no further reduction possible; breaking retry loop.\n",
1162 pseudo_iter, global_trial_ratio, old_dtau, old_dtau * lambda_max);
1169 smoothed_trial_ratio = trial_smoothed;
1170 last_trial_nonfinite = PETSC_FALSE;
1171 last_accepted_resid = resid_norm_curr[0];
1172 for (PetscInt bi = 0; bi < block_number; bi++) {
1173 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
1174 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
1175 resid_norm_prev[bi] = resid_norm_curr[bi];
1176 delta_sol_norm_prev[bi] = delta_sol_norm_curr[bi];
1182 PetscReal old_dtau = pseudo_dtau[0];
1183 PetscReal next_dtau = old_dtau;
1184 if (global_trial_ratio < 0.90) {
1187 recovery_streak = 0;
1188 }
else if (global_trial_ratio <= 1.0) {
1191 if (recovery_streak >= 3) {
1193 recovery_streak = 0;
1198 recovery_streak = 0;
1204 next_dtau = PetscMin(next_dtau, dtau_max);
1205 next_dtau = PetscMin(next_dtau, cfl_cap / lambda_max);
1206 next_dtau = PetscMax(next_dtau, dtau_min);
1207 for (PetscInt bi = 0; bi < block_number; bi++) pseudo_dtau[bi] = next_dtau;
1210 " Trial %d ACCEPTED (raw_ratio=%.4e, smoothed=%.4e); |dU|=%.6e | "
1211 "dtau %.4e -> %.4e (cfl_eff %.4f -> %.4f)\n",
1212 pseudo_iter, global_trial_ratio, trial_smoothed, global_norm_delta,
1213 old_dtau, next_dtau, old_dtau * lambda_max, next_dtau * lambda_max);
1217 for (PetscInt bi = 0; bi < block_number; bi++) {
1219 char filen[PETSC_MAX_PATH_LEN + 128];
1220 ierr = PetscSNPrintf(filen,
sizeof(filen),
1221 "%s/Momentum_Solver_DualTime_Picard_Jameson_RK_History_Block_%1d.log",
1222 simCtx->
log_dir, bi); CHKERRQ(ierr);
1224 f = fopen(filen,
"w");
1226 f = fopen(filen,
"a");
1228 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1230 PetscFPrintf(PETSC_COMM_WORLD, f,
1231 "Step: %d | PseudoIter(k): %d | dtau: %.6e | cfl_eff: %.4f | |dUk|: %le | "
1232 "|dUk|/|dU0|: %le | |Rk|: %le | |Rk|/|R0|: %le | "
1233 "trial_ratio: %le | smoothed_ratio: %le | status: accepted | "
1234 "dtau_after: %.6e | cfl_eff_after: %.4f\n",
1235 (
int)ti, (
int)pseudo_iter, old_dtau, old_dtau * lambda_max,
1236 delta_sol_norm_curr[bi], delta_sol_rel_curr[bi],
1237 resid_norm_curr[bi], resid_rel_curr[bi],
1238 trial_ratio_log[bi], trial_smoothed,
1239 next_dtau, next_dtau * lambda_max);
1277 if (residual_convergence_enabled) {
1278 const PetscBool residual_abs_pass = (PetscBool)(
1280 global_norm_resid <= simCtx->mom_resid_atol * resid_ref);
1281 const PetscBool residual_rel_pass = (PetscBool)(
1282 simCtx->
mom_resid_rtol > 0.0 && global_rel_resid <= simCtx->mom_resid_rtol);
1283 const PetscBool update_pass = (PetscBool)(
1284 tol_rtol_delta <= 0.0 || global_rel_delta <= tol_rtol_delta);
1285 converged = (PetscBool)(residual_abs_pass || (residual_rel_pass && update_pass));
1287 converged = (PetscBool)(global_norm_delta <= tol_abs_delta &&
1288 global_rel_delta <= tol_rtol_delta);
1291 if (block_number > 1) {
1296 if (last_trial_nonfinite) {
1297 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
1298 "Momentum solver exhausted its attempt limit while recovering from a non-finite trial.");
1305 PetscReal next_dtau_start = pseudo_dtau[0];
1306 PetscReal next_cfl_warmstart = next_dtau_start * lambda_max;
1310 " Step %d finished: dtau=%.4e cfl_eff=%.4f lambda_max=%.4e [1/s]. "
1311 "Next step warm-starts at cfl=%.4f.\n",
1312 simCtx->
step, next_dtau_start, next_cfl_warmstart, lambda_max, next_cfl_warmstart);
1322 if (accepted_iter == 0) {
1323 for (PetscInt bi = 0; bi < block_number; bi++) {
1324 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1325 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
1328 for (PetscInt bi = 0; bi < block_number; bi++) {
1336 PetscPrintf(PETSC_COMM_WORLD,
1337 "[WARNING] Momentum solver step %d: reached %d total attempts (%d accepted, %d rejected) "
1338 "without convergence; continuing from last accepted finite state.\n",
1339 (
int)ti, pseudo_iter, accepted_iter, rejected_iter);
1341 if (accepted_iter == 0) {
1342 PetscPrintf(PETSC_COMM_WORLD,
1343 "[WARNING] Momentum solver step %d: no pseudo-time trials were accepted; "
1344 "retaining physical-step entry state.\n", (
int)ti);
1347 "Momentum solver finished: %d attempts (%d accepted, %d rejected) of %d max accepted / %d hard cap, "
1348 "converged=%s, last accepted |R|=%.6e, last accepted |dU|=%.6e, "
1349 "next_dtau=%.4e (cfl=%.4f).\n",
1350 pseudo_iter, accepted_iter, rejected_iter, max_pseudo_steps, max_total_attempts,
1351 converged ?
"yes" :
"no",
1352 (accepted_iter > 0) ? last_accepted_resid : resid_norm_init[0],
1353 (accepted_iter > 0) ? delta_sol_norm_prev[0] : 0.0,
1354 next_dtau_start, next_cfl_warmstart);
1357 for (PetscInt bi = 0; bi < block_number; bi++) {
1358 ierr = VecDestroy(&user[bi].Rhs); CHKERRQ(ierr);
1359 ierr = VecDestroy(&user[bi].dUcont); CHKERRQ(ierr);
1360 ierr = VecDestroy(&user[bi].pUcont); CHKERRQ(ierr);
1361 ierr = VecDestroy(&pRhs[bi]); CHKERRQ(ierr);
1363 ierr = PetscFree(pRhs); CHKERRQ(ierr);
1365 ierr = PetscFree2(delta_sol_norm_init, delta_sol_norm_prev);CHKERRQ(ierr);
1366 ierr = PetscFree2(delta_sol_norm_curr, delta_sol_rel_curr);CHKERRQ(ierr);
1367 ierr = PetscFree2(resid_norm_init, resid_norm_prev);CHKERRQ(ierr);
1368 ierr = PetscFree2(resid_norm_curr, pseudo_dtau); CHKERRQ(ierr);
1369 ierr = PetscFree(resid_rel_curr); CHKERRQ(ierr);
1370 ierr = PetscFree(trial_ratio_log); CHKERRQ(ierr);
1373 PetscFunctionReturn(0);