Skip to content

Commit 1a7b94b

Browse files
Fix #2483: Implement field-based restart loading for turbulence solvers
1 parent 4300abd commit 1a7b94b

6 files changed

Lines changed: 200 additions & 33 deletions

File tree

SU2_CFD/include/solvers/CSolver.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ class CSolver {
234234
return base_nodes;
235235
}
236236

237+
/*!
238+
* \brief Find the indices of fields by name.
239+
* \param[in] target_fields - Vector of field names to find (with or without quotes).
240+
* \return Vector of indices (0-based), or -1 for fields not found.
241+
*/
242+
vector<int> FindFieldIndices(const vector<string>& target_fields) const;
243+
237244
/*!
238245
* \brief Helper function to define the type and number of variables per point for each communication type.
239246
* \param[in] config - Definition of the particular problem.

SU2_CFD/src/solvers/CSolver.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,32 @@ CSolver::~CSolver() {
188188
delete VerificationSolution;
189189
}
190190

191+
vector<int> CSolver::FindFieldIndices(const vector<string>& target_fields) const {
192+
/*--- Search for field names in the fields vector.
193+
Fields are stored with quotes, e.g., "Temperature", so we need to check
194+
both with and without quotes. ---*/
195+
196+
vector<int> indices;
197+
indices.reserve(target_fields.size());
198+
199+
for (const auto& search : target_fields) {
200+
/*--- Prepare both quoted and unquoted versions ---*/
201+
string fieldNameWithQuotes = "\"" + search + "\"";
202+
203+
/*--- Search for the field (try both with and without quotes) ---*/
204+
auto it = std::find(fields.begin(), fields.end(), fieldNameWithQuotes);
205+
if (it == fields.end()) {
206+
it = std::find(fields.begin(), fields.end(), search);
207+
}
208+
209+
/*--- Store the index or -1 if not found ---*/
210+
indices.push_back(it != fields.end() ? std::distance(fields.begin(), it) : -1);
211+
}
212+
213+
return indices;
214+
}
215+
216+
191217
void CSolver::GetPeriodicCommCountAndType(const CConfig* config,
192218
unsigned short commType,
193219
unsigned short &COUNT_PER_POINT,

SU2_CFD/src/solvers/CTransLMSolver.cpp

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -515,21 +515,19 @@ void CTransLMSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfi
515515
Read_SU2_Restart_ASCII(geometry[MESH_0], config, restart_filename);
516516
}
517517

518-
/*--- Skip flow variables ---*/
519-
520-
unsigned short skipVars = nDim + solver[MESH_0][FLOW_SOL]->GetnVar() + solver[MESH_0][TURB_SOL] ->GetnVar();
521-
522-
/*--- Adjust the number of solution variables in the incompressible
523-
restart. We always carry a space in nVar for the energy equation in the
524-
mean flow solver, but we only write it to the restart if it is active.
525-
Therefore, we must reduce skipVars here if energy is inactive so that
526-
the turbulent variables are read correctly. ---*/
527-
528-
const bool incompressible = (config->GetKind_Regime() == ENUM_REGIME::INCOMPRESSIBLE);
529-
const bool energy = config->GetEnergy_Equation();
530-
const bool weakly_coupled_heat = config->GetWeakly_Coupled_Heat();
531-
532-
if (incompressible && ((!energy) && (!weakly_coupled_heat))) skipVars--;
518+
/*--- Identify indices for LM transition variables ---*/
519+
vector<string> target_fields = {"LM_gamma", "LM_Re_t", "LM_gamma_sep", "LM_gamma_eff"};
520+
vector<int> field_indices = FindFieldIndices(target_fields);
521+
522+
/*--- Warn if any fields are missing (Master node only) ---*/
523+
if (rank == MASTER_NODE) {
524+
for (size_t i = 0; i < target_fields.size(); ++i) {
525+
if (field_indices[i] == -1) {
526+
cout << "WARNING: " << target_fields[i] << " field not found in restart file. "
527+
<< "Using initialized default.\n";
528+
}
529+
}
530+
}
533531

534532
/*--- Load data from the restart into correct containers. ---*/
535533

@@ -544,10 +542,27 @@ void CTransLMSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfi
544542
/*--- We need to store this point's data, so jump to the correct
545543
offset in the buffer of data from the restart file and load it. ---*/
546544

547-
const auto index = counter * Restart_Vars[1] + skipVars;
548-
for (auto iVar = 0u; iVar < nVar; iVar++) nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index + iVar]);
549-
nodes->SetIntermittencySep(iPoint_Local, Restart_Data[index + 2]);
550-
nodes->SetIntermittencyEff(iPoint_Local, Restart_Data[index + 3]);
545+
const auto base_idx = counter * Restart_Vars[1];
546+
547+
/*--- Load Gamma (LM_gamma) ---*/
548+
if (field_indices[0] != -1) {
549+
nodes->SetSolution(iPoint_Local, 0, Restart_Data[base_idx + field_indices[0]]);
550+
}
551+
552+
/*--- Load Re_Theta_t (LM_Re_t) ---*/
553+
if (field_indices[1] != -1) {
554+
nodes->SetSolution(iPoint_Local, 1, Restart_Data[base_idx + field_indices[1]]);
555+
}
556+
557+
/*--- Load Intermittency Sep (LM_gamma_sep) ---*/
558+
if (field_indices[2] != -1) {
559+
nodes->SetIntermittencySep(iPoint_Local, Restart_Data[base_idx + field_indices[2]]);
560+
}
561+
562+
/*--- Load Intermittency Eff (LM_gamma_eff) ---*/
563+
if (field_indices[3] != -1) {
564+
nodes->SetIntermittencyEff(iPoint_Local, Restart_Data[base_idx + field_indices[3]]);
565+
}
551566

552567
/*--- Increment the overall counter for how many points have been loaded. ---*/
553568
counter++;

SU2_CFD/src/solvers/CTurbSolver.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,31 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig*
118118
Read_SU2_Restart_ASCII(geometry[MESH_0], config, restart_filename);
119119
}
120120

121-
/*--- Skip flow variables ---*/
121+
/*--- Identify turbulence variable names based on the model ---*/
122+
vector<string> varNames(nVar);
122123

123-
unsigned short skipVars = nDim + solver[MESH_0][FLOW_SOL]->GetnVar();
124-
125-
/*--- Adjust the number of solution variables in the incompressible
126-
restart. We always carry a space in nVar for the energy equation in the
127-
mean flow solver, but we only write it to the restart if it is active.
128-
Therefore, we must reduce skipVars here if energy is inactive so that
129-
the turbulent variables are read correctly. ---*/
124+
const auto kind_turb_model = config->GetKind_Turb_Model();
125+
if (kind_turb_model == TURB_MODEL::SA) {
126+
if (nVar > 0) varNames[0] = "Nu_Tilde";
127+
}
128+
else if (kind_turb_model == TURB_MODEL::SST) {
129+
if (nVar > 0) varNames[0] = "Turb_Kin_Energy";
130+
if (nVar > 1) varNames[1] = "Omega";
131+
}
132+
/*--- Add other turbulence models as needed ---*/
130133

131-
const bool incompressible = (config->GetKind_Regime() == ENUM_REGIME::INCOMPRESSIBLE);
132-
const bool energy = config->GetEnergy_Equation();
133-
const bool weakly_coupled_heat = config->GetWeakly_Coupled_Heat();
134+
/*--- Find indices for all turbulence variables at once ---*/
135+
vector<int> field_indices = FindFieldIndices(varNames);
134136

135-
if (incompressible && ((!energy) && (!weakly_coupled_heat))) skipVars--;
137+
/*--- Warn if any fields are missing (Master node only) ---*/
138+
if (rank == MASTER_NODE) {
139+
for (unsigned short iVar = 0; iVar < nVar; ++iVar) {
140+
if (field_indices[iVar] == -1 && !varNames[iVar].empty()) {
141+
cout << "WARNING: " << varNames[iVar] << " field not found in restart file. "
142+
<< "Using initialized default.\n";
143+
}
144+
}
145+
}
136146

137147
/*--- Load data from the restart into correct containers. ---*/
138148

@@ -147,8 +157,12 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig*
147157
/*--- We need to store this point's data, so jump to the correct
148158
offset in the buffer of data from the restart file and load it. ---*/
149159

150-
const auto index = counter * Restart_Vars[1] + skipVars;
151-
for (auto iVar = 0u; iVar < nVar; iVar++) nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index + iVar]);
160+
const auto baseIndex = counter * Restart_Vars[1];
161+
for (auto iVar = 0u; iVar < nVar; iVar++) {
162+
if (field_indices[iVar] != -1) {
163+
nodes->SetSolution(iPoint_Local, iVar, Restart_Data[baseIndex + field_indices[iVar]]);
164+
}
165+
}
152166

153167
/*--- Increment the overall counter for how many points have been loaded. ---*/
154168
counter++;
@@ -166,6 +180,7 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig*
166180
} // end safe global access, pre and postprocessing are thread-safe.
167181
END_SU2_OMP_SAFE_GLOBAL_ACCESS
168182

183+
169184
/*--- MPI solution and compute the eddy viscosity ---*/
170185

171186
solver[MESH_0][TURB_SOL]->InitiateComms(geometry[MESH_0], config, MPI_QUANTITIES::SOLUTION);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2+
% %
3+
% SU2 configuration file %
4+
% Case description: Euler precursor for restart test (NACA0012) %
5+
% Author: SU2 Development Team %
6+
% File Version 8.4.0 "Harrier" %
7+
% %
8+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9+
10+
SOLVER= EULER
11+
MATH_PROBLEM= DIRECT
12+
RESTART_SOL= NO
13+
14+
MACH_NUMBER= 0.8
15+
AOA= 1.25
16+
FREESTREAM_PRESSURE= 101325.0
17+
FREESTREAM_TEMPERATURE= 288.15
18+
19+
REF_ORIGIN_MOMENT_X = 0.25
20+
REF_ORIGIN_MOMENT_Y = 0.00
21+
REF_ORIGIN_MOMENT_Z = 0.00
22+
REF_LENGTH= 1.0
23+
REF_AREA= 1.0
24+
25+
MARKER_EULER= ( airfoil )
26+
MARKER_FAR= ( farfield )
27+
28+
NUM_METHOD_GRAD= WEIGHTED_LEAST_SQUARES
29+
CFL_NUMBER= 10.0
30+
ITER= 10
31+
32+
LINEAR_SOLVER= FGMRES
33+
LINEAR_SOLVER_PREC= ILU
34+
LINEAR_SOLVER_ERROR= 1E-10
35+
LINEAR_SOLVER_ITER= 10
36+
37+
CONV_NUM_METHOD_FLOW= ROE
38+
TIME_DISCRE_FLOW= EULER_IMPLICIT
39+
40+
MESH_FILENAME= ../../../QuickStart/mesh_NACA0012_inv.su2
41+
MESH_FORMAT= SU2
42+
43+
TABULAR_FORMAT= CSV
44+
CONV_FILENAME= history
45+
RESTART_FILENAME= restart_flow_euler
46+
OUTPUT_WRT_FREQ= 10
47+
48+
SCREEN_OUTPUT=(INNER_ITER, WALL_TIME, RMS_DENSITY, RMS_ENERGY, LIFT, DRAG)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2+
% %
3+
% SU2 configuration file %
4+
% Case description: SA restart from Euler (tests missing field initialization)%
5+
% Author: SU2 Development Team %
6+
% File Version 8.4.0 "Harrier" %
7+
% %
8+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9+
10+
SOLVER= RANS
11+
KIND_TURB_MODEL= SA
12+
MATH_PROBLEM= DIRECT
13+
RESTART_SOL= YES
14+
15+
MACH_NUMBER= 0.8
16+
AOA= 1.25
17+
FREESTREAM_PRESSURE= 101325.0
18+
FREESTREAM_TEMPERATURE= 288.15
19+
REYNOLDS_NUMBER= 6.5e6
20+
REYNOLDS_LENGTH= 1.0
21+
22+
REF_ORIGIN_MOMENT_X = 0.25
23+
REF_ORIGIN_MOMENT_Y = 0.00
24+
REF_ORIGIN_MOMENT_Z = 0.00
25+
REF_LENGTH= 1.0
26+
REF_AREA= 1.0
27+
28+
MARKER_HEATFLUX= ( airfoil, 0.0 )
29+
MARKER_FAR= ( farfield )
30+
31+
NUM_METHOD_GRAD= WEIGHTED_LEAST_SQUARES
32+
CFL_NUMBER= 10.0
33+
ITER= 10
34+
35+
LINEAR_SOLVER= FGMRES
36+
LINEAR_SOLVER_PREC= ILU
37+
LINEAR_SOLVER_ERROR= 1E-10
38+
LINEAR_SOLVER_ITER= 10
39+
40+
CONV_NUM_METHOD_FLOW= ROE
41+
TIME_DISCRE_FLOW= EULER_IMPLICIT
42+
CONV_NUM_METHOD_TURB= SCALAR_UPWIND
43+
MUSCL_TURB= NO
44+
SLOPE_LIMITER_TURB= VENKATAKRISHNAN
45+
TIME_DISCRE_TURB= EULER_IMPLICIT
46+
47+
MESH_FILENAME= ../../../QuickStart/mesh_NACA0012_inv.su2
48+
MESH_FORMAT= SU2
49+
50+
TABULAR_FORMAT= CSV
51+
CONV_FILENAME= history
52+
RESTART_FILENAME= restart_flow_sa
53+
SOLUTION_FILENAME= restart_flow_euler.dat
54+
OUTPUT_WRT_FREQ= 10
55+
56+
SCREEN_OUTPUT=(INNER_ITER, WALL_TIME, RMS_DENSITY, RMS_ENERGY, RMS_NU_TILDE, LIFT, DRAG)

0 commit comments

Comments
 (0)