ExplicitComponent#
Explicit variables are those that are computed as an explicit function of other variables. For instance, \(z\) would be an explicit variable, given \(z=sin(y)\), while \(y\) would not be, given that it is defined implicitly by the nonlinear equation \(cos(x⋅y)−z⋅y=0\).
In OpenMDAO, explicit variables are defined by writing a class that inherits from the ExplicitComponent class. The explicit variables would be considered outputs while the variables on which they depend would be considered inputs (e.g., \(y\) in \(z=sin(y)\)).
ExplicitComponent Methods#
The implementation of each method will be illustrated using a simple explicit component that computes the output area as a function of inputs length and width.
import openmdao.api as om
class RectangleComp(om.ExplicitComponent):
"""
A simple Explicit Component that computes the area of a rectangle.
"""
setup()
:
Declare input and output variables via add_input
and add_output
. Information such as variable names, sizes, units, and bounds are declared here.
def setup(self):
self.add_input('length', val=1.)
self.add_input('width', val=1.)
self.add_output('area', val=1.)
setup_partials()
:
Declare partial derivatives that this component provides, using wild cards to say that this component provides derivatives of all outputs with respect to all inputs.
def setup_partials(self):
self.declare_partials('*', '*')
compute(inputs, outputs)
:
Compute the outputs
given the inputs
.
def compute(self, inputs, outputs):
outputs['area'] = inputs['length'] * inputs['width']
compute_partials(inputs, partials)
:
Note
[Optional] Compute the partials
(partial derivatives) given the inputs
.
def compute_partials(self, inputs, partials):
partials['area', 'length'] = inputs['width']
partials['area', 'width'] = inputs['length']
The Matrix-Free API: Providing derivatives as a matrix-vector product#
compute_jacvec_product(inputs, d_inputs, d_outputs, mode)
:
Note
[Optional] Provide the partial derivatives as a matrix-vector product. If mode
is ‘fwd’, this method must compute \(d\_outputs=J⋅d\_inputs\), where J is the partial derivative Jacobian. If mode
is ‘rev’, this method must compute \(d\_inputs=J^T⋅d\_outputs\).
def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):
if mode == 'fwd':
if 'area' in d_outputs:
if 'length' in d_inputs:
d_outputs['area'] += inputs['width'] * d_inputs['length']
if 'width' in d_inputs:
d_outputs['area'] += inputs['length'] * d_inputs['width']
elif mode == 'rev':
if 'area' in d_outputs:
if 'length' in d_inputs:
d_inputs['length'] += inputs['width'] * d_outputs['area']
if 'width' in d_inputs:
d_inputs['width'] += inputs['length'] * d_outputs['area']
Note that the last two are optional. A user may use finite-difference or complex-step methods, in which case these methods are not necessary. For efficiency reasons, OpenMDAO does not allow components to implement both compute_partials
and compute_jacvec_product
.