|
1 | | -# FADO script: Shape Optimization with Species Variance OF |
| 1 | +# FADO script: Shape Optimization with pressure drop minimization |
2 | 2 |
|
3 | 3 | from FADO import * |
| 4 | +from timeit import default_timer as timer |
4 | 5 | import glob |
5 | 6 | import time |
6 | 7 | import os |
7 | | - |
| 8 | +import subprocess |
8 | 9 | # get the path to su2 executable |
9 | 10 | su2_run= os.environ["SU2_RUN"] + "/" |
10 | 11 | print("SU2 executable obtained from ", su2_run) |
11 | 12 |
|
12 | | -# Define a few often used variables |
| 13 | +# Some settings that depend on the case |
| 14 | + |
| 15 | +# nr of cores for mpi |
| 16 | +ncores="8" |
| 17 | + |
13 | 18 | configMaster="sudo.cfg" |
14 | 19 | meshName="sudo_coarse_FFD.su2" |
15 | 20 | # inlet BC file |
16 | 21 | inletName="inlet.dat" |
17 | 22 | restartAdjName="solution_adj_dp.csv" |
18 | 23 |
|
| 24 | +configCopy = "config.cfg" |
| 25 | +# first, copy sudo.cfg to a copy config.cfg that is allowed to be altered. |
| 26 | +copy_command = ['cp', configMaster, configCopy] |
| 27 | +subprocess.run(copy_command) |
| 28 | + |
19 | 29 | # Design variables ----------------------------------------------------- # |
20 | 30 |
|
21 | 31 | # important, this has to match the nr of variables |
22 | 32 | # 6 x 6 x 6 = 216 |
23 | | -# x,y = 432 |
24 | 33 | # x,y,z = 648 |
25 | | -#minus the 6x6=36 nodes of the symmetry plane |
26 | | -nDV = 648-36-36 |
27 | | -# nr of cores for mpi |
28 | | -ncores="8" |
| 34 | +NDIM = 3 |
| 35 | +DX = 6 |
| 36 | +nDV = DX * DX * DX * NDIM |
29 | 37 |
|
30 | 38 | # define the objective |
31 | 39 | objective = 'Surface_Pressure_Drop' |
32 | 40 |
|
33 | | -######################################################################################################### |
34 | | -ffd = InputVariable(0.0,PreStringHandler("DV_VALUE="),nDV) |
| 41 | +# start the time! |
| 42 | +start = timer() |
35 | 43 |
|
36 | 44 | # |
37 | 45 | # Note that the last two numbers are the bounds, reduce if you want to limit the maximum deformation |
38 | 46 | ######################################################################################################### |
39 | 47 | ffd = InputVariable(np.zeros((nDV,)),ArrayLabelReplacer("__FFD_PTS__"), 0, np.ones(nDV), -0.10,0.10) |
40 | 48 | ######################################################################################################### |
41 | 49 |
|
42 | | -# Parameters ----------------------------------------------------------- # |
43 | 50 |
|
44 | | -# The master config `configMaster.cfg` serves as an SU2 adjoint regression test. |
45 | | -# For a correct gradient validation we need to exchange some options |
| 51 | +# ##### create string for DV_KIND ##### # |
| 52 | +s = "FFD_CONTROL_POINT" |
| 53 | +ffd_string = s |
| 54 | +for i in range((DX**NDIM)*NDIM - 1): |
| 55 | + ffd_string = ffd_string + ", " + s |
| 56 | + |
| 57 | + |
| 58 | +# ##### create string for DV_PARAM ##### # |
| 59 | + |
| 60 | +dv_param_string="" |
| 61 | +for idim in range(NDIM): |
| 62 | + xdim = ydim = zdim = "0.0" |
| 63 | + if (idim==0): xdim="1.0" |
| 64 | + elif (idim==1): ydim="1.0" |
| 65 | + elif (idim==2): zdim="1.0" |
| 66 | + for k in range(DX): |
| 67 | + for j in range(DX): |
| 68 | + for i in range(DX): |
| 69 | + s = "( BOX, " + str(i) + ", " + str(j) + ", " + str(k) + ", " + xdim + ", " + ydim + ", " + zdim + " );" |
| 70 | + dv_param_string += s |
| 71 | + |
| 72 | +# remove last semicolon |
| 73 | +dv_param_string = dv_param_string[:-1] |
| 74 | + |
| 75 | + |
| 76 | +# do not move FFD box nodes in vertical direction (bottom face with j=0 only ) |
| 77 | +# we remove 6*6=36 d.o.f. |
| 78 | +nDV = nDV - 2*DX*DX |
| 79 | +ffd_string.replace(s+", ","",2*DX*DX) |
| 80 | + |
| 81 | + |
| 82 | +# for bottom plane (j=0 and j=1) remove the entries that have (0.0,1.0,0.0) d.o.f. |
| 83 | +jlist = [0,1] |
| 84 | +dof = "0.0, 1.0, 0.0" |
| 85 | + |
| 86 | +for j in jlist: |
| 87 | + for k in range(DX): |
| 88 | + for i in range(DX): |
| 89 | + remove_dof = "( BOX, " + str(i) + ", " + str(j) + ", " + str(k) + ", " + dof + " )" |
| 90 | + print("removing ", remove_dof) |
| 91 | + dv_param_string = dv_param_string.replace(remove_dof+";", "", 1) |
| 92 | + # in case the plane is at the end, the string does not have a semicolon |
| 93 | + dv_param_string = dv_param_string.replace(remove_dof, "", 1) |
| 94 | + |
| 95 | + |
| 96 | +replace_dv_kind = Parameter([ffd_string], LabelReplacer("__FFD_CTRL_PTS__")) |
| 97 | +replace_dv_param =Parameter([dv_param_string], LabelReplacer("__FFD_PARAM__")) |
| 98 | + |
| 99 | +ffd = InputVariable(np.zeros((nDV,)),ArrayLabelReplacer("__FFD_PTS__"), 0, np.ones(nDV), -0.10,0.10) |
| 100 | + |
| 101 | +# Parameters ----------------------------------------------------------- # |
46 | 102 |
|
47 | 103 | # switch from direct to adjoint mode and adapt settings. |
48 | 104 | enable_direct = Parameter([""], LabelReplacer("%__DIRECT__")) |
|
55 | 111 | if objective == 'Uniformity': |
56 | 112 | print("1. set parameter for Uniformity") |
57 | 113 | enable_obj = Parameter(["SURFACE_UNIFORMITY"], LabelReplacer("__OBJ_FUNC__")) |
| 114 | + objstring="uniformity" |
58 | 115 |
|
59 | 116 | elif objective == 'Surface_Pressure_Drop': |
60 | 117 | print("1. set parameter for Surface_Pressure_Drop") |
61 | 118 | enable_obj = Parameter(["SURFACE_PRESSURE_DROP"], LabelReplacer("__OBJ_FUNC__")) |
| 119 | + objstring = "dp" |
62 | 120 |
|
63 | 121 | else: |
64 | 122 | raise Exception("no valid objective found.") |
65 | 123 |
|
| 124 | + |
| 125 | + |
66 | 126 | print(" ") |
67 | 127 | print("Running validation for", objective) |
68 | 128 |
|
| 129 | +# after the first iteration, we switch from restart=no to restart=yes, then update original cfg file |
| 130 | +restart_yes="sed -i 's/RESTART_SOL= NO/RESTART_SOL= YES/' config.cfg && cp " + configCopy + " ../../" |
69 | 131 |
|
70 | 132 | # Evaluations ---------------------------------------------------------- # |
71 | 133 |
|
72 | | -def_command = "mpirun -n " + ncores + " " + su2_run + "SU2_DEF " + configMaster |
73 | | -cfd_command = "mpirun -n " + ncores + " " + su2_run + "SU2_CFD " + configMaster + "; pwd; cp restart.csv ../../restart.csv" |
74 | | -cfd_ad_command = "mpirun -n " + ncores + " " + su2_run + "SU2_CFD_AD " + configMaster |
75 | | -dot_ad_command = "mpirun -n " + ncores + " " + su2_run + "SU2_DOT_AD " + configMaster |
| 134 | +def_command = "mpirun -n " + ncores + " " + su2_run + "SU2_DEF " + configCopy |
| 135 | +cfd_command = "mpirun -n " + ncores + " " + su2_run + "SU2_CFD " + configCopy |
| 136 | +cfd_ad_command = "mpirun -n " + ncores + " " + su2_run + "SU2_CFD_AD " + configCopy |
| 137 | +cfd_command = "mpirun -n " + ncores + " " + su2_run + "SU2_CFD " + configCopy + " && cp restart.csv ../../solution.csv" |
| 138 | +cfd_ad_command = "mpirun -n " + ncores + " " + su2_run + "SU2_CFD_AD " + configCopy + " && cp restart_adj_" + objstring + ".csv ../../solution_adj_"+objstring+".csv" |
| 139 | +dot_ad_command = "mpirun -n " + ncores + " " + su2_run + "SU2_DOT_AD " + configCopy |
| 140 | + |
| 141 | +# global iteration |
| 142 | +global_iter = 0 |
| 143 | + |
76 | 144 |
|
77 | 145 | max_tries = 1 |
78 | 146 |
|
79 | | -# mesh deformation |
| 147 | +# mesh deformation, running in subdirectory DEFORM |
80 | 148 | deform = ExternalRun("DEFORM",def_command,True) # True means sym links are used for addData |
81 | 149 | deform.setMaxTries(max_tries) |
82 | | -deform.addConfig(configMaster) |
| 150 | +deform.addConfig(configCopy) |
83 | 151 | deform.addData(meshName) |
84 | 152 | deform.addData(inletName) |
85 | 153 | deform.addExpected("mesh_out.su2") |
| 154 | +deform.addParameter(replace_dv_kind) |
| 155 | +deform.addParameter(replace_dv_param) |
86 | 156 | deform.addParameter(enable_def) |
87 | 157 | deform.addParameter(enable_obj) |
88 | 158 |
|
89 | | -# direct run |
| 159 | +# direct run, running in subdirectory DIRECT |
90 | 160 | direct = ExternalRun("DIRECT",cfd_command,True) |
91 | 161 | direct.setMaxTries(max_tries) |
92 | | -direct.addConfig(configMaster) |
| 162 | +direct.addConfig(configCopy) |
93 | 163 | direct.addData("DEFORM/mesh_out.su2",destination=meshName) |
94 | 164 | direct.addData(inletName) |
95 | 165 | direct.addData("solution.csv") |
96 | 166 | direct.addExpected("restart.csv") |
| 167 | +direct.addParameter(replace_dv_kind) |
| 168 | +direct.addParameter(replace_dv_param) |
97 | 169 | direct.addParameter(enable_direct) |
98 | 170 | direct.addParameter(enable_not_def) |
99 | 171 | direct.addParameter(enable_obj) |
100 | 172 |
|
101 | | -# adjoint run |
| 173 | +# adjoint run, running in subdorectory ADJOINT |
102 | 174 | adjoint = ExternalRun("ADJOINT",cfd_ad_command,True) |
103 | 175 | adjoint.setMaxTries(max_tries) |
104 | | -adjoint.addConfig(configMaster) |
| 176 | +adjoint.addConfig(configCopy) |
105 | 177 | adjoint.addData("DEFORM/mesh_out.su2", destination=meshName) |
106 | 178 | adjoint.addData(inletName) |
107 | 179 | adjoint.addData(restartAdjName) |
108 | 180 | # add primal solution file |
109 | 181 | adjoint.addData("DIRECT/restart.csv", destination="solution.csv") |
| 182 | +adjoint.addParameter(replace_dv_kind) |
| 183 | +adjoint.addParameter(replace_dv_param) |
110 | 184 |
|
111 | 185 | if objective == 'Uniformity': |
112 | 186 | print("2. set adjoint for Uniformity") |
|
123 | 197 | adjoint.addParameter(enable_not_def) |
124 | 198 | adjoint.addParameter(enable_obj) |
125 | 199 |
|
126 | | -# gradient projection |
| 200 | +# gradient projection, running in subdirectory DOT |
127 | 201 | dot = ExternalRun("DOT",dot_ad_command,True) |
128 | 202 | dot.setMaxTries(max_tries) |
129 | | -dot.addConfig(configMaster) |
| 203 | +dot.addConfig(configCopy) |
130 | 204 | dot.addData("DEFORM/mesh_out.su2", destination=meshName) |
131 | 205 | dot.addData(inletName) |
| 206 | +dot.addParameter(replace_dv_kind) |
| 207 | +dot.addParameter(replace_dv_param) |
132 | 208 | print("Objective = ",objective) |
133 | 209 |
|
134 | 210 | if objective == 'Uniformity': |
|
147 | 223 | dot.addParameter(enable_obj) # necessary for correct file extension |
148 | 224 |
|
149 | 225 | # update restart file |
150 | | -#update_restart = ExternalRun(".",update_restart_command,False) # True means sym links are used for addData |
151 | | - |
152 | | - |
| 226 | +update_restart = ExternalRun("UPDATE_RESTART",restart_yes,False) # True means sym links are used for addData |
| 227 | +update_restart.addData(configCopy) |
153 | 228 |
|
154 | 229 | # Functions ------------------------------------------------------------ # |
155 | 230 | # |
|
168 | 243 | func_surfdp.addValueEvalStep(deform) |
169 | 244 | func_surfdp.addValueEvalStep(direct) |
170 | 245 | func_surfdp.addGradientEvalStep(adjoint) |
| 246 | +func_surfdp.addGradientEvalStep(update_restart) |
171 | 247 | func_surfdp.addGradientEvalStep(dot) |
172 | 248 | func_surfdp.setDefaultValue(0.0) |
173 | 249 |
|
|
205 | 281 | # SOFT = if func eval fails, just the default val will be taken |
206 | 282 | driver.setFailureMode("SOFT") |
207 | 283 |
|
208 | | -# file containing the objective values per design iteration |
| 284 | +# Define the filename containing the objective values per design iteration |
209 | 285 | his = open("optim.csv","w",1) |
210 | 286 | driver.setHistorian(his) |
211 | 287 |
|
|
217 | 293 | x = driver.getInitial() |
218 | 294 |
|
219 | 295 | # disp:True prints convergence messages |
220 | | -# maxiter: int limits the optimization to maxiter number of iterations |
| 296 | +# maxiter: number of (true) design iterations that will be run |
221 | 297 | # ftol: precision tolerance goal for the value of f in the stopping criterion |
222 | | -options = {'disp': True, 'ftol': 1e-10, 'maxiter': 10} |
| 298 | +options = {'disp': True, 'ftol': 1e-10, 'maxiter': 5} |
223 | 299 |
|
224 | 300 | # Use Sequential Least Squares Programming SLSQP |
225 | 301 | optimum = scipy.optimize.minimize(driver.fun, x, method="SLSQP", jac=driver.grad,\ |
|
230 | 306 |
|
231 | 307 | print(" +--- Finished") |
232 | 308 |
|
| 309 | +end = timer() |
| 310 | +print("total time: ",end-start," seconds, ",(end-start)/60.0," minutes.") |
0 commit comments