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.1513E-01 s
model_evals : 4
model_time : 1.4243E-01 s
deriv_evals : 2
deriv_time : 9.0131E-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.