Skip to content

Commit 8849767

Browse files
SSW 14.0 Modifications for SNOPT (#295)
* Fix opt manager nan exit (#284) * fix bug in optimization manager * Update optimization_manager.py * Create a generalized mesh AIM. (#286) * Generalized mesh AIM * New notation in meshAIM * Update egads_aim.py * Update aflr_aim.py * Formatting * Update egads_aim.py * FUNtoFEM read and write unsteady aero loads files (#289) * working unsteady aero loads files * black reformat * FUN3D v14.0.2 interface stable release for thermal cases (#288) * fun3d 14.0 fun3d interface changes * add separate fun3d 14 and 13.0 interfaces * Update fun3d_14_interface.py name to Fun3d14Interface * update fun3d 14 interface unittests * update fun3d model * black reformat * update fun3d 14.0 thermal changes * update fun3d 14 interface with debug statements * new thermal fun3d test * add new fun3d thermal interface test * fun3d 14 thermal interface test complete * update the fun3d 14 thermal interface test * update the import statements * black reformat * black reformat with psf/black-stable * Apply suggestions from code review * undo debug changes * black reformat * Rollback test_fun3d_tacs.py to FUN3D 13.6 test * Update test_fun3d_tacs.py to add fun3d_project_name back in * black reformat --------- Co-authored-by: Brian Burke <[email protected]> * FUN3D 14.0 Coupling Frequency for Coupled Adjoint speedup + Early Stopping Fix (#291) * huge speedup in funtofem fully coupled adjoint solve * turn hanim off in turbulent beta nml * working adjoint derivatives and change adjoint_steps * working early stopping criterion in FUN3D 14.0.2 * add error check for first aero function w early stopping * input funtofem loose coupling frequency through the fun3d interface (no longer namelist input) * update nml for turbulent beta * black reformat + throw error if FUN3D 13.6 uses loose coupling frequency * Update funtofem/interface/fun3d_interface.py --------- Co-authored-by: Brian Burke <[email protected]> * commit ssw 14.0 example * egads aero mesh example * prototype ssw finite difference test * remove reload design file * update cfl in namelist * fix steps in namelist * update panel thickness script * add FD test for the derivatives * fix early stopping multi analysis bug * update ssw 14 fun3d nml * new aero loads for ssw case * oneway sizing opt * updated aerodynamic function fun3d check * black reformat --------- Co-authored-by: Brian Burke <[email protected]>
1 parent ef1677c commit 8849767

File tree

74 files changed

+32827
-227
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+32827
-227
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
"""
2+
1_panel_thickness.py
3+
4+
Run a coupled optimization of the panel thicknesses of the wing structure.
5+
No shape variables are included in this optimization.
6+
"""
7+
8+
from pyoptsparse import SNOPT, Optimization
9+
from funtofem import *
10+
from mpi4py import MPI
11+
from tacs import caps2tacs
12+
import os, time
13+
14+
comm = MPI.COMM_WORLD
15+
16+
base_dir = os.path.dirname(os.path.abspath(__file__))
17+
csm_path = os.path.join(base_dir, "geometry", "ssw.csm")
18+
19+
# Optimization options
20+
hot_start = False
21+
store_history = True
22+
23+
test_derivatives = False
24+
25+
nprocs_tacs = 8
26+
27+
global_debug_flag = False
28+
29+
# Derivative test stuff
30+
FILENAME = "complex-step.txt"
31+
FILEPATH = os.path.join(base_dir, FILENAME)
32+
33+
aitken_file = os.path.join(base_dir, "aitken-hist.txt")
34+
35+
# FUNTOFEM MODEL
36+
# <----------------------------------------------------
37+
# Freestream quantities -- see README
38+
T_inf = 268.338 # Freestream temperature
39+
q_inf = 1.21945e4 # Dynamic pressure
40+
41+
# Construct the FUNtoFEM model
42+
f2f_model = FUNtoFEMmodel("ssw-sizing1")
43+
tacs_model = caps2tacs.TacsModel.build(
44+
csm_file=csm_path,
45+
comm=comm,
46+
problem_name="capsStruct1",
47+
active_procs=[0],
48+
verbosity=1,
49+
)
50+
tacs_model.mesh_aim.set_mesh(
51+
edge_pt_min=2,
52+
edge_pt_max=20,
53+
global_mesh_size=0.3,
54+
max_surf_offset=0.2,
55+
max_dihedral_angle=15,
56+
).register_to(tacs_model)
57+
f2f_model.structural = tacs_model
58+
59+
tacs_aim = tacs_model.tacs_aim
60+
tacs_aim.set_config_parameter("view:flow", 0)
61+
tacs_aim.set_config_parameter("view:struct", 1)
62+
63+
for proc in tacs_aim.active_procs:
64+
if comm.rank == proc:
65+
aim = tacs_model.mesh_aim.aim
66+
aim.input.Mesh_Sizing = {
67+
"chord": {"numEdgePoints": 20},
68+
"span": {"numEdgePoints": 8},
69+
"vert": {"numEdgePoints": 4},
70+
}
71+
72+
# add tacs constraints in
73+
caps2tacs.PinConstraint("root").register_to(tacs_model)
74+
75+
# ---------------------------------------------------->
76+
77+
# BODIES AND STRUCT DVs
78+
# <----------------------------------------------------
79+
80+
# wing = Body.aeroelastic("wing", boundary=3).relaxation(
81+
# AitkenRelaxation(
82+
# theta_init=0.6, theta_max=0.95, history_file=aitken_file, debug=True
83+
# )
84+
# )
85+
wing = Body.aeroelastic("wing", boundary=3)
86+
87+
# setup the material and shell properties
88+
aluminum = caps2tacs.Isotropic.aluminum().register_to(tacs_model)
89+
90+
nribs = int(tacs_model.get_config_parameter("nribs"))
91+
nspars = int(tacs_model.get_config_parameter("nspars"))
92+
nOML = nribs - 1
93+
94+
for irib in range(1, nribs + 1):
95+
name = f"rib{irib}"
96+
prop = caps2tacs.ShellProperty(
97+
caps_group=name, material=aluminum, membrane_thickness=0.04
98+
).register_to(tacs_model)
99+
Variable.structural(name, value=0.01).set_bounds(
100+
lower=0.001, upper=0.15, scale=100.0
101+
).register_to(wing)
102+
103+
for ispar in range(1, nspars + 1):
104+
name = f"spar{ispar}"
105+
prop = caps2tacs.ShellProperty(
106+
caps_group=name, material=aluminum, membrane_thickness=0.04
107+
).register_to(tacs_model)
108+
Variable.structural(name, value=0.01).set_bounds(
109+
lower=0.001, upper=0.15, scale=100.0
110+
).register_to(wing)
111+
112+
for iOML in range(1, nOML + 1):
113+
name = f"OML{iOML}"
114+
prop = caps2tacs.ShellProperty(
115+
caps_group=name, material=aluminum, membrane_thickness=0.04
116+
).register_to(tacs_model)
117+
Variable.structural(name, value=0.01).set_bounds(
118+
lower=0.001, upper=0.15, scale=100.0
119+
).register_to(wing)
120+
121+
for prefix in ["LE", "TE"]:
122+
name = f"{prefix}spar"
123+
prop = caps2tacs.ShellProperty(
124+
caps_group=name, material=aluminum, membrane_thickness=0.04
125+
).register_to(tacs_model)
126+
Variable.structural(name, value=0.01).set_bounds(
127+
lower=0.001, upper=0.15, scale=100.0
128+
).register_to(wing)
129+
130+
# register the wing body to the model
131+
wing.register_to(f2f_model)
132+
133+
# ---------------------------------------------------->
134+
135+
# INITIAL STRUCTURE MESH, SINCE NO STRUCT SHAPE VARS
136+
# <----------------------------------------------------
137+
138+
tacs_aim.setup_aim()
139+
tacs_aim.pre_analysis()
140+
141+
# ---------------------------------------------------->
142+
143+
# SCENARIOS
144+
# <----------------------------------------------------
145+
146+
# make a funtofem scenario
147+
cruise = Scenario.steady("cruise", steps=1000, coupling_frequency=50, uncoupled_steps=0)
148+
cruise.adjoint_steps = (
149+
100 # outer coupling iterations, total 5000 flow adjoints, 100 grid adjoints
150+
)
151+
cruise.set_stop_criterion(early_stopping=True, min_adjoint_steps=50)
152+
mass = Function.mass().optimize(
153+
scale=1.0e-4, objective=True, plot=True, plot_name="mass"
154+
)
155+
ksfailure = Function.ksfailure(ks_weight=10.0, safety_factor=1.5).optimize(
156+
scale=1.0, upper=1.0, objective=False, plot=True, plot_name="ks-cruise"
157+
)
158+
cruise.include(ksfailure).include(mass)
159+
cruise.set_temperature(T_ref=T_inf, T_inf=T_inf)
160+
cruise.set_flow_ref_vals(qinf=q_inf)
161+
cruise.register_to(f2f_model)
162+
163+
# ---------------------------------------------------->
164+
165+
# COMPOSITE FUNCTIONS
166+
# <----------------------------------------------------
167+
168+
# skin thickness adjacency constraints
169+
if not test_derivatives:
170+
variables = f2f_model.get_variables()
171+
section_prefix = ["rib", "OML"]
172+
section_nums = [nribs, nOML]
173+
for isection, prefix in enumerate(section_prefix):
174+
section_num = section_nums[isection]
175+
for iconstr in range(1, section_num):
176+
left_var = f2f_model.get_variables(names=f"{prefix}{iconstr}")
177+
right_var = f2f_model.get_variables(names=f"{prefix}{iconstr+1}")
178+
# adj_constr = (left_var - right_var) / left_var
179+
# adj_ratio = 0.15
180+
adj_constr = left_var - right_var
181+
adj_diff = 0.002
182+
adj_constr.set_name(f"{prefix}{iconstr}-{iconstr+1}").optimize(
183+
lower=-adj_diff, upper=adj_diff, scale=1.0, objective=False
184+
).register_to(f2f_model)
185+
186+
187+
# ---------------------------------------------------->
188+
189+
# DISCIPLINE INTERFACES AND DRIVERS
190+
# <----------------------------------------------------
191+
192+
solvers = SolverManager(comm)
193+
solvers.flow = Fun3d14Interface(
194+
comm,
195+
f2f_model,
196+
fun3d_dir="cfd",
197+
forward_stop_tolerance=1e-12,
198+
forward_min_tolerance=1e-8,
199+
adjoint_stop_tolerance=1e-12,
200+
adjoint_min_tolerance=1e-8,
201+
debug=global_debug_flag,
202+
)
203+
# fun3d_project_name = "ssw-pw1.2"
204+
solvers.structural = TacsSteadyInterface.create_from_bdf(
205+
model=f2f_model,
206+
comm=comm,
207+
nprocs=nprocs_tacs,
208+
bdf_file=tacs_aim.root_dat_file,
209+
prefix=tacs_aim.root_analysis_dir,
210+
debug=global_debug_flag,
211+
)
212+
213+
transfer_settings = TransferSettings(npts=200)
214+
215+
# Build the FUNtoFEM driver
216+
f2f_driver = FUNtoFEMnlbgs(
217+
solvers=solvers,
218+
transfer_settings=transfer_settings,
219+
model=f2f_model,
220+
debug=global_debug_flag,
221+
)
222+
223+
if test_derivatives: # test using the finite difference test
224+
# load the previous design
225+
# design_in_file = os.path.join(base_dir, "design", "sizing-oneway.txt")
226+
# f2f_model.read_design_variables_file(comm, design_in_file)
227+
228+
start_time = time.time()
229+
230+
# run the finite difference test
231+
max_rel_error = TestResult.derivative_test(
232+
"fun3d+tacs-ssw1",
233+
model=f2f_model,
234+
driver=f2f_driver,
235+
status_file="1-derivs.txt",
236+
complex_mode=False,
237+
epsilon=1e-4,
238+
)
239+
240+
end_time = time.time()
241+
dt = end_time - start_time
242+
if comm.rank == 0:
243+
print(f"total time for ssw derivative test is {dt} seconds", flush=True)
244+
print(f"max rel error = {max_rel_error}", flush=True)
245+
246+
# exit before optimization
247+
exit()
248+
249+
250+
# PYOPTSPARSE OPTMIZATION
251+
# <----------------------------------------------------
252+
253+
# create an OptimizationManager object for the pyoptsparse optimization problem
254+
design_in_file = os.path.join(base_dir, "design", "sizing-oneway.txt")
255+
design_out_file = os.path.join(base_dir, "design", "design-1.txt")
256+
257+
design_folder = os.path.join(base_dir, "design")
258+
if comm.rank == 0:
259+
if not os.path.exists(design_folder):
260+
os.mkdir(design_folder)
261+
history_file = os.path.join(design_folder, "design-1.hst")
262+
store_history_file = history_file if store_history else None
263+
hot_start_file = history_file if hot_start else None
264+
265+
# Reload the previous design
266+
# f2f_model.read_design_variables_file(comm, design_in_file)
267+
268+
if comm.rank == 0:
269+
# f2f_driver.print_summary()
270+
f2f_model.print_summary()
271+
272+
manager = OptimizationManager(
273+
f2f_driver,
274+
design_out_file=design_out_file,
275+
hot_start=hot_start,
276+
hot_start_file=hot_start_file,
277+
debug=True,
278+
)
279+
280+
# create the pyoptsparse optimization problem
281+
opt_problem = Optimization("sswOpt", manager.eval_functions)
282+
283+
# add funtofem model variables to pyoptsparse
284+
manager.register_to_problem(opt_problem)
285+
286+
# run an SNOPT optimization
287+
snoptimizer = SNOPT(options={"Verify level": 0, "Function precision": 1e-8})
288+
289+
sol = snoptimizer(
290+
opt_problem,
291+
sens=manager.eval_gradients,
292+
storeHistory=store_history_file,
293+
hotStart=hot_start_file,
294+
)
295+
296+
# print final solution
297+
sol_xdict = sol.xStar
298+
299+
if comm.rank == 0:
300+
print(f"Final solution = {sol_xdict}", flush=True)
301+
302+
# ---------------------------------------------------->

0 commit comments

Comments
 (0)