Solves the momentum equations using dual-time Picard iteration with Jameson RK smoothing.
Local to this translation unit.
769{
770 (void)ibm;
771 (void)fsi;
772
775
776
777 const PetscInt ti = simCtx->
step;
778 const PetscReal dt = simCtx->
dt;
779
780
782 const PetscReal alfa[] = {0.25, 1.0/3.0, 0.5, 1.0};
783 Vec *pRhs;
784
785
786 PetscBool force_restart = PETSC_FALSE;
787
788
790 const PetscReal tol_abs_delta = simCtx->
mom_atol;
791 const PetscReal tol_rtol_delta = simCtx->
mom_rtol;
792
793
794 PetscErrorCode ierr;
795 PetscMPIInt rank;
796 PetscInt istage, pseudo_iter;
797 PetscInt accepted_iter = 0, rejected_iter = 0, recovery_streak = 0;
798 PetscReal ts, te, cput;
799
800
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;
806
807
808
809
810
811
812
813
814 PetscReal lambda_max = 0.0;
815
816
817
818
819
821
822
823
824 PetscReal resid_ref = 0.0;
825 PetscReal dtau_min, dtau_max;
826
827
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;
833
834 PetscFunctionBeginUser;
836 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
838
839
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;
848
849 ierr = PetscTime(&ts); CHKERRQ(ierr);
850
851
852
853 if (block_number > 1) {
854
855 }
856
857 for (PetscInt bi = 0; bi < block_number; bi++) {
859
860
861
862
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);
867
868
869 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
870
871
873
874
875 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
876
877
878 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_init[bi]); CHKERRQ(ierr);
879
880
881
882 {
883 PetscReal ucont_inf;
884 ierr = VecNorm(user[bi].Ucont, NORM_INFINITY, &ucont_inf); CHKERRQ(ierr);
886 }
887
888
889 resid_norm_prev[bi] = resid_norm_init[bi];
890 delta_sol_norm_prev[bi] = 1000.0;
891
892
893 LOG_ALLOW(
GLOBAL,
LOG_INFO,
" Block %d | Max RHS = %.6f | initial pseudo-CFL = %.4f .\n", bi, resid_norm_init[bi], cfl);
894 }
895
896
897
898
899
900
901
902
903
904
908
909
910 for (PetscInt bi = 0; bi < block_number; bi++) {
911 pseudo_dtau[bi] = cfl / lambda_max;
912 }
913
914
915
916
917
918 {
919 PetscBool shadow = PETSC_FALSE;
920 ierr = PetscOptionsGetBool(NULL, NULL, "-mom_stability_shadow", &shadow, NULL); CHKERRQ(ierr);
921 if (shadow) {
926
927
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,
936 }
937 }
938
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,
948 max_pseudo_steps);
949
950
951 pseudo_iter = 0;
952 PetscBool residual_convergence_enabled =
954 PetscBool converged = PETSC_FALSE;
955 PetscBool last_trial_nonfinite = PETSC_FALSE;
956
957
958 const PetscInt max_total_attempts = max_pseudo_steps * 3;
959 while (!converged && accepted_iter < max_pseudo_steps && pseudo_iter < max_total_attempts)
960 {
961 pseudo_iter++;
962 force_restart = PETSC_FALSE;
963
964
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);
971 }
972
973 for (PetscInt bi = 0; bi < block_number; bi++) {
974
975
976 for (istage = 0; istage < 4; istage++) {
977
979
980
981
982
983 ierr = VecWAXPY(user[bi].Ucont,
984 pseudo_dtau[bi] * alfa[istage],
985 user[bi].Rhs,
986 user[bi].pUcont); CHKERRQ(ierr);
987
988
991
993
994
996
997 }
998
999
1000
1001
1002
1003
1004 ierr = VecWAXPY(user[bi].dUcont, -1.0, user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
1005
1006
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);
1009
1010
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;
1015
1016 } else {
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];
1019 else
1020 delta_sol_rel_curr[bi] = 0.0;
1021
1022 if(resid_norm_init[bi] > 1.0e-10)
1023 resid_rel_curr[bi] = resid_norm_curr[bi] / resid_norm_init[bi];
1024 else
1025 resid_rel_curr[bi] = 0.0;
1026 }
1027
1028
1029 {
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;
1035 else
1036 trial_ratio_log[bi] = PETSC_MAX_REAL;
1037 }
1038 }
1039
1040
1041 global_norm_delta = -1.0e20;
1042 global_rel_delta = -1.0e20;
1043 global_norm_resid = -1.0e20;
1044 global_rel_resid = -1.0e20;
1045
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);
1051 }
1052 ierr = PetscTime(&te); CHKERRQ(ierr);
1053 cput = te - ts;
1055 pseudo_iter, global_norm_delta, global_rel_delta, global_rel_resid, cput);
1056
1057
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++) {
1062 PetscReal ratio;
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) {
1066 ratio = 0.0;
1067 } else {
1068 ratio = PETSC_MAX_REAL;
1069 }
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));
1075 }
1076
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;
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098 PetscReal trial_smoothed = smoothed_trial_ratio;
1099 if (!global_nonfinite) {
1102 }
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]);
1109
1111
1112 force_restart = global_nonfinite;
1113 } else {
1114 force_restart = (PetscBool)(global_nonfinite ||
1116 }
1117
1118 if (force_restart) {
1119
1120
1121
1122 PetscReal old_dtau = pseudo_dtau[0];
1124
1125
1128 rejected_iter++;
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;
1137 }
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]" : "");
1144
1145 if (!rank) {
1146 for (PetscInt bi = 0; bi < block_number; bi++) {
1147 FILE *f;
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");
1154 else
1155 f = fopen(filen, "a");
1157 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1158
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);
1169 fclose(f);
1170 }
1171 }
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.");
1176 }
1177
1178
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);
1183 break;
1184 }
1185 continue;
1186 }
1187
1188 accepted_iter++;
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];
1197 }
1198
1199
1200
1201
1202 PetscReal old_dtau = pseudo_dtau[0];
1203 PetscReal next_dtau = old_dtau;
1204 if (global_trial_ratio < 0.90) {
1205
1207 recovery_streak = 0;
1208 } else if (global_trial_ratio <= 1.0) {
1209
1210 recovery_streak++;
1211 if (recovery_streak >= 3) {
1213 recovery_streak = 0;
1214 }
1215 } else {
1216
1218 recovery_streak = 0;
1219 }
1220
1221
1222
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;
1228
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);
1234
1235
1236 if (!rank) {
1237 for (PetscInt bi = 0; bi < block_number; bi++) {
1238 FILE *f;
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");
1245 else
1246 f = fopen(filen, "a");
1248 PetscFPrintf(PETSC_COMM_WORLD, f,
"# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep);
1249
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);
1260 fclose(f);
1261 }
1262 }
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
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));
1306 } else {
1307 converged = (PetscBool)(global_norm_delta <= tol_abs_delta &&
1308 global_rel_delta <= tol_rtol_delta);
1309 }
1310
1311 if (block_number > 1) {
1312
1313 }
1314 }
1315
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.");
1319 }
1320
1321
1322
1323
1324
1325 PetscReal next_dtau_start = pseudo_dtau[0];
1326 PetscReal next_cfl_warmstart = next_dtau_start * lambda_max;
1327
1328 if (!rank) {
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);
1333 }
1334
1335
1338
1339
1340
1341
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);
1346 }
1347 }
1348 for (PetscInt bi = 0; bi < block_number; bi++) {
1352 }
1353
1355 if (!converged) {
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);
1360 }
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);
1365 }
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);
1375
1376
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);
1382 }
1383 ierr = PetscFree(pRhs); CHKERRQ(ierr);
1384
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);
1391
1393 PetscFunctionReturn(0);
1394}
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
@ LOG_WARNING
Non-critical issues that warrant attention.
#define MOM_CFL_CAP_SAFETY
static PetscErrorCode ComputeGlobalSpectralRadiusEstimate(UserCtx *user, PetscInt block_number, PetscReal dt, PetscReal *lambda_max_out)
Compute a conservative global pseudo-time spectral radius estimate.
PetscErrorCode ComputeTotalResidual(UserCtx *user)
Shared implementation of ComputeTotalResidual().
PetscErrorCode ComputeMomentumStabilityEstimate(UserCtx *user, PetscInt block_number, PetscReal dt, MomStabCandidate candidate, MomStabilityReport *rep)
Practical conservative momentum pseudo-time stability estimate (shadow).
#define MOM_CFL_CAP_RELAX
Diagnostic report produced by ComputeMomentumStabilityEstimate().
PetscReal mom_last_lambda_max
PetscReal pseudo_cfl_reduction_factor
PetscBool mom_last_converged
PetscBool no_pseudo_cfl_backtrack
char log_dir[PETSC_MAX_PATH_LEN]
PetscReal mom_dt_jameson_residual_norm_noise_allowance_factor
PetscReal pseudo_cfl_growth_factor
PetscInt mom_max_pseudo_steps
PetscReal mom_ratio_ema_alpha