Conversion Guide for the Auto-IVC (IndepVarComp) Feature
Contents
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):
# this input will connect to entries 0, 1, and 2 of its source
self.add_input('x', np.ones(3), src_indices=[0, 1, 2])
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):
# this input will connect to entries 3 and 4 of its source
self.add_input('x', np.ones(2), src_indices=[3, 4])
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(), promotes_inputs=['x'])
p.model.add_subsystem('C2', MyComp2(), promotes_inputs=['x'])
p.model.add_design_var('x')
p.setup()
p.run_model()
class MyComp1(om.ExplicitComponent):
def setup(self):
# this input will connect to entries 0, 1, and 2 of its source
self.add_input('x', np.ones(3), src_indices=[0, 1, 2])
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):
# this input will connect to entries 3 and 4 of its source
self.add_input('x', np.ones(2), src_indices=[3, 4])
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(), promotes_inputs=['x'])
p.model.add_subsystem('C2', MyComp2(), promotes_inputs=['x'])
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()
%%px
import openmdao.api as om
from openmdao.utils.array_utils import take_nth
class DistribNoncontiguousComp(om.ExplicitComponent):
"""Uses 4 procs and takes non-contiguous input var slices and has output
var slices as well
"""
def initialize(self):
self.options.declare('arr_size', types=int, default=11,
desc="Size of input and output vectors.")
def compute(self, inputs, outputs):
outputs['outvec'] = inputs['invec']*2.0
def setup(self):
comm = self.comm
rank = comm.rank
arr_size = self.options['arr_size']
idxs = list(take_nth(rank, comm.size, range(arr_size)))
self.add_input('invec', np.ones(len(idxs), float), distributed=True)
self.add_output('outvec', np.ones(len(idxs), float), distributed=True)
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)