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()))

OptionDefaultAcceptable ValuesAcceptable TypesDescription
always_optFalse[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.
distributedFalse[True, False]['bool']If True, set all variables in this component as distributed across multiple processes
do_coloringFalse[True, False]['bool']If True, attempt to compute a total coloring for the submodel.
run_root_onlyFalse[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.

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)