Unit Testing Partial Derivatives#
If you want to check the implementations of a Component
’s partial derivatives as part of a unit test, you can make use of a custom assert function, assert_check_partials
.
- openmdao.utils.assert_utils.assert_check_partials(data, atol=1e-06, rtol=1e-06)[source]
Raise assertion if any entry from the return from check_partials is above a tolerance.
- Parameters:
- datadict of dicts of dicts
- First key:
is the component name;
- Second key:
is the (output, input) tuple of strings;
- Third key:
is one of [‘rel error’, ‘abs error’, ‘magnitude’, ‘J_fd’, ‘J_fwd’, ‘J_rev’];
- For ‘rel error’, ‘abs error’, ‘magnitude’ the value is: A tuple containing norms for
forward - fd, adjoint - fd, forward - adjoint.
- For ‘J_fd’, ‘J_fwd’, ‘J_rev’ the value is: A numpy array representing the computed
Jacobian for the three different methods of computation.
- atolfloat
Absolute error. Default is 1e-6.
- rtolfloat
Relative error. Default is 1e-6.
In your unit test, after calling check_partials
on a Component, you can call the assert_check_partials
function with the returned value from check_partials
.
Usage#
In the following code, compute_partials
is intentionally coded incorrectly to demonstrate how assert_check_partials
can be used to detect this kind of error.
import numpy as np
import openmdao.api as om
from openmdao.utils.assert_utils import assert_check_partials
class BrokenDerivComp(om.ExplicitComponent):
def setup(self):
self.add_input('x1', 3.0)
self.add_input('x2', 5.0)
self.add_output('y', 5.5)
def setup_partials(self):
self.declare_partials(of='*', wrt='*')
def compute(self, inputs, outputs):
""" Compute outputs. """
outputs['y'] = 3.0 * inputs['x1'] + 4.0 * inputs['x2']
def compute_partials(self, inputs, partials):
"""Intentionally incorrect derivative."""
J = partials
J['y', 'x1'] = np.array([4.0])
J['y', 'x2'] = np.array([40])
prob = om.Problem()
prob.model = BrokenDerivComp()
prob.set_solver_print(level=0)
prob.setup()
prob.run_model()
data = prob.check_partials(out_stream=None)
print(data)
try:
assert_check_partials(data, atol=1.e-6, rtol=1.e-6)
except ValueError as err:
print(str(err))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[2], line 31
27 prob.model = BrokenDerivComp()
29 prob.set_solver_print(level=0)
---> 31 prob.setup()
32 prob.run_model()
34 data = prob.check_partials(out_stream=None)
File /usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/core/problem.py:888, in Problem.setup(self, check, logger, mode, force_alloc_complex, distributed_vector_class, local_vector_class, derivatives)
885 warn_deprecation(msg)
887 if not isinstance(self.model, Group):
--> 888 raise TypeError("The model for this Problem is of type "
889 f"'{self.model.__class__.__name__}'. "
890 "The model must be a Group or a sub-class of Group.")
892 # A distributed vector type is required for MPI
893 if comm.size > 1:
TypeError: The model for this Problem is of type 'BrokenDerivComp'. The model must be a Group or a sub-class of Group.