Skip to content

Commit 950d272

Browse files
authored
Python source term for heat solver (#2626)
* python source term for heat solver
1 parent 8e8cc78 commit 950d272

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

SU2_CFD/include/solvers/CHeatSolver.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,17 @@ class CHeatSolver final : public CScalarSolver<CHeatVariable> {
196196
unsigned short iMesh,
197197
unsigned short iRKStep) override;
198198

199+
/*!
200+
* \brief Source term computation.
201+
* \param[in] geometry - Geometrical definition of the problem.
202+
* \param[in] solver_container - Container vector with all the solutions.
203+
* \param[in] numerics_container - Description of the numerical method.
204+
* \param[in] config - Definition of the particular problem.
205+
* \param[in] iMesh - Index of the mesh in multigrid computations.
206+
*/
207+
void Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics **numerics_container,
208+
CConfig *config, unsigned short iMesh) override ;
209+
199210

200211
void Set_Heatflux_Areas(CGeometry *geometry, CConfig *config) override;
201212

SU2_CFD/src/solvers/CHeatSolver.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,20 @@ void CHeatSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_contain
311311
}
312312
}
313313

314+
void CHeatSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics **numerics_container,
315+
CConfig *config, unsigned short iMesh) {
316+
317+
/*--- Regular source terms go here. ---*/
318+
/*--- ... ---*/
319+
320+
/*--- Custom user defined source term (from the python wrapper) ---*/
321+
if (config->GetPyCustomSource()) {
322+
CustomSourceResidual(geometry, solver_container, numerics_container, config, iMesh);
323+
}
324+
325+
}
326+
327+
314328
void CHeatSolver::Set_Heatflux_Areas(CGeometry *geometry, CConfig *config) {
315329

316330
BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS {

TestCases/parallel_regression.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,17 @@ def main():
15341534
pywrapper_zimont.command = TestCase.Command("mpirun -np 2", "python", "run.py")
15351535
test_list.append(pywrapper_zimont)
15361536

1537+
1538+
# Heat solver unsteady with source
1539+
pywrapper_Unst_Heat_Source = TestCase('pywrapper_Unst_Heat_Source')
1540+
pywrapper_Unst_Heat_Source.cfg_dir = "py_wrapper/custom_heat_source"
1541+
pywrapper_Unst_Heat_Source.cfg_file = "run.py"
1542+
pywrapper_Unst_Heat_Source.test_iter = 10
1543+
pywrapper_Unst_Heat_Source.unsteady = True
1544+
pywrapper_Unst_Heat_Source.test_vals = [-5.235402, 300.010000, 300.000000]
1545+
pywrapper_Unst_Heat_Source.command = TestCase.Command("mpirun -n 2", "python", "run.py")
1546+
test_list.append(pywrapper_Unst_Heat_Source)
1547+
15371548
##############################################
15381549
### Method of Manufactured Solutions (MMS) ###
15391550
##############################################
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env python
2+
3+
## \file run.py
4+
# \brief Unsteady heat transfer case with custom source term.
5+
# \version 8.3.0 "Harrier"
6+
#
7+
# SU2 Project Website: https://su2code.github.io
8+
#
9+
# The SU2 Project is maintained by the SU2 Foundation
10+
# (http://su2foundation.org)
11+
#
12+
# Copyright 2012-2025, SU2 Contributors (cf. AUTHORS.md)
13+
#
14+
# SU2 is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU Lesser General Public
16+
# License as published by the Free Software Foundation; either
17+
# version 2.1 of the License, or (at your option) any later version.
18+
#
19+
# SU2 is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22+
# Lesser General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU Lesser General Public
25+
# License along with SU2. If not, see <http://www.gnu.org/licenses/>.
26+
27+
from mpi4py import MPI
28+
import sys
29+
import pysu2 # imports the SU2 wrapped module
30+
31+
common_settings = """
32+
SOLVER= HEAT_EQUATION
33+
INC_NONDIM= DIMENSIONAL
34+
35+
TIME_DOMAIN= YES
36+
TIME_STEP= 0.002
37+
TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER
38+
39+
FREESTREAM_TEMPERATURE= 300
40+
MATERIAL_DENSITY= 1000
41+
SPECIFIC_HEAT_CP = 500
42+
THERMAL_CONDUCTIVITY_CONSTANT= 10.0
43+
44+
MARKER_HEATFLUX= ( x_minus, 0, x_plus, 0, y_minus, 0, y_plus, 0 )
45+
MARKER_PYTHON_CUSTOM= ( x_minus, x_plus, y_minus, y_plus )
46+
MARKER_MONITORING= ( x_minus, x_plus, y_minus, y_plus )
47+
48+
PYTHON_CUSTOM_SOURCE= YES
49+
50+
NUM_METHOD_GRAD= GREEN_GAUSS
51+
CFL_NUMBER= 100
52+
53+
LINEAR_SOLVER= CONJUGATE_GRADIENT
54+
DISCADJ_LIN_SOLVER= CONJUGATE_GRADIENT
55+
LINEAR_SOLVER_PREC= ILU
56+
DISCADJ_LIN_PREC= ILU
57+
LINEAR_SOLVER_ERROR= 1E-5
58+
LINEAR_SOLVER_ITER= 100
59+
60+
MESH_FORMAT= RECTANGLE
61+
MESH_BOX_SIZE= ( 33, 33, 0 )
62+
MESH_BOX_LENGTH= ( __SIZE__, __SIZE__, 0 )
63+
64+
OUTPUT_FILES= RESTART, PARAVIEW
65+
OUTPUT_WRT_FREQ= 100,100
66+
OBJECTIVE_FUNCTION= AVG_TEMPERATURE
67+
68+
INNER_ITER= 20
69+
CONV_RESIDUAL_MINVAL= -4
70+
CONV_STARTITER= 2
71+
MAX_TIME= 10.0
72+
TIME_ITER= 101
73+
"""
74+
75+
primal_settings = """
76+
MATH_PROBLEM= DIRECT
77+
SCREEN_OUTPUT= TIME_ITER, CUR_TIME, INNER_ITER, RMS_RES, LINSOL, AVG_TEMPERATURE, TAVG_AVG_TEMPERATURE
78+
HISTORY_OUTPUT= ITER, RMS_RES, HEAT, TAVG_HEAT
79+
"""
80+
81+
def HeatSource(time, driver, iPoint):
82+
"""Applies a source in the lower left quadrant for a period of time."""
83+
allCoords = driver.Coordinates()
84+
coord = allCoords.Get(iPoint)
85+
x = coord[0]
86+
y = coord[1]
87+
xp = 0.0125
88+
yp = 0.0125
89+
R = 0.0125
90+
Source = 0.0
91+
if (time > 0.0):
92+
if ((x-xp)*(x-xp) + (y-yp)*(y-yp) < R*R):
93+
Source = 100.0
94+
95+
return Source
96+
97+
def RunPrimal(size):
98+
"""
99+
Run the heat solver with a custom heat source.
100+
Returns the final average boundary temperature.
101+
"""
102+
comm = MPI.COMM_WORLD
103+
rank = comm.Get_rank()
104+
105+
if rank == 0:
106+
with open('config_unsteady.cfg', 'w') as f:
107+
f.write(common_settings.replace('__SIZE__', str(size)) + primal_settings)
108+
print("\n------------------------------ Begin Solver -----------------------------\n")
109+
sys.stdout.flush()
110+
111+
comm.Barrier()
112+
113+
# Initialize the corresponding driver of SU2, this includes solver preprocessing
114+
try:
115+
driver = pysu2.CSinglezoneDriver("config_unsteady.cfg", 1, comm)
116+
except TypeError as exception:
117+
print('A TypeError occured in pysu2.CDriver : ',exception)
118+
raise
119+
120+
# Run the time loop in python to vary the heat flux.
121+
dt = driver.GetUnsteadyTimeStep()
122+
123+
iHEATSOLVER = driver.GetSolverIndices()['HEAT']
124+
Source = driver.UserDefinedSource(iHEATSOLVER)
125+
126+
127+
for time_iter in range(driver.GetNumberTimeIter()):
128+
# set the source term, per point
129+
for i_node in range(driver.GetNumberNodes() - driver.GetNumberHaloNodes()):
130+
# add source term:
131+
S = HeatSource(time_iter * dt, driver, i_node)
132+
Source.Set(i_node, 0, S)
133+
134+
135+
driver.Preprocess(time_iter)
136+
137+
# Run one time iteration.
138+
driver.Run()
139+
driver.Postprocess()
140+
driver.Update()
141+
142+
# Monitor the solver and output solution to file if required.
143+
driver.Monitor(time_iter)
144+
driver.Output(time_iter)
145+
146+
# Get the final average temperature.
147+
avg_temperature = driver.GetOutputValue('AVG_TEMPERATURE')
148+
149+
# Finalize the solver and exit cleanly.
150+
driver.Finalize()
151+
152+
return avg_temperature
153+
154+
155+
def main():
156+
157+
RunPrimal(0.1)
158+
159+
if __name__ == '__main__':
160+
main()

0 commit comments

Comments
 (0)