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_coloringTrue[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)
Full total jacobian for problem 'problem2/problem3' was computed 3 times, taking 0.0015432010000040464 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
Full total jacobian for problem 'problem2/problem4' was computed 3 times, taking 0.00208426500000769 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'sub1' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'sub2' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).

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();
Full total jacobian for problem 'problem6/problem5' was computed 3 times, taking 0.0010955230000035954 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
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'
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'subcomp' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).

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();
Full total jacobian for problem 'problem7/problem8' was computed 3 times, taking 0.0015808019999212775 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
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'
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'comp' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).

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()
Full total jacobian for problem 'problem9/problem10' was computed 3 times, taking 0.0012931429999980537 seconds.
Total jacobian shape: (1, 3) 

No coloring was computed successfully.
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'
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'comp' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).

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)
Full total jacobian for problem 'problem11/problem12' was computed 3 times, taking 0.0012178519999679338 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
Full total jacobian for problem 'problem11/problem13' was computed 3 times, taking 0.0020515439999826413 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'sub1' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'sub2' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).

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)
Full total jacobian for problem 'problem14/problem15' was computed 3 times, taking 0.0012061200000061945 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
Full total jacobian for problem 'problem14/problem16' was computed 3 times, taking 0.001481846999922709 seconds.
Total jacobian shape: (1, 2) 

No coloring was computed successfully.
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'sub1.submodel1' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/utils/coloring.py:387: DerivativesWarning:'sub2.submodel2' <class SubmodelComp>: Coloring was deactivated.  Improvement of 0.0% was less than min allowed (5.0%).