Skip to content

Dual-time restart is inconsistent with the LM transition model: TRANS_SOL time levels are never initialised (v8.5.0) #2993

Open

Description

@PhaGe8539

Version / platform. SU2 v8.5.0 "Harrier" (release tarball), Windows 11 x64. Reproduced with the official v8.5.0 Windows binary
and with a from-source build (GCC 15 / MSYS2 UCRT64, -Dwith-omp=true -Dwith-mpi=disabled). Same behaviour in develop by reading
the source (see "Where").

Summary. With KIND_TRANS_MODEL= LM (SST-LM here) and TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER, the transition solver's
dual-time history (Solution_time_n, Solution_time_n1) is never set when a run starts or restarts. It keeps its zero allocation
until the end of the first physical step, so the BDF2 term of that step acts on intermittency and Re_theta_t as if both were zero at
n and n-1: a sink of strength 3/(2 dt) over the whole field (1/dt for 1ST_ORDER). The flow and turbulence solvers are handled
correctly (PushSolutionBackInTime pushes them back and reloads the RESTART_ITER-1 file); the transition solver is simply left out.
Consequence: a restarted time-accurate SST-LM run does not continue the un-restarted one, and every (re)start injects a transient.

Where (v8.5.0 sources).

  • SU2_CFD/include/solvers/CFVMFlowSolverBase.inl, CFVMFlowSolverBase::PushSolutionBackInTime (lines 1120-1167): Set_Solution_time_n()
    / _n1() and the TimeIter-1 reload are done for FLOW_SOL and, if rans, TURB_SOL only. TRANS_SOL does not appear.
  • SU2_CFD/include/solvers/CScalarSolver.inl:860 CScalarSolver::PushSolutionBackInTime exists but is called only from
    CSpeciesSolver.cpp:674 and CSpeciesFlameletSolver.cpp:328.
  • SU2_CFD/src/variables/CTransLMVariable.cpp:31-46: the constructor sets Solution and Solution_Old only (compare
    CTurbSAVariable.cpp:50-57, which initialises the time levels when dual_time).
  • SU2_CFD/src/iteration/CFluidIteration.cpp:194: the TRANS time levels are first set by SetDualTime_Solver at the END of step 1.
  • The BDF residual that consumes the zero levels: CScalarSolver.inl dual-time source (3 U^{n+1} - 4 U^n + U^{n-1}) V / (2 dt).

Minimal reproducer (the "9 + 1 vs 10" test, as in #2707). Any 2-D airfoil SST-LM case; the public one is the E387 transition
tutorial (compressible_flow/Transitional_Airfoil/Langtry_and_Menter/E387). Steps:

  1. Converge the steady case (RESTART_SOL= NO), keep restart_flow.dat; copy it to restart_flow_00000.dat and restart_flow_00001.dat.
  2. Time-accurate config: TIME_DOMAIN= YES, TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER, TIME_STEP= <c/U/200>, INNER_ITER= 40,
    RESTART_SOL= YES, RESTART_ITER= 2, SOLUTION_FILENAME= restart_flow.dat, OUTPUT_WRT_FREQ= 1, WRT_RESTART_COMPACT= NO,
    HISTORY_OUTPUT= (ITER, RMS_RES, AERO_COEFF, TIME_DOMAIN); remove ITER.
  3. Run A: TIME_ITER= 12 (10 physical steps, continuous).
  4. Run B: TIME_ITER= 11 (9 steps), then restart with RESTART_ITER= 11, TIME_ITER= 12 (1 step; reads _00009 and _00010).
  5. Compare the history row of Time_Iter 11 (the 10th step) between A and B.

Expected. An exact restart reproduces step 10 to round-off (the flow and SST residuals do).

Actual (our case: 2-D airfoil, SST-LM MENTER_LANGTRY, Re 2e5, M 0.15, Tu 0.1 %, medium C-mesh, dt = c/U/200, 6 OpenMP threads).
At the restarted step the log10 RMS residuals jump and the record never rejoins the continuous run:

quantity at Time_Iter 11 continuous (A) 9 + restart + 1 (B) difference
log10 rms[LM_1] (intermittency) -3.5708 -0.3549 +3.22 orders
log10 rms[LM_2] (Re_theta_t) -0.5694 +0.5454 +1.11 orders
log10 rms[k] +0.45 orders
log10 rms[Rho] -0.024
CD -2.6e-4 relative

The same numbers result with WRT_RESTART_COMPACT= YES. This is the behaviour described in discussion #2615 (LM_1 about -0.24 vs
-3.8 after a restart).

With the patch below (three guarded additions, nothing else changed) the same test gives identical A and B rows to the printed
precision (all differences 0 at 1e-6), and the continuous run itself starts cleanly: log10 rms[LM_1] at step 10 is -6.47 instead of
-3.57, because the stock run also receives the kick at its own first step.

Proposed patch (against v8.5.0; TRANS_SOL treated exactly like TURB_SOL):

--- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl
+++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl
@@ PushSolutionBackInTime
+  const bool trans = rans && (config->GetKind_Trans_Model() != TURB_TRANS_MODEL::NONE) &&
+                     (solver_container[MESH_0][TRANS_SOL] != nullptr);
   for (unsigned short iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) {
     ...
     if (rans) { TURB_SOL->Set_Solution_time_n(); TURB_SOL->Set_Solution_time_n1(); }
+    if (trans) {
+      solver_container[iMesh][TRANS_SOL]->GetNodes()->Set_Solution_time_n();
+      solver_container[iMesh][TRANS_SOL]->GetNodes()->Set_Solution_time_n1();
+    }
   ...
   if (restart && DT_STEPPING_2ND) {
     FLOW_SOL->LoadRestart(..., TimeIter-1, true);
     if (rans) TURB_SOL->LoadRestart(..., TimeIter-1, false);
+    if (trans) solver_container[MESH_0][TRANS_SOL]->LoadRestart(geometry, solver_container, config, TimeIter-1, false);
     for (iMesh ...) {
       FLOW_SOL->Set_Solution_time_n();
       if (rans) TURB_SOL->Set_Solution_time_n();
+      if (trans) solver_container[iMesh][TRANS_SOL]->GetNodes()->Set_Solution_time_n();

Optional backstop in CTransLMVariable::CTransLMVariable (as CTurbSAVariable): if (dual_time) { Solution_time_n = Solution_time_n1 = Solution; }.
(An alternative with the same effect would be to call CScalarSolver::PushSolutionBackInTime for the transition solver, the way
the species solvers do.) I'm happy to share the complete unified diff against v8.5.0 or open a PR if that helps.

Related: CTransLMSolver::LoadRestart (v8.5.0 lines 560-561) reads Intermittency_Sep / _Eff from Restart_Data[index + 2]
and [index + 3], i.e. from whatever variables follow the two LM solution variables in the file; Postprocessing recomputes both
anyway. PR #1901 drops these reads; with the patch above the second LoadRestart call would otherwise repeat them, so we ported that
change as well. Steady results are unaffected by either change (two steady SST-LM cases reproduce the stock histories to 1e-7).

Verification done. (a) steady path: two 6000-iteration SST-LM cases identical to the stock binary to 1.2e-7 relative in CD;
(b) the 9 + 1 vs 10 test above, 2 x 2 (stock / patched x compact NO / YES).

Related: discussion #2615, PRs #1901, #2707, #2730, #2542.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions