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.2868145687763044
2.5882497142915994
3.1634019903189774
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]