Skip to content

Commit a87a1ed

Browse files
authored
Add improvements, bug fixes, + notes from j-signorelli/su2-precice-pywrapper (#34)
* Nondimensional mode implementation * Fix compilation w/ OMP bug * Specify problem dimension as argument * Clarify meaning of Monitor * Save time and iter for implicit coupling * Fix CHT initial read/write (was misleading) (read_data --> write_data) * Add disclaimer/note on restarting simulations
1 parent 6540312 commit a87a1ed

File tree

4 files changed

+76
-18
lines changed

4 files changed

+76
-18
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ mpirun -n 8 python3 SU2_preCICE_CHT.py -f SU2_config_file.cfg --parallel
166166

167167
**NOTE**: As of SU2 v7.5.1: Deforming `MARKER_EULER`'s are buggy when simulations are run in parallel, leading to unexpected results. More information can be found at this discussion here: https://github.com/su2code/SU2/discussions/1931.
168168

169-
### Further notes
169+
## Important note on restarts
170+
171+
This code **has not been tested** for restarts using initializations *from* SU2. Any restarted simulations should have SU2 be the first participant and receive initialization data. It is possible that, if SU2 must send initialization data, that it is incorrect (it may use default values in the config file, or just be zeros if the data hasn't been computed until after/during a first iteration). Admittedly, this is from a lack of understanding of the specifics of how SU2 operates and there may not be a trivial work-around.
172+
173+
## Further notes
170174

171175
Result files (vtu) generated from SU2 might be incompatible with your ParaView version. For example, ParaView 5.11.2 on Ubuntu 22.04 is known to fail with SU2 7.5.1 result files, but ParaView 5.12 works.
172176

replacement_files/python_wrapper_structure.cpp

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,41 @@ void CDriver::PythonInterface_Preprocessing(CConfig **config, CGeometry ****geom
4747
if (rank == MASTER_NODE) cout << "Setting customized boundary conditions for zone " << iZone << endl;
4848
for (iMesh = 0; iMesh <= config[iZone]->GetnMGLevels(); iMesh++) {
4949
geometry[iZone][INST_0][iMesh]->SetCustomBoundary(config[iZone]);
50+
// preCICE: Update input file initial custom boundary temperature/HF to be nondimensional.
51+
// Was fixed in SU2 v8 here: https://github.com/su2code/SU2/pull/2078
52+
//------------------------------------------------------------------------------------------------
53+
// Basically just copied + pasted (terrible coding but as a quick/least invasive fix) CGeometry::SetCustomBoundary
54+
unsigned short iMarker;
55+
unsigned long iVertex;
56+
string Marker_Tag;
57+
58+
for(iMarker=0; iMarker < geometry[iZone][INST_0][iMesh]->GetnMarker(); iMarker++){
59+
Marker_Tag = config[iZone]->GetMarker_All_TagBound(iMarker);
60+
if(config[iZone]->GetMarker_All_PyCustom(iMarker)){
61+
switch(config[iZone]->GetMarker_All_KindBC(iMarker)){
62+
case HEAT_FLUX:
63+
for(iVertex=0; iVertex < geometry[iZone][INST_0][iMesh]->GetnVertex(iMarker); iVertex++){
64+
geometry[iZone][INST_0][iMesh]->SetCustomBoundaryHeatFlux(iMarker, iVertex, config[iZone]->GetWall_HeatFlux(Marker_Tag)/config[iZone]->GetHeat_Flux_Ref());
65+
}
66+
break;
67+
case ISOTHERMAL:
68+
for(iVertex=0; iVertex < geometry[iZone][INST_0][iMesh]->GetnVertex(iMarker); iVertex++){
69+
geometry[iZone][INST_0][iMesh]->SetCustomBoundaryTemperature(iMarker, iVertex, config[iZone]->GetIsothermal_Temperature(Marker_Tag)/config[iZone]->GetTemperature_Ref());
70+
}
71+
break;
72+
case INLET_FLOW:
73+
// This case is handled in the solver class.
74+
break;
75+
default:
76+
cout << "WARNING: Marker " << Marker_Tag << " is not customizable. Using default behavior." << endl;
77+
break;
78+
}
79+
}
80+
}
81+
//-------------------------------------------------------------------------------------------------
5082
}
83+
84+
5185
geometry[iZone][INST_0][MESH_0]->UpdateCustomBoundaryConditions(geometry[iZone][INST_0], config[iZone]);
5286

5387
if ((config[iZone]->GetKind_Solver() == MAIN_SOLVER::EULER) ||
@@ -491,7 +525,7 @@ void CDriver::FinalizeMESH_SOL() {
491525
const bool secondOrder = config_container[ZONE_0]->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND;
492526
const su2double invTimeStep = 1.0 / config_container[ZONE_0]->GetDelta_UnstTimeND();
493527

494-
SU2_OMP_FOR_STAT(omp_chunk_size)
528+
//SU2_OMP_FOR_STAT(omp_chunk_size) - omp_chunk_size part of CMeshSolver
495529
for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) {
496530

497531
/*--- Coordinates of the current point at n+1, n, & n-1 time levels. ---*/
@@ -513,7 +547,7 @@ void CDriver::FinalizeMESH_SOL() {
513547
geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetGridVel(iPoint, iDim, GridVel);
514548
}
515549
}
516-
END_SU2_OMP_FOR
550+
//END_SU2_OMP_FOR
517551

518552
for (auto iMGlevel = 1u; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++)
519553
geometry_container[ZONE_0][INST_0][iMGlevel]->SetRestricted_GridVelocity(geometry_container[ZONE_0][INST_0][iMGlevel-1]);
@@ -635,13 +669,15 @@ passivedouble CDriver::GetVertexTemperature(unsigned short iMarker, unsigned lon
635669
vertexWallTemp = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetTemperature(iPoint);
636670
}
637671

638-
return SU2_TYPE::GetValue(vertexWallTemp);
672+
//preCICE: re-dimensionalize before returning
673+
return SU2_TYPE::GetValue(vertexWallTemp * config_container[ZONE_0]->GetTemperature_Ref());
639674

640675
}
641676

642677
void CDriver::SetVertexTemperature(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallTemp){
643678

644-
geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryTemperature(iMarker, iVertex, val_WallTemp);
679+
// preCICE: non-dimensionalize before setting
680+
geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryTemperature(iMarker, iVertex, val_WallTemp / config_container[ZONE_0]->GetTemperature_Ref());
645681
}
646682

647683
vector<passivedouble> CDriver::GetVertexHeatFluxes(unsigned short iMarker, unsigned long iVertex) const {
@@ -671,9 +707,10 @@ vector<passivedouble> CDriver::GetVertexHeatFluxes(unsigned short iMarker, unsig
671707
}
672708
}
673709

674-
HeatFluxPassive[0] = SU2_TYPE::GetValue(HeatFlux[0]);
675-
HeatFluxPassive[1] = SU2_TYPE::GetValue(HeatFlux[1]);
676-
HeatFluxPassive[2] = SU2_TYPE::GetValue(HeatFlux[2]);
710+
//preCICE: re-dimensionalize before returning
711+
HeatFluxPassive[0] = SU2_TYPE::GetValue(HeatFlux[0] * config_container[ZONE_0]->GetHeat_Flux_Ref());
712+
HeatFluxPassive[1] = SU2_TYPE::GetValue(HeatFlux[1] * config_container[ZONE_0]->GetHeat_Flux_Ref());
713+
HeatFluxPassive[2] = SU2_TYPE::GetValue(HeatFlux[2] * config_container[ZONE_0]->GetHeat_Flux_Ref());
677714

678715
return HeatFluxPassive;
679716
}
@@ -718,12 +755,14 @@ passivedouble CDriver::GetVertexNormalHeatFlux(unsigned short iMarker, unsigned
718755
vertexWallHeatFlux = -thermal_conductivity*dTdn;
719756
}
720757

721-
return SU2_TYPE::GetValue(vertexWallHeatFlux);
758+
//preCICE: re-dimensionalize before returning
759+
return SU2_TYPE::GetValue(vertexWallHeatFlux * config_container[ZONE_0]->GetHeat_Flux_Ref());
722760
}
723761

724762
void CDriver::SetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallHeatFlux){
725763

726-
geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryHeatFlux(iMarker, iVertex, val_WallHeatFlux);
764+
// preCICE: non-dimensionalize before setting
765+
geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryHeatFlux(iMarker, iVertex, val_WallHeatFlux / config_container[ZONE_0]->GetHeat_Flux_Ref());
727766
}
728767

729768
passivedouble CDriver::GetThermalConductivity(unsigned short iMarker, unsigned long iVertex) const {

run/SU2_preCICE_CHT.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ def main():
5555
parser.add_option("-c", "--precice-config", dest="precice_config", help="Specify preCICE config file", default="../precice-config.xml")
5656
parser.add_option("-m", "--precice-mesh", dest="precice_mesh", help="Specify the preCICE mesh name", default="Fluid-Mesh")
5757
parser.add_option("-r", "--precice-reverse", action="store_true", dest="precice_reverse", help="Include flag to have SU2 write temperature, read heat flux", default=False)
58-
58+
59+
# Dimension
60+
parser.add_option("-d", "--dimension", dest="nDim", help="Dimension of fluid domain", type="int", default=3)
61+
5962
(options, args) = parser.parse_args()
60-
options.nDim = int(2) # Specify dimension here
6163
options.nZone = int(1) # Specify number of zones here (1)
6264

6365
# Import mpi4py for parallel run
@@ -177,9 +179,9 @@ def main():
177179
if (interface.is_action_required(precice.action_write_initial_data())):
178180

179181
for i, iVertex in enumerate(iVertices_CHTMarker_PHYS):
180-
read_data[i] = GetInitialFxn(CHTMarkerID, iVertex)
182+
write_data[i] = GetInitialFxn(CHTMarkerID, iVertex)
181183

182-
interface.write_block_scalar_data(write_data_id, vertex_ids, read_data)
184+
interface.write_block_scalar_data(write_data_id, vertex_ids, write_data)
183185
interface.mark_action_fulfilled(precice.action_write_initial_data())
184186

185187
interface.initialize_data()
@@ -194,13 +196,16 @@ def main():
194196
if options.with_MPI == True:
195197
comm.Barrier()
196198

197-
199+
precice_saved_time = 0
200+
precice_saved_iter = 0
198201
while (interface.is_coupling_ongoing()):
199202

200203
# Implicit coupling
201204
if (interface.is_action_required(precice.action_write_iteration_checkpoint())):
202205
# Save the state
203206
SU2Driver.SaveOldState()
207+
precice_saved_time = time
208+
precice_saved_iter = TimeIter
204209
interface.mark_action_fulfilled(precice.action_write_iteration_checkpoint())
205210

206211
if (interface.is_read_data_available()):
@@ -234,7 +239,7 @@ def main():
234239
# Update the solver for the next time iteration
235240
SU2Driver.Update()
236241

237-
# Monitor the solver and output solution to file if required
242+
# Monitor the solver
238243
stopCalc = SU2Driver.Monitor(TimeIter)
239244

240245
if (interface.is_write_data_required(deltaT)):
@@ -253,6 +258,8 @@ def main():
253258
if (interface.is_action_required(precice.action_read_iteration_checkpoint())):
254259
# Reload old state
255260
SU2Driver.ReloadOldState()
261+
time = precice_saved_time
262+
TimeIter = precice_saved_iter
256263
interface.mark_action_fulfilled(precice.action_read_iteration_checkpoint())
257264
else: # Output and increment as usual
258265
SU2Driver.Output(TimeIter)

run/SU2_preCICE_FSI.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ def main():
5555
parser.add_option("-c", "--precice-config", dest="precice_config", help="Specify preCICE config file", default="../precice-config.xml")
5656
parser.add_option("-m", "--precice-mesh", dest="precice_mesh", help="Specify the preCICE mesh name", default="Fluid-Mesh")
5757

58+
# Dimension
59+
parser.add_option("-d", "--dimension", dest="nDim", help="Dimension of fluid domain", type="int", default=3)
60+
5861
(options, args) = parser.parse_args()
59-
options.nDim = int(2)
6062
options.nZone = int(1)
6163

6264
# Import mpi4py for parallel run
@@ -180,12 +182,16 @@ def main():
180182
if options.with_MPI == True:
181183
comm.Barrier()
182184

185+
precice_saved_time = 0
186+
precice_saved_iter = 0
183187
while (interface.is_coupling_ongoing()):#(TimeIter < nTimeIter):
184188

185189
# Implicit coupling
186190
if (interface.is_action_required(precice.action_write_iteration_checkpoint())):
187191
# Save the state
188192
SU2Driver.SaveOldState()
193+
precice_saved_time = time
194+
precice_saved_iter = TimeIter
189195
interface.mark_action_fulfilled(precice.action_write_iteration_checkpoint())
190196

191197
if (interface.is_read_data_available()):
@@ -220,7 +226,7 @@ def main():
220226
# Update the solver for the next time iteration
221227
SU2Driver.Update()
222228

223-
# Monitor the solver and output solution to file if required
229+
# Monitor the solver
224230
stopCalc = SU2Driver.Monitor(TimeIter)
225231

226232

@@ -241,6 +247,8 @@ def main():
241247
if (interface.is_action_required(precice.action_read_iteration_checkpoint())):
242248
# Reload old state
243249
SU2Driver.ReloadOldState()
250+
time = precice_saved_time
251+
TimeIter = precice_saved_iter
244252
interface.mark_action_fulfilled(precice.action_read_iteration_checkpoint())
245253
else: # Output and increment as usual
246254
SU2Driver.Output(TimeIter)

0 commit comments

Comments
 (0)