SubmodelComp#
SubmodelComp
provides a way to evaluate an OpenMDAO system within an OpenMDAO system.
SubmodelComp Options#
import openmdao.api as om
om.show_options_table(om.SubmodelComp(problem=om.Problem()))
Option | Default | Acceptable Values | Acceptable Types | Description |
---|---|---|---|---|
always_opt | False | [True, False] | ['bool'] | If True, force nonlinear operations on this component to be included in the optimization loop even if this component is not relevant to the design variables and responses. |
derivs_method | N/A | ['jax', 'cs', 'fd', None] | N/A | The method to use for computing derivatives |
distributed | False | [True, False] | ['bool'] | If True, set all variables in this component as distributed across multiple processes |
do_coloring | False | [True, False] | ['bool'] | If True, attempt to compute a total coloring for the submodel. |
run_root_only | False | [True, False] | ['bool'] | If True, call compute, compute_partials, linearize, apply_linear, apply_nonlinear, and compute_jacvec_product only on rank 0 and broadcast the results to the other ranks. |
use_jit | True | [True, False] | ['bool'] | If True, attempt to use jit on compute_primal, assuming jax or some other AD package is active. |
SubmodelComp Constructor#
The call signature for the SubmodelComp
constructor is
- SubmodelComp.__init__(problem, inputs=None, outputs=None, reports=False, **kwargs)[source]
Initialize all attributes.
Using the SubmodelComp#
SubmodelComp
allows you to add a component that contains a complete Problem
in itself. The only required argument is problem
. This takes an instantiated problem that already has a model. That way, the user can declare any desired options for the problem and have it used for the underlying subproblem.
Other arguments include inputs
, outputs
, and reports
. Input and output argument formats are discussed in the next section, but if the inputs and outputs are not specified in the SubmodelComp
’s instantiation, they will have to be added later using the add_input
and add_output
methods. The reports
option controls report generation for the underlying subproblem. SubmodelComp
performs more efficiently if it doesn’t have to write reports, but if reports are desired, then the reports
argument can be set to True
.
SubmodelComp
provides a way to evaluate an OpenMDAO model within an OpenMDAO system. Unlike a typical subsystem, using a subproblem exposes only a limited number of inputs and outputs of the underlying model to the parent system. This may be beneficial from a performance standpoint when there are many inputs and outputs of the internal model that aren’t needed in the top-level model.
Note that this means that nonlinear and linear solvers are needed on the subproblem’s model if implicit behavior is present, since the internal variables are invisible to solvers in the parent system.
At this time, OpenMDAO does not evaluate gradients through the optimization process, so a gradient-based driver at the outer level cannot access derivatives across the optimization on the inner level.
Inputs and Outputs#
Inputs and outputs can be passed into SubmodelComp
as a list of str
, tuple
, or both. If the list element is str
, then it must specify the promoted name of a variable in the model. All inputs and outputs you wish to use must be promoted to the model level. If the list element is tuple
, then the first element of the tuple
must be the group level promoted name or the absolute name of the variable, and the second element is an alias that SubmodelComp
will use to refer to the variable. For example:
(path.to.var, desired_var_name)
or (var, desired_var_name) if the variable is already promoted at the group level
Input and output names can also include wildcards if the type is str
.
If not specified at instantiation, inputs and outputs will have to be declared using the add_input
and add_output
methods.
Example: Using SubmodelComp#
import openmdao.api as om
from numpy import pi
p = om.Problem()
# create a model that computes x = r*cos(theta)
submodel1 = om.Group()
submodel1.add_subsystem('sub1_ivc_r', om.IndepVarComp('r', 1.),
promotes_outputs=['r'])
submodel1.add_subsystem('sub1_ivc_theta', om.IndepVarComp('theta', pi),
promotes_outputs=['theta'])
submodel1.add_subsystem('subComp1', om.ExecComp('x = r*cos(theta)'),
promotes_inputs=['r', 'theta'],
promotes_outputs=['x'])
# create a model that computes y = r*sin(theta)
submodel2 = om.Group()
submodel2.add_subsystem('sub2_ivc_r', om.IndepVarComp('r', 2),
promotes_outputs=['r'])
submodel2.add_subsystem('sub2_ivc_theta', om.IndepVarComp('theta', pi/2),
promotes_outputs=['theta'])
submodel2.add_subsystem('subComp2', om.ExecComp('y = r*sin(theta)'),
promotes_inputs=['r', 'theta'],
promotes_outputs=['y'])
# wrap the x and y models as sub-problems
subprob1 = om.Problem(model=submodel1)
subprob2 = om.Problem(model=submodel2)
subcomp1 = om.SubmodelComp(problem=subprob1,
inputs=['r', 'theta'], outputs=['x'])
subcomp2 = om.SubmodelComp(problem=subprob2,
inputs=['r', 'theta'], outputs=['y'])
# add both sub-problems and a Component that uses their outputs
p.model.add_subsystem('sub1', subcomp1,
promotes_inputs=['r','theta'],
promotes_outputs=['x'])
p.model.add_subsystem('sub2', subcomp2,
promotes_inputs=['r','theta'],
promotes_outputs=['y'])
p.model.add_subsystem('supComp', om.ExecComp('z = x**2 + y'),
promotes_inputs=['x', 'y'],
promotes_outputs=['z'])
p.model.set_input_defaults('r', 1)
p.model.set_input_defaults('theta', pi)
p.setup(force_alloc_complex=True)
p.run_model()
cpd = p.check_partials(method='cs', out_stream=None)
Example: Variable Aliases#
import openmdao.api as om
# create a Problem that will be nested in another Problem
subprob = om.Problem()
submodel = subprob.model
submodel.add_subsystem('subsys', om.ExecComp('z = x**2 + y**2'))
# wrap that Problem in a SubmodelComp, renaming the inputs and output
subcomp = om.SubmodelComp(problem=subprob,
inputs=[('subsys.x', 'a'), ('subsys.y', 'b')],
outputs=[('subsys.z', 'c')])
# create a top-level Problem that contains the SubmodelComp
p = om.Problem()
p.model.add_subsystem('subcomp', subcomp, promotes_inputs=['a', 'b'], promotes_outputs=['c'])
p.setup()
p.set_val('a', 1)
p.set_val('b', 2)
p.run_model()
inputs = p.model.list_inputs()
outputs = p.model.list_outputs()
2 Input(s) in 'model'
varname val prom_name
------- ---- ---------
subcomp
a [1.] a
b [2.] b
1 Explicit Output(s) in 'model'
varname val prom_name
------- ---- ---------
subcomp
c [5.] c
0 Implicit Output(s) in 'model'
Example: Using Variables with the Same Name#
import openmdao.api as om
p = om.Problem()
model = om.Group()
model.add_subsystem('x1Comp', om.ExecComp('x1 = x*3'))
model.add_subsystem('x2Comp', om.ExecComp('x2 = x**3'))
model.add_subsystem('model', om.ExecComp('z = x1**2 + x2**2'))
model.connect('x1Comp.x1', 'model.x1')
model.connect('x2Comp.x2', 'model.x2')
subprob = om.Problem()
subprob.model.add_subsystem('submodel', model)
comp = om.SubmodelComp(problem=subprob,
inputs=[('submodel.x1Comp.x', 'x'), ('submodel.x2Comp.x', 'y')],
outputs=[('submodel.model.z', 'z')])
p.model.add_subsystem('comp', comp)
p.model.set_input_defaults('comp.x', 1)
p.model.set_input_defaults('comp.y', 2)
p.setup()
p.run_model()
inputs = p.model.list_inputs()
outputs = p.model.list_outputs()
2 Input(s) in 'model'
varname val prom_name
------- ---- ---------
comp
x [1.] comp.x
y [2.] comp.y
1 Explicit Output(s) in 'model'
varname val prom_name
------- ----- ---------
comp
z [73.] comp.z
0 Implicit Output(s) in 'model'
Example: Adding Inputs and Outputs Using Wildcards#
import openmdao.api as om
p = om.Problem()
submodel = om.Group()
submodel.add_subsystem('sub', om.ExecComp('z = x1**2 + x2**2 + x3**2'), promotes=['*'])
subprob = om.Problem()
subprob.model.add_subsystem('submodel', submodel, promotes=['*'])
comp = om.SubmodelComp(problem=subprob, inputs=['x*'], outputs=['*'])
p.model.add_subsystem('comp', comp, promotes_inputs=['*'], promotes_outputs=['*'])
p.setup()
p.set_val('x1', 1)
p.set_val('x2', 2)
p.set_val('x3', 3)
p.run_model()
inputs = p.model.list_inputs()
outputs = p.model.list_outputs()
3 Input(s) in 'model'
varname val prom_name
------- ---- ---------
comp
x1 [1.] x1
x2 [2.] x2
x3 [3.] x3
1 Explicit Output(s) in 'model'
varname val prom_name
------- ----- ---------
comp
z [14.] z
0 Implicit Output(s) in 'model'
Example: Adding Inputs and Outputs After Instantiation#
import openmdao.api as om
p = om.Problem()
# create a model that computes x = r*cos(theta)
submodel1 = om.Group()
submodel1.add_subsystem('sub1_ivc_r', om.IndepVarComp('r', 1.),
promotes_outputs=['r'])
submodel1.add_subsystem('sub1_ivc_theta', om.IndepVarComp('theta', pi),
promotes_outputs=['theta'])
submodel1.add_subsystem('subComp1', om.ExecComp('x = r*cos(theta)'))
# create a model that computes y = r*sin(theta)
submodel2 = om.Group()
submodel2.add_subsystem('sub2_ivc_r', om.IndepVarComp('r', 2),
promotes_outputs=['r'])
submodel2.add_subsystem('sub2_ivc_theta', om.IndepVarComp('theta', pi/2),
promotes_outputs=['theta'])
submodel2.add_subsystem('subComp2', om.ExecComp('y = r*sin(theta)'))
# wrap the x and y models as sub-problems
subprob1 = om.Problem()
subprob1.model.add_subsystem('submodel1', submodel1, promotes=['*'])
subprob2 = om.Problem()
subprob2.model.add_subsystem('submodel2', submodel2, promotes=['*'])
comp1 = om.SubmodelComp(problem=subprob1)
comp2 = om.SubmodelComp(problem=subprob2)
# add inputs and outputs for the sub-problems
comp1.add_input('subComp1.r', name='r')
comp1.add_input('subComp1.theta', name='theta')
comp2.add_input('subComp2.r', name='r')
comp2.add_input('subComp2.theta', name='theta')
comp1.add_output('subComp1.x', name='x')
comp2.add_output('subComp2.y', name='y')
# add both sub-problems and a Component that uses their outputs
p.model.add_subsystem('sub1', comp1,
promotes_inputs=['r','theta'],
promotes_outputs=['x'])
p.model.add_subsystem('sub2', comp2,
promotes_inputs=['r','theta'],
promotes_outputs=['y'])
p.model.add_subsystem('supComp', om.ExecComp('z = x**2 + y'),
promotes_inputs=['x', 'y'],
promotes_outputs=['z'])
p.model.set_input_defaults('r', 1)
p.model.set_input_defaults('theta', pi)
p.setup(force_alloc_complex=True)
p.run_model()
cpd = p.check_partials(method='cs', out_stream=None)
Example: Adding Inputs and Outputs in Configure#
import openmdao.api as om
class Subsys1(om.Group):
def setup(self):
model = om.Group()
comp = om.ExecComp('x = r*cos(theta)')
model.add_subsystem('comp', comp, promotes_inputs=['r', 'theta'],
promotes_outputs=['x'])
subprob = om.Problem()
subprob.model.add_subsystem('model', model)
subprob.model.promotes('model', any=['*'])
self.add_subsystem('submodel1', om.SubmodelComp(problem=subprob))
def configure(self):
self._get_subsystem('submodel1').add_input('r')
self._get_subsystem('submodel1').add_input('theta')
self._get_subsystem('submodel1').add_output('x')
self.promotes('submodel1', ['r', 'theta', 'x'])
class Subsys2(om.Group):
def setup(self):
model = om.Group()
comp = om.ExecComp('y = r*sin(theta)')
model.add_subsystem('comp', comp, promotes_inputs=['r', 'theta'],
promotes_outputs=['y'])
subprob = om.Problem()
subprob.model.add_subsystem('model', model)
subprob.model.promotes('model', any=['*'])
self.add_subsystem('submodel2', om.SubmodelComp(problem=subprob))
def configure(self):
self._get_subsystem('submodel2').add_input('r')
self._get_subsystem('submodel2').add_input('theta')
self._get_subsystem('submodel2').add_output('y')
self.promotes('submodel2', ['r', 'theta', 'y'])
p = om.Problem()
p.model.add_subsystem('sub1', Subsys1(),
promotes_inputs=['r', 'theta'],
promotes_outputs=['x'])
p.model.add_subsystem('sub2', Subsys2(),
promotes_inputs=['r', 'theta'],
promotes_outputs=['y'])
p.model.add_subsystem('supComp', om.ExecComp('z = x**2 + y'),
promotes_inputs=['x', 'y'],
promotes_outputs=['z'])
p.setup(force_alloc_complex=True)
p.set_val('r', 1)
p.set_val('theta', pi)
p.run_model()
cpd = p.check_partials(method='cs', out_stream=None)