MuxComp#
MuxComp works to combine
multiple inputs into a single value. This can be useful in situations where scalar outputs
from multiple components need to be fed into a single vectorized component.
MuxComp combines two or more inputs into a single output by stacking them along an axis.
MuxComp Options#
MuxComp has a single option, vec_size, which provides the number of inputs to be
combined into a single output. The default value of vec_size is 2.
Adding Variables#
A single MuxComp can mux multiple variables, so long as all variables
are compatible with the given vec_size. Variables are added via the add_var method.
The axis along which the muxing is to occur is given via the axis argument.
The variables are joined along a new dimension, the index of which is given by axis.
The specified axis follows the convention used by the numpy.stack function.
Giving axis = 0 will stack the inputs along the first axis (vertically).
Giving axis = 1 will stack the inputs along the second axis (horizontally).
Giving axis = -1 will stack the inputs along the last axis, and so is dependent on the shape of the inputs.
Due to the axis convention of numpy.stack, the axis index is only valid if it is less than or
equal to the number of dimensions in the inputs.
For example, 1D arrays can be stacked vertically (axis = 0) or horizontally (axis = 1), but not
depth-wise (axis = 2).
- MuxComp.add_var(name, val=1.0, shape=None, units=None, desc='', axis=0)[source]
Add an output variable to be muxed, and all associated input variables.
- Parameters:
- namestr
Name of the variable in this component’s namespace.
- valfloat or list or tuple or ndarray or Iterable
The initial value of the variable being added in user-defined units. Default is 1.0.
- shapeint or tuple or list or None
Shape of the input variables to be muxed, only required if val is not an array. Default is None.
- unitsstr or None
Units in which this input variable will be provided to the component during execution. Default is None, which means it is unitless.
- descstr
Description of the variable.
- axisint
The axis along which the elements will be stacked. Note that N-dimensional inputs cannot be stacked along an axis greater than N.
Example: Muxing 3 (n x 1) columns into a single (n x 3) matrix#
In this example we start with three (n x 1) column vectors (x, y, and z) and
combine them into a single position vector r (n x 3). This is achieved by stacking the vectors
along axis = 1. Like the previous example, this is somewhat contrived but is intended to demonstrate
the capabilities of the MuxComp.
import numpy as np
import openmdao.api as om
# The number of elements to be muxed
n = 3
# The size of each element to be muxed
m = 100
p = om.Problem()
mux_comp = p.model.add_subsystem(name='mux', subsys=om.MuxComp(vec_size=n))
mux_comp.add_var('r', shape=(m,), axis=1, units='m')
p.model.add_subsystem(name='vec_mag_comp',
subsys=om.VectorMagnitudeComp(vec_size=m, length=n, in_name='r',
mag_name='r_mag', units='m'))
p.model.connect('mux.r', 'vec_mag_comp.r')
p.setup()
p.set_val('mux.r_0', 1 + np.random.rand(m))
p.set_val('mux.r_1', 1 + np.random.rand(m))
p.set_val('mux.r_2', 1 + np.random.rand(m))
p.run_model()
# Verify the results against numpy.dot in a for loop.
for i in range(n):
r_i = [p.get_val('mux.r_0')[i], p.get_val('mux.r_1')[i], p.get_val('mux.r_2')[i]]
expected_i = np.sqrt(np.dot(r_i, r_i))
print(p.get_val('vec_mag_comp.r_mag')[i])
2.685962574174284
2.5298618941199544
2.634555197777959
Example: Using om.slicer to reduce a 3-column matrix into constituent vectors#
The inverse functionality, that is “demuxing” or breaking up of inputs into multiple values, is accomplished using the om.slicer() utility.
This example is contrived and could be achieved with a single vectorized component, but it serves to give an example of how this would be implemented.
import numpy as np
import openmdao.api as om
# The number of elements to be demuxed
n = 3
arr_5x3 = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12],
[13, 14, 15],
])
p = om.Problem()
p.model.add_subsystem('indep', om.IndepVarComp('x', arr_5x3, units='km'), promotes=['*'])
p.model.add_subsystem('indep2', om.IndepVarComp('y', arr_5x3, units='km'), promotes=['*'])
p.model.add_subsystem(name='longitude_comp',
subsys=om.ExecComp('long = atan(y/x)',
x={'val': np.ones(n), 'units': 'km'},
y={'val': np.ones(n), 'units': 'km'},
long={'val': np.ones(n), 'units': 'rad'}))
# Use the src_indices arg in promotes to perform the demuxing
p.model.promotes('longitude_comp', inputs=['x'], src_indices=om.slicer[0, :])
p.model.promotes('longitude_comp', inputs=['y'], src_indices=om.slicer[1, :])
p.setup()
p.run_model()
print(p.get_val('longitude_comp.x'))
print(p.get_val('longitude_comp.y'))
print(p.get_val('longitude_comp.long'))
[1. 2. 3.]
[4. 5. 6.]
[1.32581766 1.19028995 1.10714872]