DotProductComp#

DotProductComp performs a dot product between two compatible inputs. It may be vectorized to provide the result at one or more points simultaneously.

\[ c_i = \bar{a}_i \cdot \bar{b}_i \]

DotProductComp Options#

The default vec_size is 1, providing the dot product of \(a\) and \(b\) at a single point. The lengths of \(a\) and \(b\) are provided by option length.

Other options for DotProductComp allow the user to rename the input variables \(a\) and \(b\) and the output \(c\), as well as specifying their units.

OptionDefaultAcceptable ValuesAcceptable TypesDescription
a_nameaN/A['str']The variable name for input vector a.
a_unitsN/AN/A['str']The units for vector a.
always_optFalse[True, False]['bool']If True, force nonlinear operations on this component to be included in the optimization loop even if this component is not relevant to the design variables and responses.
b_namebN/A['str']The variable name for input vector b.
b_unitsN/AN/A['str']The units for vector b.
c_namecN/A['str']The variable name for output vector c.
c_unitsN/AN/A['str']The units for vector c.
derivs_methodN/A['jax', 'cs', 'fd', None]N/AThe method to use for computing derivatives
distributedFalse[True, False]['bool']If True, set all variables in this component as distributed across multiple processes
length3N/A['int']The length of vectors a and b
run_root_onlyFalse[True, False]['bool']If True, call compute, compute_partials, linearize, apply_linear, apply_nonlinear, and compute_jacvec_product only on rank 0 and broadcast the results to the other ranks.
use_jitTrue[True, False]['bool']If True, attempt to use jit on compute_primal, assuming jax or some other AD package is active.
vec_size1N/A['int']The number of points at which the dot product is computed

DotProductComp Constructor#

The call signature for the DotProductComp constructor is:

DotProductComp.__init__(**kwargs)[source]

Initialize the Dot Product component.

DotProductComp Usage#

There are often situations when numerous products need to be computed, essentially in parallel. You can reduce the number of components required by having one DotProductComp perform multiple operations. This is also convenient when the different operations have common inputs.

The add_product method is used to create additional products after instantiation.

DotProductComp.add_product(c_name, a_name='a', b_name='b', c_units=None, a_units=None, b_units=None, vec_size=1, length=3)[source]

Add a new output product to the dot product component.

Parameters:
c_namestr

The name of the vector product output.

a_namestr

The name of the first vector input.

b_namestr

The name of the second input.

c_unitsstr or None

The units of the output.

a_unitsstr or None

The units of input a.

b_unitsstr or None

The units of input b.

vec_sizeint

The number of points at which the dot vector product should be computed simultaneously. The shape of the output is (vec_size,).

lengthint

The length of the vectors a and b. Their shapes are (vec_size, length).

DotProductComp Example#

In the following example DotProductComp is used to compute instantaneous power as the dot product of force and velocity at 100 points simultaneously. Note the use of a_name, b_name, and c_name to assign names to the inputs and outputs. Units are assigned using a_units, b_units, and c_units. Note that no internal checks are performed to ensure that c_units are consistent with a_units and b_units.

import numpy as np
import openmdao.api as om

n = 24

p = om.Problem()

dp_comp = om.DotProductComp(vec_size=n, length=3, a_name='F', b_name='v', c_name='P',
                            a_units='N', b_units='m/s', c_units='W')

p.model.add_subsystem(name='dot_prod_comp', subsys=dp_comp,
                     promotes_inputs=[('F', 'force'), ('v', 'vel')])

p.setup()

p.set_val('force', np.random.rand(n, 3))
p.set_val('vel', np.random.rand(n, 3))

p.run_model()

# Verify the results against numpy.dot in a for loop.
expected = []
for i in range(n):
    a_i = p.get_val('force')[i, :]
    b_i = p.get_val('vel')[i, :]
    expected.append(np.dot(a_i, b_i))

    actual_i = p.get_val('dot_prod_comp.P')[i]
    rel_error = np.abs(expected[i] - actual_i)/actual_i
    assert rel_error < 1e-9, f"Relative error: {rel_error}"

print(p.get_val('dot_prod_comp.P', units='kW'))
[0.00148426 0.00081653 0.00046695 0.00050623 0.00033433 0.0010325
 0.00084326 0.00072877 0.0008672  0.00104245 0.00078472 0.0004424
 0.00092914 0.00063798 0.00123198 0.00103439 0.00093749 0.0009753
 0.00056013 0.00021286 0.00092547 0.001315   0.00068833 0.00083587]

DotProductComp Example with Multiple Products#

When defining multiple products:

  • An input name in one call to add_product may not be an output name in another call, and vice-versa.

  • The units and shape of variables used across multiple products must be the same in each one.

n = 24

p = om.Problem()

dp_comp = om.DotProductComp(vec_size=n, length=3,
                            a_name='F', b_name='d', c_name='W',
                            a_units='N', b_units='m', c_units='J')

dp_comp.add_product(vec_size=n, length=3,
                    a_name='F', b_name='v', c_name='P',
                    a_units='N', b_units='m/s', c_units='W')

p.model.add_subsystem(name='dot_prod_comp', subsys=dp_comp,
                      promotes_inputs=[('F', 'force'), ('d', 'disp'), ('v', 'vel')])

p.setup()

p.set_val('force', np.random.rand(n, 3))
p.set_val('disp', np.random.rand(n, 3))
p.set_val('vel', np.random.rand(n, 3))

p.run_model()

# Verify the results against numpy.dot in a for loop.
expected_P = []
expected_W = []
for i in range(n):
    a_i = p.get_val('force')[i, :]

    b_i = p.get_val('disp')[i, :]
    expected_W.append(np.dot(a_i, b_i))

    actual_i = p.get_val('dot_prod_comp.W')[i]
    rel_error = np.abs(actual_i - expected_W[i])/actual_i
    assert rel_error < 1e-9, f"Relative error: {rel_error}"

    b_i = p.get_val('vel')[i, :]
    expected_P.append(np.dot(a_i, b_i))

    actual_i = p.get_val('dot_prod_comp.P')[i]
    rel_error = np.abs(expected_P[i] - actual_i)/actual_i
    assert rel_error < 1e-9, f"Relative error: {rel_error}"

print(p.get_val('dot_prod_comp.W', units='kJ'))
[0.00060654 0.00097888 0.00137741 0.00046485 0.00042112 0.00041937
 0.00035177 0.0012071  0.00131611 0.00037301 0.00030558 0.00040842
 0.00155313 0.00073003 0.00103939 0.00096253 0.00027821 0.00075883
 0.00063468 0.00068416 0.00025707 0.00071574 0.00053135 0.00073681]
print(p.get_val('dot_prod_comp.P', units='kW'))
[5.32947078e-04 1.09481925e-03 1.01497067e-03 2.76135868e-04
 2.73535268e-04 5.83186320e-04 7.90366437e-04 1.42356888e-03
 1.40889866e-03 7.86839992e-04 3.38324277e-04 8.51893106e-04
 1.91536820e-03 9.50483477e-04 1.14760653e-03 1.89723559e-04
 9.94225241e-05 7.53370906e-04 6.78116319e-04 5.94075647e-04
 1.38244227e-03 6.09664031e-04 1.82653505e-04 7.38396938e-04]