Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application Case Fixes - multipoint derivative dicts, early_stopping, composite materials, funtofem.out file for remote driver #247

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
21efa87
fix typo in test bdf utils callbacks
sean-engelstad Oct 4, 2023
8a358e0
Merge branch 'smdogroup:master' into master
sean-engelstad Oct 6, 2023
3e40aaf
Merge branch 'smdogroup:master' into master
sean-engelstad Oct 11, 2023
14ed9a3
Merge branch 'smdogroup:master' into master
sean-engelstad Oct 25, 2023
af987b1
add early stopping criterion to steady state analyses
sean-engelstad Oct 25, 2023
73fb50b
add early stopping bool checks to the early stopping
sean-engelstad Oct 25, 2023
03821f1
black reformat
sean-engelstad Oct 25, 2023
e28757a
Update scenario.py
sean-engelstad Oct 25, 2023
3aac22f
Merge branch 'master' of github.com:sean-engelstad/funtofem into earl…
sean-engelstad Oct 25, 2023
fafe9b3
tolerances for early stopping
sean-engelstad Oct 26, 2023
ee0c5b1
Merge branch 'master' of github.com:sean-engelstad/funtofem into earl…
sean-engelstad Oct 28, 2023
28db0f2
add external shape flag for oneway aero
sean-engelstad Oct 28, 2023
0e59807
black reformat
sean-engelstad Oct 28, 2023
ec2935b
change remote dir call structure
sean-engelstad Oct 29, 2023
509be86
fix bug for off-scenario variables missing from dict
sean-engelstad Oct 30, 2023
4d79878
update remote directories
sean-engelstad Oct 30, 2023
dafba33
add functions file write out for user inspection
sean-engelstad Oct 30, 2023
15aa12b
move mapbcs to the scenario dir
sean-engelstad Oct 31, 2023
669faad
fix functions file printout
sean-engelstad Oct 31, 2023
d81cc99
allow full fun3d residuals list to be extracted
sean-engelstad Oct 31, 2023
243152e
black reformat
sean-engelstad Oct 31, 2023
81ce392
rewrite distribute_aero_loads in a faster way
sean-engelstad Nov 1, 2023
d93a0cb
Merge branch 'application2' of github.com:sean-engelstad/funtofem int…
sean-engelstad Nov 1, 2023
713e3fb
add debug messages and option for moving mapbc
sean-engelstad Nov 1, 2023
29f28b8
Merge branch 'application2' of github.com:sean-engelstad/funtofem int…
sean-engelstad Nov 1, 2023
38003e8
change full_name properties to use scenario-name not scenario.name
sean-engelstad Nov 1, 2023
e64f12e
Merge branch 'application2' of github.com:sean-engelstad/funtofem int…
sean-engelstad Nov 1, 2023
f478dad
add smeared composite shell constitutive to callback
sean-engelstad Nov 1, 2023
b9749d4
read aero, struct variables from analysis system call
sean-engelstad Nov 1, 2023
f76625f
Merge branch 'application2' of github.com:sean-engelstad/funtofem int…
sean-engelstad Nov 1, 2023
7d0711c
fix evaluate composite func bug
sean-engelstad Nov 1, 2023
aad9605
ksfailure, safety factor inputs
sean-engelstad Nov 1, 2023
35e7e19
Merge branch 'application2' of github.com:sean-engelstad/funtofem int…
sean-engelstad Nov 1, 2023
9bf72a7
change way to reset funcs to zero in shape driver
sean-engelstad Nov 1, 2023
9ed4110
flush print statement messages
sean-engelstad Nov 1, 2023
b0e4eed
add safety factor feature
sean-engelstad Nov 1, 2023
faa6f19
Merge branch 'application2' of github.com:sean-engelstad/funtofem int…
sean-engelstad Nov 1, 2023
87109d4
try writing fun3d aim aero DVs
sean-engelstad Nov 1, 2023
2ddb615
send aerodynamic derivatives through functions_file and remote
sean-engelstad Nov 1, 2023
600f002
write function file for optim
sean-engelstad Nov 1, 2023
1f0215c
take aero dvs off the write_sensitivity_file call now
sean-engelstad Nov 1, 2023
029f9ea
separate the analysis and optim functions files
sean-engelstad Nov 2, 2023
b78f72b
add full precision entry into functions file
sean-engelstad Nov 2, 2023
98b3453
change funtofem.out file structure
sean-engelstad Nov 2, 2023
4b4b306
fix functions file writeout with unittest
sean-engelstad Nov 2, 2023
92275e9
black reformat new unittest
sean-engelstad Nov 2, 2023
b1ed3aa
add timing data printouts to funtofem shape driver
sean-engelstad Nov 2, 2023
91263f7
tweak timing printouts
sean-engelstad Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions examples/framework/tacs_oneway_naca_wing/1_tacs_sizing_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@

# make the composite functions for adjacency constraints
variables = f2f_model.get_variables()
adj_ratio = 4.0
adj_ratio = 2.0
adj_scale = 10.0
for irib in range(
1, nribs
Expand Down Expand Up @@ -149,12 +149,15 @@
prob = om.Problem()

# Create the OpenMDAO component using the built-in Funtofem component
f2f_subsystem = FuntofemComponent(driver=tacs_driver, write_dir=tacs_aim.analysis_dir)
design_out_file = "design-test.txt"
f2f_subsystem = FuntofemComponent(
driver=tacs_driver, write_dir=tacs_aim.analysis_dir, design_out_file=design_out_file
)
prob.model.add_subsystem("f2fSystem", f2f_subsystem)
f2f_subsystem.register_to_model(prob.model, "f2fSystem")

# setup the optimizer settings # COBYLA for auto-FDing
optimizer = "pyoptsparse"
optimizer = "scipy"
if optimizer == "scipy":
prob.driver = om.ScipyOptimizeDriver(optimizer="SLSQP", tol=1.0e-9, disp=True)
elif optimizer == "pyoptsparse":
Expand Down
199 changes: 199 additions & 0 deletions examples/framework/tacs_oneway_naca_wing/3_tacs_sizing_opt_stringer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
"""
Sean Engelstad, May 2023
GT SMDO Lab, Dr. Graeme Kennedy
OnewayStructDriver example
"""

from funtofem import *
from tacs import caps2tacs
import openmdao.api as om
from mpi4py import MPI

# --------------------------------------------------------------#
# Setup CAPS Problem and FUNtoFEM model
# --------------------------------------------------------------#
comm = MPI.COMM_WORLD
f2f_model = FUNtoFEMmodel("tacs_wing")
wing = Body.aeroelastic(
"wing"
) # says aeroelastic but not coupled, may want to make new classmethods later...

# define the Tacs model
tacs_model = caps2tacs.TacsModel.build(csm_file="large_naca_wing.csm", comm=comm)
tacs_model.mesh_aim.set_mesh( # need a refined-enough mesh for the derivative test to pass
edge_pt_min=15,
edge_pt_max=20,
global_mesh_size=0.01,
max_surf_offset=0.01,
max_dihedral_angle=5,
).register_to(
tacs_model
)
tacs_aim = tacs_model.tacs_aim

aluminum = caps2tacs.Isotropic.aluminum()
aluminum_stringer = caps2tacs.Orthotropic.smeared_stringer(
aluminum, area_ratio=0.5
).register_to(tacs_model)

# setup the thickness design variables + automatic shell properties
# using Composite functions, this part has to go after all funtofem variables are defined...
nribs = int(tacs_model.get_config_parameter("nribs"))
nspars = int(tacs_model.get_config_parameter("nspars"))
nOML = int(tacs_aim.get_output_parameter("nOML"))

init_thickness = 0.08
for irib in range(1, nribs + 1):
name = f"rib{irib}"
caps2tacs.CompositeProperty.one_ply(
caps_group=name,
material=aluminum_stringer,
thickness=init_thickness,
ply_angle=0,
).register_to(tacs_model)
Variable.structural(name, value=init_thickness).set_bounds(
lower=0.01, upper=0.2, scale=100.0
).register_to(wing)

for ispar in range(1, nspars + 1):
name = f"spar{ispar}"
caps2tacs.CompositeProperty.one_ply(
caps_group=name,
material=aluminum_stringer,
thickness=init_thickness,
ply_angle=0,
).register_to(tacs_model)
Variable.structural(name, value=init_thickness).set_bounds(
lower=0.01, upper=0.2, scale=100.0
).register_to(wing)

for iOML in range(1, nOML + 1):
name = f"OML{iOML}"
caps2tacs.CompositeProperty.one_ply(
caps_group=name,
material=aluminum_stringer,
thickness=init_thickness,
ply_angle=0,
).register_to(tacs_model)
Variable.structural(name, value=init_thickness).set_bounds(
lower=0.01, upper=0.2, scale=100.0
).register_to(wing)

# add constraints and loads
caps2tacs.PinConstraint("root").register_to(tacs_model)
caps2tacs.GridForce("OML", direction=[0, 0, 1.0], magnitude=10).register_to(tacs_model)

# run the tacs model setup and register to the funtofem model
f2f_model.structural = tacs_model

# register the funtofem Body to the model
wing.register_to(f2f_model)

# make the scenario(s)
tacs_scenario = Scenario.steady("tacs", steps=100)
Function.mass().optimize(scale=1.0e-2, objective=True, plot=True).register_to(
tacs_scenario
)
Function.ksfailure(ks_weight=10.0).optimize(
scale=30.0, upper=0.267, objective=False, plot=True
).register_to(tacs_scenario)
tacs_scenario.register_to(f2f_model)

# make the composite functions for adjacency constraints
variables = f2f_model.get_variables()
adj_ratio = 2.0
adj_scale = 10.0
for irib in range(
1, nribs
): # not (1, nribs+1) bc we want to do one less since we're doing nribs-1 pairs
left_rib = f2f_model.get_variables(names=f"rib{irib}")
right_rib = f2f_model.get_variables(names=f"rib{irib+1}")
# make a composite function for relative diff in rib thicknesses
adj_rib_constr = (left_rib - right_rib) / left_rib
adj_rib_constr.set_name(f"rib{irib}-{irib+1}").optimize(
lower=-adj_ratio, upper=adj_ratio, scale=1.0, objective=False
).register_to(f2f_model)

for ispar in range(1, nspars):
left_spar = f2f_model.get_variables(names=f"spar{ispar}")
right_spar = f2f_model.get_variables(names=f"spar{ispar+1}")
# make a composite function for relative diff in spar thicknesses
adj_spar_constr = (left_spar - right_spar) / left_spar
adj_spar_constr.set_name(f"spar{ispar}-{ispar+1}").optimize(
lower=-adj_ratio, upper=adj_ratio, scale=1.0, objective=False
).register_to(f2f_model)

for iOML in range(1, nOML):
left_OML = f2f_model.get_variables(names=f"OML{iOML}")
right_OML = f2f_model.get_variables(names=f"OML{iOML+1}")
# make a composite function for relative diff in OML thicknesses
adj_OML_constr = (left_OML - right_OML) / left_OML
adj_OML_constr.set_name(f"OML{iOML}-{iOML+1}").optimize(
lower=-adj_ratio, upper=adj_ratio, scale=1.0, objective=False
).register_to(f2f_model)

# make the BDF and DAT file for TACS structural analysis
tacs_aim.setup_aim()
tacs_aim.pre_analysis()

# build the solver manager, no tacs interface since built for each new shape
# in the tacs driver
solvers = SolverManager(comm)
solvers.flow = NullAerodynamicSolver(comm=comm, model=f2f_model)
solvers.structural = TacsSteadyInterface.create_from_bdf(
model=f2f_model,
comm=comm,
nprocs=1,
bdf_file=tacs_aim.dat_file_path,
prefix=tacs_aim.analysis_dir,
)
solvers.flow.copy_struct_mesh()
null_driver = NullDriver(solvers, model=f2f_model, transfer_settings=None)

# build the tacs oneway driver
tacs_driver = OnewayStructDriver.prime_loads(driver=null_driver)

# --------------------------------------------------------------------------#
# Setup OpenMDAO Problem and Perform Sizing Optimization on the Wing
# --------------------------------------------------------------------------#

# setup the OpenMDAO Problem object
prob = om.Problem()

# Create the OpenMDAO component using the built-in Funtofem component
design_out_file = "design-test.txt"
f2f_subsystem = FuntofemComponent(
driver=tacs_driver, write_dir=tacs_aim.analysis_dir, design_out_file=design_out_file
)
prob.model.add_subsystem("f2fSystem", f2f_subsystem)
f2f_subsystem.register_to_model(prob.model, "f2fSystem")

# setup the optimizer settings # COBYLA for auto-FDing
optimizer = "scipy"
if optimizer == "scipy":
prob.driver = om.ScipyOptimizeDriver(optimizer="SLSQP", tol=1.0e-9, disp=True)
elif optimizer == "pyoptsparse":
prob.driver = om.pyOptSparseDriver(optimizer="SNOPT")
# prob.driver.opt_settings['Major feasibility tolerance'] = 1e-5 # lower tolerance to prevent tight oscillations

# Start the optimization
print("\n==> Starting optimization...")
prob.setup()

debug = False
if debug:
print("Checking partials...", flush=True)
prob.check_partials(compact_print=True)

else:
prob.run_driver()

# report the final optimal design
design_hdl = f2f_subsystem._design_hdl
for var in f2f_model.get_variables():
opt_value = prob.get_val(f"f2fSystem.{var.name}")
design_hdl.write(f"\t{var.name} = {opt_value}")

prob.cleanup()
# close the design hdl file
f2f_subsystem.cleanup()
3 changes: 3 additions & 0 deletions examples/framework/tacs_oneway_naca_wing/large_naca_wing.csm
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ set margin1 5.0
set margin2 3.0
set margin3 10.0

dimension compositeCoord 9 1 0
set compositeCoord "0;0;0;0;1;0;1;0;0;"

### 1. Wing Solid Body ###

Expand Down Expand Up @@ -178,6 +180,7 @@ udprim editAttr filename <<

# add AIM attribute to specify the analyses to use
select body
csystem wing compositeCoord
attribute capsAIM $egadsTessAIM;tacsAIM

end
Expand Down
48 changes: 44 additions & 4 deletions funtofem/driver/funtofem_nlbgs_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ def _solve_steady_forward(self, scenario, steps=None):
)
steps = 1000

# flow preconditioner steps (mainly for aerothermal and aerothermoelastic analysis to precondition temperatures)
for step in range(1, scenario.preconditioner_steps + 1):
# Take a step in the flow solver for preconditioner (just aerodynamic iteration)
# flow uncoupled steps (mainly for aerothermal and aerothermoelastic analysis to precondition temperatures)
for step in range(1, scenario.uncoupled_steps + 1):
# Take a step in the flow solver for (just aerodynamic iteration)
fail = self.solvers.flow.conditioner_iterate(
scenario, self.model.bodies, step
)
Expand All @@ -140,7 +140,7 @@ def _solve_steady_forward(self, scenario, steps=None):
return fail

# Loop over the NLBGS steps
for step in range(scenario.preconditioner_steps + 1, steps + 1):
for step in range(scenario.uncoupled_steps + 1, steps + 1):
# Transfer displacements and temperatures
for body in self.model.bodies:
body.transfer_disps(scenario)
Expand Down Expand Up @@ -189,6 +189,26 @@ def _solve_steady_forward(self, scenario, steps=None):
for body in self.model.bodies:
body.aitken_relax(self.comm, scenario)

# check for early stopping criterion, exit if meets criterion
exit_early = False
if scenario.early_stopping and step > scenario.min_forward_steps:
for solver in self.solvers.solver_list:
forward_resid = abs(solver.get_forward_residual(step=step))
forward_tol = solver.forward_tolerance
if forward_resid < forward_tol:
if self.comm.rank == 0:
print(
f"F2F Steady Forward analysis of scenario {scenario.name} exited early"
)
print(
f"\tat step {step} with tolerance {forward_resid} < {forward_tol}",
flush=True,
)
exit_early = True
break
if exit_early:
break

return fail

def _solve_steady_adjoint(self, scenario):
Expand Down Expand Up @@ -254,6 +274,26 @@ def _solve_steady_adjoint(self, scenario):
for body in self.model.bodies:
body.aitken_adjoint_relax(self.comm, scenario)

# check for early stopping criterion, exit if meets criterion
exit_early = False
if scenario.early_stopping and step > scenario.min_adjoint_steps:
for solver in self.solvers.solver_list:
adjoint_resid = abs(solver.get_adjoint_residual(step=step))
adjoint_tol = solver.adjoint_tolerance
if adjoint_resid < adjoint_tol:
if self.comm.rank == 0:
print(
f"F2F Steady Adjoint analysis of scenario {scenario.name}"
)
print(
f"\texited early at step {step} with tolerance {adjoint_resid} < {adjoint_tol}",
flush=True,
)
exit_early = True
break
if exit_early:
break

self._extract_coordinate_derivatives(scenario, self.model.bodies, steps)
return 0

Expand Down
Loading
Loading