Conversion Guide for the Auto-IVC (IndepVarComp) Feature#

As of the OpenMDAO 3.2 release, it is no longer necessary to add an IndepVarComp to your model to handle the assignment of unconnected inputs as design variables.

Declaring Design Variables#

This is what we used to do

import openmdao.api as om

prob = om.Problem()
indeps = prob.model.add_subsystem('indeps', om.IndepVarComp())
indeps.add_output('x', 3.0)
indeps.add_output('y', -4.0)

prob.model.add_subsystem('paraboloid',
                         om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3'))

prob.model.connect('indeps.x', 'paraboloid.x')
prob.model.connect('indeps.y', 'paraboloid.y')

# setup the optimization
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'

prob.model.add_design_var('indeps.x', lower=-50, upper=50)
prob.model.add_design_var('indeps.y', lower=-50, upper=50)
prob.model.add_objective('paraboloid.f')

prob.setup()
prob.run_driver()

This is how we handle IVCs now

prob = om.Problem()

prob.model.add_subsystem('paraboloid',
                         om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3'),
                         promotes_inputs=['x', 'y'])

# setup the optimization
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'

prob.model.add_design_var('x', lower=-50, upper=50)
prob.model.add_design_var('y', lower=-50, upper=50)
prob.model.add_objective('paraboloid.f')

prob.setup()

prob['x'] = 3.0
prob['y'] = -4.0

prob.run_driver()

Declaring a Multi-Component Input as a Design Variable#

import openmdao.api as om

prob = om.Problem()
indeps = prob.model.add_subsystem('indeps', om.IndepVarComp())
indeps.add_output('x', 3.0)
indeps.add_output('y', -4.0)

prob.model.add_subsystem('parab', Paraboloid())

# define the component whose output will be constrained
prob.model.add_subsystem('const', om.ExecComp('g = x + y'))

prob.model.connect('indeps.x', ['parab.x', 'const.x'])
prob.model.connect('indeps.y', ['parab.y', 'const.y'])

# setup the optimization
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'COBYLA'

prob.model.add_design_var('indeps.x', lower=-50, upper=50)
prob.model.add_design_var('indeps.y', lower=-50, upper=50)
prob.model.add_objective('parab.f_xy')

# to add the constraint to the model
prob.model.add_constraint('const.g', lower=0, upper=10.)
# prob.model.add_constraint('const.g', equals=0.)

prob.setup()
prob.run_driver()
prob = om.Problem()
prob.model.add_subsystem('parab', Paraboloid(),
                         promotes_inputs=['x', 'y'])

# define the component whose output will be constrained
prob.model.add_subsystem('const', om.ExecComp('g = x + y'),
                         promotes_inputs=['x', 'y'])

# Design variables 'x' and 'y' span components, so we need to provide a common initial
# value for them.
prob.model.set_input_defaults('x', 3.0)
prob.model.set_input_defaults('y', -4.0)

# setup the optimization
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'COBYLA'

prob.model.add_design_var('x', lower=-50, upper=50)
prob.model.add_design_var('y', lower=-50, upper=50)
prob.model.add_objective('parab.f_xy')

# to add the constraint to the model
prob.model.add_constraint('const.g', lower=0, upper=10.)

prob.setup()
prob.run_driver()

Declaring a New Name for a Promoted Input#

prob = om.Problem()

indeps = prob.model.add_subsystem('indeps', om.IndepVarComp())
indeps.add_output('width', 3.0)
indeps.add_output('length', -4.0)

prob.model.add_subsystem('paraboloid',
                       om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3'))

prob.model.connect('indeps.width', 'paraboloid.x')
prob.model.connect('indeps.length', 'paraboloid.y')

prob.setup()
prob = om.Problem()

prob.model.add_subsystem('paraboloid',
                         om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3'),
                         promotes_inputs=[('x', 'width'), ('y', 'length')])

# Could also set these after setup.
prob.model.set_input_defaults('width', 3.0)
prob.model.set_input_defaults('length', -4.0)

prob.setup()

Declare an Input Defined with Source Indices as a Design Variable#

class MyComp1(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', np.ones(3))
        self.add_output('y', 1.0)

    def compute(self, inputs, outputs):
        outputs['y'] = np.sum(inputs['x'])*2.0

class MyComp2(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', np.ones(2))
        self.add_output('y', 1.0)

    def compute(self, inputs, outputs):
        outputs['y'] = np.sum(inputs['x'])*4.0

p = om.Problem()

p.model.add_subsystem('indep', om.IndepVarComp('x', np.ones(5)),
                      promotes_outputs=['x'])
p.model.add_subsystem('C1', MyComp1())
p.model.add_subsystem('C2', MyComp2())

# this input will connect to entries 0, 1, and 2 of its source
p.model.promotes('C1', inputs=['x'], src_indices=[0, 1, 2])

# this input will connect to entries 3 and 4 of its source
p.model.promotes('C2', inputs=['x'], src_indices=[3, 4])

p.model.add_design_var('x')
p.setup()
p.run_model()
class MyComp1(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', np.ones(3))
        self.add_output('y', 1.0)

    def compute(self, inputs, outputs):
        outputs['y'] = np.sum(inputs['x'])*2.0

class MyComp2(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', np.ones(2))
        self.add_output('y', 1.0)

    def compute(self, inputs, outputs):
        outputs['y'] = np.sum(inputs['x'])*4.0

p = om.Problem()

# IndepVarComp is required to define the full size of the source vector.
p.model.add_subsystem('indep', om.IndepVarComp('x', np.ones(5)),
                      promotes_outputs=['x'])
p.model.add_subsystem('C1', MyComp1())
p.model.add_subsystem('C2', MyComp2())

# this input will connect to entries 0, 1, and 2 of its source
p.model.promotes('C1', inputs=['x'], src_indices=[0, 1, 2])

# this input will connect to entries 3 and 4 of its source
p.model.promotes('C2', inputs=['x'], src_indices=[3, 4])

p.model.add_design_var('x')
p.setup()
p.run_model()

Setting Default Units for an Input#

prob = om.Problem()

ivc = om.IndepVarComp()
ivc.add_output('x2', 100.0, units='degC')
prob.model.add_subsystem('T1', ivc,
                       promotes_outputs=['x2'])

# Input units in degF
prob.model.add_subsystem('tgtF', TgtCompF(),
                       promotes_inputs=['x2'])

# Input units in degC
prob.model.add_subsystem('tgtC', TgtCompC(),
                       promotes_inputs=['x2'])

# Input units in deg
prob.model.add_subsystem('tgtK', TgtCompK(),
                       promotes_inputs=['x2'])

prob.setup()
prob = om.Problem()

# Input units in degF
prob.model.add_subsystem('tgtF', TgtCompF(),
                         promotes_inputs=['x2'])

# Input units in degC
prob.model.add_subsystem('tgtC', TgtCompC(),
                         promotes_inputs=['x2'])

# Input units in degK
prob.model.add_subsystem('tgtK', TgtCompK(),
                         promotes_inputs=['x2'])

prob.model.set_input_defaults('x2', 100.0, units='degC')

prob.setup()

Creating a Distributed Component with Unconnected Inputs#

size = 4

prob = om.Problem()

prob.model.add_subsystem("C1", DistribNoncontiguousComp(arr_size=size),
                       promotes=['invec', 'outvec'])

prob.setup()

rank = prob.model.comm.rank
if rank == 0:
    prob.set_val('invec', np.array([1.0, 3.0]))
else:
    prob.set_val('invec', np.array([5.0, 7.0]))

prob.run_model()
size = 4

prob = om.Problem()

# An IndepVarComp is required on all unconnected distributed inputs.
ivc = om.IndepVarComp()
ivc.add_output('invec', np.ones(size), distributed=True)
prob.model.add_subsystem('P', ivc,
                         promotes_outputs=['invec'])

prob.model.add_subsystem("C1", DistribNoncontiguousComp(arr_size=size),
                         promotes=['invec', 'outvec'])

prob.setup()

prob.set_val('P.invec', np.array([1.0, 3.0, 5.0, 7.0]))

prob.run_model()

Setting and Getting Inputs#

prob = om.Problem()
indeps = prob.model.add_subsystem('indeps', om.IndepVarComp())
indeps.add_output('x', 3.0)
indeps.add_output('y', -4.0)

prob.model.add_subsystem('paraboloid',
                         om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3'))

prob.model.connect('indeps.x', 'paraboloid.x')
prob.model.connect('indeps.y', 'paraboloid.y')

prob.setup()

x = prob.get_val('indeps.x')
prob.set_val('indeps.y', 15.0)
prob = om.Problem()

prob.model.add_subsystem('paraboloid',
                         om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3'),
                         promotes_inputs=['x', 'y'])

prob.setup()

x = prob.get_val('x')
prob.set_val('y', 15.0)