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.
[fv-az520-749:46425] mca_base_component_repository_open: unable to open mca_btl_openib: librdmacm.so.1: cannot open shared object file: No such file or directory (ignored)
  • 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) :


[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) :


[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, because the class can implement compute_partials and/or compute_jacvec_product, or neither if the user wants to use the finite-difference or complex-step method.