|
| 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