Skip to content

Commit 3bc9ca2

Browse files
Fix #2483: Add field-based restart loading with missing field initialization
1 parent e1befed commit 3bc9ca2

File tree

4 files changed

+213
-18
lines changed

4 files changed

+213
-18
lines changed

SU2_CFD/include/solvers/CFVMFlowSolverBase.inl

Lines changed: 150 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,47 @@ void CFVMFlowSolverBase<V, R>::LoadRestart_impl(CGeometry **geometry, CSolver **
856856
}
857857
}
858858

859+
/*--- Check for missing fields and prepare field-based lookup ---*/
860+
const bool incompressible = (config->GetKind_Regime() == ENUM_REGIME::INCOMPRESSIBLE);
861+
const bool energy = config->GetEnergy_Equation();
862+
const bool weakly_coupled_heat = config->GetWeakly_Coupled_Heat();
863+
const bool flamelet = (config->GetKind_FluidModel() == FLUID_FLAMELET);
864+
865+
/*--- Find field indices for solution variables ---*/
866+
int fieldIdx_Pressure = -1, fieldIdx_Temperature = -1;
867+
int fieldIdx_Velocity[MAXNDIM] = {-1, -1, -1};
868+
int fieldIdx_Density = -1, fieldIdx_Energy = -1;
869+
int fieldIdx_Momentum[MAXNDIM] = {-1, -1, -1};
870+
871+
if (incompressible) {
872+
fieldIdx_Pressure = FindFieldIndex("Pressure");
873+
for (auto iDim = 0u; iDim < nDim; iDim++) {
874+
string velName = "Velocity_" + string(iDim == 0 ? "x" : (iDim == 1 ? "y" : "z"));
875+
fieldIdx_Velocity[iDim] = FindFieldIndex(velName);
876+
}
877+
if (energy || weakly_coupled_heat || flamelet) {
878+
fieldIdx_Temperature = FindFieldIndex("Temperature");
879+
}
880+
} else {
881+
/*--- Compressible flow ---*/
882+
fieldIdx_Density = FindFieldIndex("Density");
883+
for (auto iDim = 0u; iDim < nDim; iDim++) {
884+
string momName = "Momentum_" + string(iDim == 0 ? "x" : (iDim == 1 ? "y" : "z"));
885+
fieldIdx_Momentum[iDim] = FindFieldIndex(momName);
886+
}
887+
fieldIdx_Energy = FindFieldIndex("Energy");
888+
}
889+
890+
/*--- Warn about missing fields and prepare defaults ---*/
891+
su2double default_Temperature = 0.0;
892+
if (incompressible && (energy || weakly_coupled_heat || flamelet) && fieldIdx_Temperature < 0) {
893+
if (rank == MASTER_NODE) {
894+
cout << "\nWARNING: The restart file does not contain Temperature field." << endl;
895+
cout << "Temperature will be initialized from config (INC_TEMPERATURE_INIT)." << endl;
896+
}
897+
default_Temperature = config->GetInc_Temperature_Init() / config->GetInc_Temperature_Ref();
898+
}
899+
859900
/*--- Load data from the restart into correct containers. ---*/
860901

861902
unsigned long counter = 0;
@@ -868,19 +909,103 @@ void CFVMFlowSolverBase<V, R>::LoadRestart_impl(CGeometry **geometry, CSolver **
868909

869910
if (iPoint_Local > -1) {
870911

871-
/*--- We need to store this point's data, so jump to the correct
872-
offset in the buffer of data from the restart file and load it. ---*/
873-
874-
auto index = counter * Restart_Vars[1] + skipVars;
875-
876-
if (SolutionRestart == nullptr) {
877-
for (auto iVar = 0u; iVar < nVar_Restart; iVar++)
878-
nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index+iVar]);
912+
/*--- Base index for this point in the restart data ---*/
913+
auto baseIndex = counter * Restart_Vars[1];
914+
915+
/*--- Initialize solution buffer with defaults ---*/
916+
su2double solutionBuffer[MAXNVAR] = {0.0};
917+
918+
/*--- Load solution variables using field-based lookup ---*/
919+
if (incompressible) {
920+
/*--- Incompressible flow: Pressure, Velocity_x, Velocity_y, [Velocity_z], [Temperature] ---*/
921+
922+
/*--- Load Pressure (index 0) ---*/
923+
if (fieldIdx_Pressure >= 0) {
924+
solutionBuffer[0] = Restart_Data[baseIndex + fieldIdx_Pressure];
925+
} else {
926+
/*--- Use default from config ---*/
927+
solutionBuffer[0] = config->GetPressure_FreeStreamND();
928+
if (rank == MASTER_NODE && counter == 0) {
929+
cout << "WARNING: Pressure field not found in restart file, using config default." << endl;
930+
}
931+
}
932+
933+
/*--- Load Velocity components (indices 1..nDim) ---*/
934+
const su2double* Velocity_Inf = config->GetVelocity_FreeStreamND();
935+
for (auto iDim = 0u; iDim < nDim; iDim++) {
936+
if (fieldIdx_Velocity[iDim] >= 0) {
937+
solutionBuffer[iDim + 1] = Restart_Data[baseIndex + fieldIdx_Velocity[iDim]];
938+
} else {
939+
/*--- Use default from config ---*/
940+
solutionBuffer[iDim + 1] = Velocity_Inf[iDim];
941+
if (rank == MASTER_NODE && counter == 0) {
942+
cout << "WARNING: Velocity_" << (iDim == 0 ? "x" : (iDim == 1 ? "y" : "z"))
943+
<< " field not found in restart file, using config default." << endl;
944+
}
945+
}
946+
}
947+
948+
/*--- Load Temperature (index nDim+1) if energy equation is enabled ---*/
949+
if (energy || weakly_coupled_heat || flamelet) {
950+
if (fieldIdx_Temperature >= 0) {
951+
solutionBuffer[nDim + 1] = Restart_Data[baseIndex + fieldIdx_Temperature];
952+
} else {
953+
/*--- Use default from config ---*/
954+
solutionBuffer[nDim + 1] = default_Temperature;
955+
}
956+
}
957+
} else {
958+
/*--- Compressible flow: Density, Momentum_x, Momentum_y, [Momentum_z], Energy ---*/
959+
960+
/*--- Load Density (index 0) ---*/
961+
if (fieldIdx_Density >= 0) {
962+
solutionBuffer[0] = Restart_Data[baseIndex + fieldIdx_Density];
963+
} else {
964+
solutionBuffer[0] = config->GetDensity_FreeStreamND();
965+
if (rank == MASTER_NODE && counter == 0) {
966+
cout << "WARNING: Density field not found in restart file, using config default." << endl;
967+
}
968+
}
969+
970+
/*--- Load Momentum components (indices 1..nDim) ---*/
971+
const su2double* Velocity_Inf_Comp = config->GetVelocity_FreeStreamND();
972+
for (auto iDim = 0u; iDim < nDim; iDim++) {
973+
if (fieldIdx_Momentum[iDim] >= 0) {
974+
solutionBuffer[iDim + 1] = Restart_Data[baseIndex + fieldIdx_Momentum[iDim]];
975+
} else {
976+
/*--- Compute from density and velocity defaults ---*/
977+
solutionBuffer[iDim + 1] = config->GetDensity_FreeStreamND() * Velocity_Inf_Comp[iDim];
978+
if (rank == MASTER_NODE && counter == 0) {
979+
cout << "WARNING: Momentum_" << (iDim == 0 ? "x" : (iDim == 1 ? "y" : "z"))
980+
<< " field not found in restart file, using config default." << endl;
981+
}
982+
}
983+
}
984+
985+
/*--- Load Energy (index nDim+1) ---*/
986+
if (fieldIdx_Energy >= 0) {
987+
solutionBuffer[nDim + 1] = Restart_Data[baseIndex + fieldIdx_Energy];
988+
} else {
989+
/*--- Compute from config defaults ---*/
990+
su2double vel2 = 0.0;
991+
for (auto iDim = 0u; iDim < nDim; iDim++) {
992+
su2double vel = Velocity_Inf_Comp[iDim];
993+
vel2 += vel * vel;
994+
}
995+
solutionBuffer[nDim + 1] = config->GetEnergy_FreeStreamND();
996+
if (rank == MASTER_NODE && counter == 0) {
997+
cout << "WARNING: Energy field not found in restart file, using config default." << endl;
998+
}
999+
}
8791000
}
880-
else {
881-
/*--- Used as buffer, allows defaults for nVar > nVar_Restart. ---*/
882-
for (auto iVar = 0u; iVar < nVar_Restart; iVar++)
883-
SolutionRestart[iVar] = Restart_Data[index + iVar];
1001+
1002+
/*--- Set solution from buffer ---*/
1003+
if (SolutionRestart == nullptr) {
1004+
for (auto iVar = 0u; iVar < nVar; iVar++)
1005+
nodes->SetSolution(iPoint_Local, iVar, solutionBuffer[iVar]);
1006+
} else {
1007+
for (auto iVar = 0u; iVar < nVar; iVar++)
1008+
SolutionRestart[iVar] = solutionBuffer[iVar];
8841009
nodes->SetSolution(iPoint_Local, SolutionRestart);
8851010
}
8861011

@@ -894,14 +1019,22 @@ void CFVMFlowSolverBase<V, R>::LoadRestart_impl(CGeometry **geometry, CSolver **
8941019
/*--- the grid velocities are set to 0. This is useful for FSI computations ---*/
8951020

8961021
/*--- Rewind the index to retrieve the Coords. ---*/
897-
index = counter * Restart_Vars[1];
1022+
auto index = baseIndex;
8981023
const auto* Coord = &Restart_Data[index];
8991024

9001025
su2double GridVel[MAXNDIM] = {0.0};
9011026
if (!steady_restart) {
902-
/*--- Move the index forward to get the grid velocities. ---*/
903-
index += skipVars + nVar_Restart + config->GetnTurbVar();
904-
for (auto iDim = 0u; iDim < nDim; iDim++) { GridVel[iDim] = Restart_Data[index+iDim]; }
1027+
/*--- Load grid velocities using field-based lookup ---*/
1028+
int fieldIdx_GridVel[MAXNDIM] = {-1, -1, -1};
1029+
for (auto iDim = 0u; iDim < nDim; iDim++) {
1030+
string gridVelName = "Grid_Velocity_" + string(iDim == 0 ? "x" : (iDim == 1 ? "y" : "z"));
1031+
fieldIdx_GridVel[iDim] = FindFieldIndex(gridVelName);
1032+
if (fieldIdx_GridVel[iDim] >= 0) {
1033+
GridVel[iDim] = Restart_Data[baseIndex + fieldIdx_GridVel[iDim]];
1034+
} else {
1035+
GridVel[iDim] = 0.0; /*--- Default to zero if not found ---*/
1036+
}
1037+
}
9051038
}
9061039

9071040
for (auto iDim = 0u; iDim < nDim; iDim++) {
@@ -915,7 +1048,7 @@ void CFVMFlowSolverBase<V, R>::LoadRestart_impl(CGeometry **geometry, CSolver **
9151048

9161049
if (static_fsi && update_geo) {
9171050
/*--- Rewind the index to retrieve the Coords. ---*/
918-
index = counter*Restart_Vars[1];
1051+
auto index = baseIndex;
9191052
const auto* Coord = &Restart_Data[index];
9201053

9211054
for (auto iDim = 0u; iDim < nDim; iDim++) {

SU2_CFD/include/solvers/CSolver.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3392,6 +3392,13 @@ class CSolver {
33923392
const CConfig *config,
33933393
string val_filename);
33943394

3395+
/*!
3396+
* \brief Find the index of a field in the restart file fields vector.
3397+
* \param[in] fieldName - Name of the field to find (with or without quotes).
3398+
* \return Index of the field (0-based, excluding PointID), or -1 if not found.
3399+
*/
3400+
int FindFieldIndex(const string& fieldName) const;
3401+
33953402
/*!
33963403
* \brief Read the metadata from a native SU2 restart file (ASCII or binary).
33973404
* \param[in] geometry - Geometrical definition of the problem.

SU2_CFD/src/solvers/CSolver.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,6 +2907,30 @@ void CSolver::Read_SU2_Restart_ASCII(CGeometry *geometry, const CConfig *config,
29072907

29082908
}
29092909

2910+
int CSolver::FindFieldIndex(const string& fieldName) const {
2911+
/*--- Search for the field name in the fields vector.
2912+
Fields are stored with quotes, e.g., "Temperature", so we need to check
2913+
both with and without quotes. The first field is "PointID" which we skip. ---*/
2914+
2915+
string fieldNameWithQuotes = "\"" + fieldName + "\"";
2916+
string fieldNameNoQuotes = fieldName;
2917+
2918+
/*--- Search starting from index 1 (skip PointID) ---*/
2919+
for (size_t i = 1; i < fields.size(); i++) {
2920+
string field = fields[i];
2921+
PrintingToolbox::trim(field);
2922+
2923+
/*--- Check if field matches (with or without quotes) ---*/
2924+
if (field == fieldNameWithQuotes || field == fieldNameNoQuotes) {
2925+
/*--- Return index excluding PointID (0-based) ---*/
2926+
return static_cast<int>(i - 1);
2927+
}
2928+
}
2929+
2930+
/*--- Field not found ---*/
2931+
return -1;
2932+
}
2933+
29102934
void CSolver::Read_SU2_Restart_Binary(CGeometry *geometry, const CConfig *config, string val_filename) {
29112935

29122936
char str_buf[CGNS_STRING_SIZE], fname[100];

SU2_CFD/src/solvers/CTurbSolver.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,26 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig*
135135

136136
if (incompressible && ((!energy) && (!weakly_coupled_heat) && (!flamelet))) skipVars--;
137137

138+
/*--- Determine number of turbulence variables in restart file ---*/
139+
/*--- Total vars in restart = coordinates + flow vars + turbulence vars + grid velocities ---*/
140+
unsigned short nVar_Restart = 0;
141+
if (Restart_Vars[1] > skipVars) {
142+
/*--- Estimate turbulence vars: total - skipVars, but cap at nVar ---*/
143+
nVar_Restart = min(static_cast<unsigned short>(Restart_Vars[1] - skipVars), nVar);
144+
}
145+
146+
/*--- Check if turbulence fields are present in restart file ---*/
147+
/*--- Note: This is a simplified check. Full field-based lookup would require
148+
knowing the specific turbulence model variable names (Nu_Tilde, Turb_Kin_Energy, etc.) ---*/
149+
bool turb_fields_missing = false;
150+
if (nVar_Restart < nVar) {
151+
turb_fields_missing = true;
152+
if (rank == MASTER_NODE) {
153+
cout << "\nWARNING: The restart file appears to be missing turbulence variables." << endl;
154+
cout << "Turbulence variables will be initialized from config defaults." << endl;
155+
}
156+
}
157+
138158
/*--- Load data from the restart into correct containers. ---*/
139159

140160
unsigned long counter = 0;
@@ -149,7 +169,18 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig*
149169
offset in the buffer of data from the restart file and load it. ---*/
150170

151171
const auto index = counter * Restart_Vars[1] + skipVars;
152-
for (auto iVar = 0u; iVar < nVar; iVar++) nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index + iVar]);
172+
173+
/*--- Load available turbulence variables ---*/
174+
for (auto iVar = 0u; iVar < nVar_Restart; iVar++) {
175+
nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index + iVar]);
176+
}
177+
178+
/*--- Initialize missing turbulence variables from defaults ---*/
179+
if (turb_fields_missing) {
180+
for (auto iVar = nVar_Restart; iVar < nVar; iVar++) {
181+
nodes->SetSolution(iPoint_Local, iVar, Solution_Inf[iVar]);
182+
}
183+
}
153184

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

0 commit comments

Comments
 (0)