Moving Some Systems Outside of the Optimization Loop#
Sometimes a model contains systems that don’t need to be executed during each iteration of an optimization loop. If those systems are expensive to execute, leaving them out of the optimization loop can significantly improve performance.
If the Problem
option group_by_pre_opt_post
is True, OpenMDAO will separate all of the
Components in the model into pre
, optimization
, or post
sets based on the dependency graph.
Only those Components found in
the optimization
set will be executed during each iteration of the optimization, while the ones
in the pre
and post
sets will only execute before or after the optimization loop.
It’s also possible, by setting the always_opt
option on a component, to force that component
to be included in the optimization loop regardless of its dependencies. Note that depending
on what its dependecies actually are, moving it to the optimization loop may also force other
components to move there even if they would normally be in pre
or post
.
Example#
import numpy as np
import openmdao.api as om
from openmdao.test_suite.components.exec_comp_for_test import ExecComp4Test
size = 3
prob = om.Problem(group_by_pre_opt_post=True)
prob.driver = om.ScipyOptimizeDriver(optimizer='SLSQP', disp=False)
model = prob.model
model.add_subsystem('pre1', ExecComp4Test('y=2.*x', x=np.ones(size), y=np.zeros(size)))
model.add_subsystem('pre2', ExecComp4Test('y=3.*x', x=np.ones(size), y=np.zeros(size)))
model.add_subsystem('iter1', ExecComp4Test('y=x1 + x2*4. + x3',
x1=np.ones(size), x2=np.ones(size),
x3=np.ones(size), y=np.zeros(size)))
model.add_subsystem('iter2', ExecComp4Test('y=.5*x', x=np.ones(size), y=np.zeros(size)))
model.add_subsystem('iter4', ExecComp4Test('y=7.*x', x=np.ones(size), y=np.zeros(size)))
model.add_subsystem('iter3', ExecComp4Test('y=6.*x', x=np.ones(size), y=np.zeros(size)))
model.add_subsystem('post1', ExecComp4Test('y=8.*x', x=np.ones(size), y=np.zeros(size)))
model.add_subsystem('post2', ExecComp4Test('y=x1*9. + x2*5', x1=np.ones(size),
x2=np.ones(size), y=np.zeros(size)))
# we don't want ExecComps to be colored because it makes the iter counting more complicated
for comp in model.system_iter(typ=ExecComp4Test):
comp.options['do_coloring'] = False
comp.options['has_diag_partials'] = True
model.connect('pre1.y', ['iter1.x1', 'post2.x1'])
model.connect('pre2.y', 'iter1.x2')
model.connect('iter1.y', ['iter2.x', 'iter4.x'])
model.connect('iter2.y', 'post2.x2')
model.connect('iter3.y', 'post1.x')
model.connect('iter4.y', 'iter3.x')
prob.model.add_design_var('iter1.x3', lower=0, upper=10)
prob.model.add_constraint('iter2.y', upper=10.)
prob.model.add_objective('iter3.y', index=0)
prob.setup()
prob.run_driver()
Problem: problem
Driver: ScipyOptimizeDriver
success : True
iterations : 3
runtime : 2.1682E-01 s
model_evals : 4
model_time : 1.4224E-01 s
deriv_evals : 2
deriv_time : 9.2197E-02 s
exit_status : SUCCESS
Check pre/post via the command line#
Use the openmdao list_pre_post
command to view the sets of components found in the pre
and post
sets. Any components not shown will be found in the optimization
set and will run during each iteration of the optimization loop.
Running the command on a script containing the example model above would show the following:
Pre-optimization systems:
pre1
pre2
Post-optimization systems:
post1
post2
Note that the pre
and post
sets will only be shown if the driver
is an optimizer and the group_by_pre_opt_post
option of the Problem
is True.