The set_input_defaults function#

The set_input_defaults function in OpenMDAO is used to specify metadata for inputs that are promoted to the same name within a Group. This is necessary when multiple inputs within a Group are promoted to the same name, but their units or initial values differ. If set_input_defaults is not used in this scenario, OpenMDAO will raise an error during setup.

Group.set_input_defaults(name, val=UNDEFINED, units=None, src_shape=None)[source]

Specify metadata to be assumed when multiple inputs are promoted to the same name.

Parameters:
namestr

Promoted input name.

valobject

Value to assume for the promoted input.

unitsstr or None

Units to assume for the promoted input.

src_shapeint or tuple

Assumed shape of any connected source or higher level promoted input.

This function does not set the actual values of the inputs, only the metadata that will be used to populate the AutoIVC output connected to them. The metadata specified via set_input_defaults is applied during the model setup phase, when the AutoIVC connections are resolved.

Example #1#

In this example, we have two components that promote the variable x but use different units. This will result in an error during setup if left unresolved:

import openmdao.api as om

p1 = om.Problem()
model = p1.model

# Note that units and value to use for the promoted variable 'x' are ambiguous due to having different defaults
model.add_subsystem('C1', om.ExecComp('y = 3.*x', x={'val': 3000., 'units': 'mm'}), promotes=['x'])
model.add_subsystem('C2', om.ExecComp('y = 4.*x', x={'val': 400., 'units': 'cm'}), promotes=['x'])

p1.setup()
try:
    p1.final_setup()
except Exception as err:
    print(str(err))
Collected errors for problem 'problem':
   <model> <class Group>: The following inputs, ['C1.x', 'C2.x'], promoted to 'x', are connected but their metadata entries ['units', 'val'] differ. Call model.set_input_defaults('x', units=?, val=?) to remove the ambiguity.

The ambiguity can be resolved by setting the desired default values for the promoted variable at the group level by calling set_input_defaults:

model.set_input_defaults('x', val=1., units='m')

# Note that the we have specified the default metadata for the AutoIVC output that will supply values
# for the promoted 'x' (_auto_ivc.v0) but it has not been applied yet. It will be applied during setup.

# Calling list_vars (or list_inputs/list_outputs) at this point will show the default values from the component definitions
model.list_vars(units=True, list_autoivcs=True);
5 Variables(s) in 'model'

varname    val      io      units  prom_name
---------  -------  ------  -----  ---------
_auto_ivc
  v0       [3000.]  output  mm     x        
C1
  x        [3000.]  input   mm     x        
  y        [1.]     output  None   C1.y     
C2
  x        [400.]   input   cm     x        
  y        [1.]     output  None   C2.y     
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:4431: OpenMDAOWarning:Calling `list_vars` before `final_setup` will only display the default values of variables and will not show the result of any `set_val` calls.
p1.setup()

# now the default value and units for the AutoIVC have been applied
model.list_vars(units=True, list_autoivcs=True);
4 Variables(s) in 'model'

varname  val      io      units  prom_name
-------  -------  ------  -----  ---------
C1
  x      [3000.]  input   mm     x        
  y      [1.]     output  None   C1.y     
C2
  x      [400.]   input   cm     x        
  y      [1.]     output  None   C2.y     
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:4431: OpenMDAOWarning:Calling `list_vars` before `final_setup` will only display the default values of variables and will not show the result of any `set_val` calls.
p1.run_model()

model.list_vars(units=True, list_autoivcs=True);
5 Variables(s) in 'model'

varname    val      io      units  prom_name
---------  -------  ------  -----  ---------
_auto_ivc
  v0       [1.]     output  m      x        
C1
  x        [1000.]  input   mm     x        
  y        [3000.]  output  None   C1.y     
C2
  x        [100.]   input   cm     x        
  y        [400.]   output  None   C2.y     

Example #2#

For nested groups, set_input_defaults can be called in the sub-group’s configure method:

import openmdao.api as om

class MyGroup(om.Group):
    def setup(self):
        self.add_subsystem('C1', om.ExecComp('y = 3.*x', x={'val': 3000., 'units': 'mm'}), promotes=['x'])
        self.add_subsystem('C2', om.ExecComp('y = 4.*x', x={'val': 400., 'units': 'cm'}), promotes=['x'])

    def configure(self):
        self.set_input_defaults('x', val=1., units='m')

p2 = om.Problem()
model = p2.model

model.add_subsystem('G', MyGroup())

p2.setup()
p2.run_model()

model.list_vars(units=True, list_autoivcs=True);
5 Variables(s) in 'model'

varname    val      io      units  prom_name
---------  -------  ------  -----  ---------
_auto_ivc
  v0       [1.]     output  m      G.x      
G
  C1
    x      [1000.]  input   mm     G.x      
    y      [3000.]  output  None   G.C1.y   
  C2
    x      [100.]   input   cm     G.x      
    y      [400.]   output  None   G.C2.y   

Example #3#

The above examples demonstrate the use of set_input_defaults to disambiguate default values and units. The following example shows how to use the src_shape argument to specify the shape of an input that may be different then the promoted variables:

import numpy as np
import openmdao.api as om

class MyComp1(om.ExplicitComponent):
    """ multiplies input array by 2. """
    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):
    """ multiplies input array by 4. """
    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

class MyGroup(om.Group):
    def setup(self):
        self.add_subsystem('comp1', MyComp1())
        self.add_subsystem('comp2', MyComp2())

    def configure(self):
        # splits input via promotes using src_indices
        self.promotes('comp1', inputs=['x'], src_indices=[0, 1, 2])
        self.promotes('comp2', inputs=['x'], src_indices=[3, 4])

p3 = om.Problem()

# Note: src_shape is different that the shape of either target
p3.model.set_input_defaults('x', src_shape=(5,), val=1.)

p3.model.add_subsystem('G1', MyGroup(), promotes_inputs=['x'])

p3.setup()
p3.final_setup()

p3.get_val('x')
array([1., 1., 1., 1., 1.])

Example #4#

The set_input_defaults function can be used to set default values for discrete variables as well.

In the following example, the intent is to set the material for all objects by promoting it as a discrete variable from each component and setting it for the whole model:

import math
import openmdao.api as om

density = {
    'steel': 7.85,  # g/cm^3
    'aluminum': 2.7  # g/cm^3
}

class SquarePlate(om.ExplicitComponent):
    """
    Calculate the weight of a square plate.
    material is a discrete input (default: steel)
    """
    def setup(self):
        self.add_discrete_input('material', 'steel')

        self.add_input('length', 1.0, units='cm')
        self.add_input('width', 1.0, units='cm')
        self.add_input('thickness', 1.0, units='cm')

        self.add_output('weight', 1.0, units='g')

    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
        length = inputs['length']
        width = inputs['width']
        thickness = inputs['thickness']
        material = discrete_inputs['material']

        outputs['weight'] = length * width * thickness * density[material]

class CirclePlate(om.ExplicitComponent):
    """
    Calculate the weight of a circular plate.
    material is a discrete input (default: aluminum)
    """
    def setup(self):
        self.add_discrete_input('material', 'aluminum')

        self.add_input('radius', 1.0, units='cm')
        self.add_input('thickness', 1.0, units='g')

        self.add_output('weight', 1.0, units='g')

    def compute(self, inputs, outputs, discrete_inputs, discrete_output):
        radius = inputs['radius']
        thickness = inputs['thickness']
        material = discrete_inputs['material']

        outputs['weight'] =  math.pi * radius**2 * thickness * density[material]

p4 = om.Problem()
model = p4.model

model.add_subsystem('square', SquarePlate(), promotes_inputs=['material'])
model.add_subsystem('circle', CirclePlate(), promotes_inputs=['material'])

model.set_input_defaults('material', 'steel')

p4.setup()

p4.run_model()

model.list_vars(units=True);
9 Variables(s) in 'model'

varname      val            io      units  prom_name       
-----------  -------------  ------  -----  ----------------
square
  length     [1.]           input   cm     square.length   
  width      [1.]           input   cm     square.width    
  thickness  [1.]           input   cm     square.thickness
  weight     [7.85]         output  g      square.weight   
  material   steel          input   n/a    material        
circle
  radius     [1.]           input   cm     circle.radius   
  thickness  [1.]           input   g      circle.thickness
  weight     [24.66150233]  output  g      circle.weight   
  material   steel          input   n/a    material        

Note that setting units or src_shape is not valid for a discrete variable and will result in an error if either of those arguments are supplied:

p5 = om.Problem()
model = p5.model

model.add_subsystem('square', SquarePlate(), promotes_inputs=['material'])
model.add_subsystem('circle', CirclePlate(), promotes_inputs=['material'])

model.set_input_defaults('material', 'steel', units='g', src_shape=(1,))

try:
    p5.setup()
except Exception as err:
    print(str(err))

How the set_input_defaults function differs from the set_val function#

While both set_input_defaults and set_val deal with variable management in OpenMDAO, they have distinct purposes and are used in different contexts.

  • set_input_defaults is used at the group level to define default metadata (units and initial value) for promoted inputs, specifically to resolve ambiguity when multiple inputs are promoted to the same name. This is crucial for inputs connected to the automatically generated _auto_ivc component.

    • Used to resolve inconsistencies between Auto-IVC values.

    • Specifically used at the group level to specify metadata to be assumed when multiple inputs are promoted to the same name. This is required when the promoted inputs have differing units or values.

  • set_val is used at the problem level to set the actual value of a variable, including inputs, outputs, and implicit state variables. It can handle unit conversions and set values for specific indices in array variables.

    • Used at the run script level to set the value of an input variable.

    • Can be used to set the value of a variable in a different unit than its declared unit, and OpenMDAO will perform the conversion.

    • Can be used to set specific indices or index ranges of array variables.

In essence, set_input_defaults helps OpenMDAO correctly determine the units and initial values of connected inputs during the setup phase, while set_val is used to directly manipulate variable values before or during a run.

Key Differences

  • Scope: set_input_defaults is used at the group level to define default metadata for promoted inputs, while set_val is used at the problem level to set specific values for variables.

  • Purpose: set_input_defaults resolves ambiguities when multiple inputs are promoted to the same name, while set_val is used to assign values to variables.

  • Timing: set_input_defaults is typically called during the model setup phase, while set_val can be called before or during a run of the model.