Changing Check Settings for FD or CS#
Changing Settings for Inputs on a Specific Component#
You can change the settings for the approximation schemes that will be used to compare with your component’s derivatives by calling the set_check_partial_options
method.
- Component.set_check_partial_options(wrt, method='fd', form=None, step=None, step_calc=None, minimum_step=None, directional=False)[source]
Set options that will be used for checking partial derivatives.
- Parameters:
- wrtstr or list of str
The name or names of the variables that derivatives are taken with respect to. This can contain the name of any input or output variable. May also contain a glob pattern.
- methodstr
Method for check: “fd” for finite difference, “cs” for complex step.
- formstr
Finite difference form for check, can be “forward”, “central”, or “backward”. Leave undeclared to keep unchanged from previous or default value.
- stepfloat
Step size for finite difference check. Leave undeclared to keep unchanged from previous or default value.
- step_calcstr
Step type for computing the size of the finite difference step. It can be ‘abs’ for absolute, ‘rel_avg’ for a size relative to the absolute value of the vector input, or ‘rel_element’ for a size relative to each value in the vector input. In addition, it can be ‘rel_legacy’ for a size relative to the norm of the vector. For backwards compatibilty, it can be ‘rel’, which is now equivalent to ‘rel_avg’. Defaults to None, in which case the approximation method provides its default value..
- minimum_stepfloat
Minimum step size allowed when using one of the relative step_calc options.
- directionalbool
Set to True to perform a single directional derivative for each vector variable in the pattern named in wrt.
Note
If you want to use method=”cs”, then you must also pass force_alloc_complex
=True to setup. See the example below.
This allows custom tailoring of the approximation settings on a variable basis.
Usage Examples#
ParaboloidMatVec
class definition
class ParaboloidMatVec(Paraboloid):
""" Use matrix-vector product."""
def setup_partials(self):
pass
def compute_partials(self, inputs, partials):
"""Analytical derivatives."""
pass
def compute_jacvec_product(self, inputs, dinputs, doutputs, mode):
"""Returns the product of the incoming vector with the Jacobian."""
x = inputs['x'][0]
y = inputs['y'][0]
if mode == 'fwd':
if 'x' in dinputs:
doutputs['f_xy'] += (2.0*x - 6.0 + y)*dinputs['x']
if 'y' in dinputs:
doutputs['f_xy'] += (2.0*y + 8.0 + x)*dinputs['y']
elif mode == 'rev':
if 'x' in dinputs:
dinputs['x'] += (2.0*x - 6.0 + y)*doutputs['f_xy']
if 'y' in dinputs:
dinputs['y'] += (2.0*y + 8.0 + x)*doutputs['f_xy']
ParaboloidTricky
class definition
class ParaboloidTricky(om.ExplicitComponent):
"""
Evaluates the equation f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3.
"""
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('f_xy', val=0.0)
self.scale = 1e-7
self.declare_partials(of='*', wrt='*')
def compute(self, inputs, outputs):
"""
f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3
Optimal solution (minimum): x = 6.6667; y = -7.3333
"""
sc = self.scale
x = inputs['x']*sc
y = inputs['y']*sc
outputs['f_xy'] = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0
def compute_partials(self, inputs, partials):
"""
Jacobian for our paraboloid.
"""
sc = self.scale
x = inputs['x']
y = inputs['y']
partials['f_xy', 'x'] = 2.0*x*sc*sc - 6.0*sc + y*sc*sc
partials['f_xy', 'y'] = 2.0*y*sc*sc + 8.0*sc + x*sc*sc
import openmdao.api as om
from openmdao.core.tests.test_check_partials import ParaboloidTricky
from openmdao.test_suite.components.paraboloid_mat_vec import ParaboloidMatVec
prob = om.Problem()
comp = prob.model.add_subsystem('comp', ParaboloidTricky())
prob.model.add_subsystem('comp2', ParaboloidMatVec())
prob.model.connect('comp.f_xy', 'comp2.x')
prob.set_solver_print(level=0)
comp.set_check_partial_options(wrt='*', step=1e-2)
prob.setup()
prob.run_model()
prob.check_partials(compact_print=True)
----------------------------------
Component: ParaboloidTricky 'comp'
----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -6.0000e-07 | 4.9644e-14 | -6.0000e-07 | -6.0000e-07 | 8.2740e-08 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 8.0000e-07 | 8.0000e-07 | 6.6192e-14 | 8.0000e-07 | 8.0000e-07 | 8.2740e-08 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
-----------------------------------
Component: ParaboloidMatVec 'comp2'
-----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | 3.8000e+01 | 3.8000e+01 | 1.0409e-06 | 3.8000e+01 | 3.8000e+01 | 1.0409e-06 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 2.7393e-08 | 3.8000e+01 | 3.8000e+01 | 2.7393e-08 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | >ABS_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 3.0000e+01 | 3.0000e+01 | 1.0043e-06 | 3.0000e+01 | 3.0000e+01 | 1.0043e-06 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0000e+01 | 3.3476e-08 | 3.0000e+01 | 3.0000e+01 | 3.3476e-08 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | >ABS_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
#################################################################
Sub Jacobian with Largest Relative Error: ParaboloidTricky 'comp'
#################################################################
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) |
+===============+================+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -6.0000e-07 | 4.9644e-14 | -6.0000e-07 | -6.0000e-07 | 8.274e-08 |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
{'comp': {('f_xy', 'x'): {'J_fwd': array([[-6.e-07]]),
'J_fd': array([[-6.0000005e-07]]),
'abs error': _ErrorData(forward=4.964422262660536e-14, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=8.274036419837383e-08, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=6e-07, reverse=0.0, fd=6.000000496442226e-07),
'vals_at_max_abs': _ErrorData(forward=(-6e-07, -6.000000496442226e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(-6e-07, -6.000000496442226e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}},
('f_xy', 'y'): {'J_fwd': array([[8.e-07]]),
'J_fd': array([[8.00000066e-07]]),
'abs error': _ErrorData(forward=6.619229683547381e-14, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=8.274036419837383e-08, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=8e-07, reverse=0.0, fd=8.000000661922968e-07),
'vals_at_max_abs': _ErrorData(forward=(8e-07, 8.000000661922968e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(8e-07, 8.000000661922968e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}}},
'comp2': {('f_xy', 'x'): {'J_fwd': array([[38.]]),
'J_rev': array([[38.]]),
'J_fd': array([[38.00000104]]),
'abs error': _ErrorData(forward=1.0409276001155376e-06, reverse=1.0409276001155376e-06, fwd_rev=0.0),
'rel error': _ErrorData(forward=2.739283083162063e-08, reverse=2.739283083162063e-08, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=38.0, reverse=38.0, fd=38.0000010409276),
'vals_at_max_abs': _ErrorData(forward=(38.0, 38.0000010409276), reverse=(38.0, 38.0000010409276), fwd_rev=(38.0, 38.0)),
'vals_at_max_rel': _ErrorData(forward=(38.0, 38.0000010409276), reverse=(38.0, 38.0000010409276), fwd_rev=(38.0, 38.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True},
('f_xy', 'y'): {'J_fwd': array([[30.]]),
'J_rev': array([[30.]]),
'J_fd': array([[30.000001]]),
'abs error': _ErrorData(forward=1.0042822395917028e-06, reverse=1.0042822395917028e-06, fwd_rev=0.0),
'rel error': _ErrorData(forward=3.3476073532409224e-08, reverse=3.3476073532409224e-08, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=30.0, reverse=30.0, fd=30.00000100428224),
'vals_at_max_abs': _ErrorData(forward=(30.0, 30.00000100428224), reverse=(30.0, 30.00000100428224), fwd_rev=(30.0, 30.0)),
'vals_at_max_rel': _ErrorData(forward=(30.0, 30.00000100428224), reverse=(30.0, 30.00000100428224), fwd_rev=(30.0, 30.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True}}}
Here, we show how to set the method. In this case, we use complex step on TrickyParaboloid because the finite difference is less accurate.
Note
You need to set force_alloc_complex
to True during setup to utilize complex step during a check.
import openmdao.api as om
from openmdao.core.tests.test_check_partials import ParaboloidTricky
from openmdao.test_suite.components.paraboloid_mat_vec import ParaboloidMatVec
prob = om.Problem()
comp = prob.model.add_subsystem('comp', ParaboloidTricky())
prob.model.add_subsystem('comp2', ParaboloidMatVec())
prob.model.connect('comp.f_xy', 'comp2.x')
prob.set_solver_print(level=0)
comp.set_check_partial_options(wrt='*', method='cs')
prob.setup(force_alloc_complex=True)
prob.run_model()
prob.check_partials(compact_print=True)
----------------------------------
Component: ParaboloidTricky 'comp'
----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -6.0000e-07 | 0.0000e+00 | -6.0000e-07 | -6.0000e-07 | 0.0000e+00 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 8.0000e-07 | 8.0000e-07 | 1.0588e-22 | 8.0000e-07 | 8.0000e-07 | 1.3235e-16 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
-----------------------------------
Component: ParaboloidMatVec 'comp2'
-----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | 3.8000e+01 | 3.8000e+01 | 1.0409e-06 | 3.8000e+01 | 3.8000e+01 | 1.0409e-06 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 2.7393e-08 | 3.8000e+01 | 3.8000e+01 | 2.7393e-08 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | >ABS_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 3.0000e+01 | 3.0000e+01 | 1.0043e-06 | 3.0000e+01 | 3.0000e+01 | 1.0043e-06 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0000e+01 | 3.3476e-08 | 3.0000e+01 | 3.0000e+01 | 3.3476e-08 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | >ABS_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
##################################################################
Sub Jacobian with Largest Relative Error: ParaboloidMatVec 'comp2'
##################################################################
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+============+
| f_xy | y | 3.0000e+01 | 3.0000e+01 | 1.0043e-06 | 3.0000e+01 | 3.0000e+01 | 1.0043e-06 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0000e+01 | 3.3476e-08 | 3.0000e+01 | 3.0000e+01 | 3.3476e-08 | 3.0000e+01 | 3.0000e+01 | 0.0 |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
{'comp': {('f_xy', 'x'): {'J_fwd': array([[-6.e-07]]),
'J_fd': array([[-6.e-07]]),
'abs error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=6e-07, reverse=0.0, fd=6e-07),
'vals_at_max_abs': _ErrorData(forward=(-6e-07, -6e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(-6e-07, -6e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}},
('f_xy', 'y'): {'J_fwd': array([[8.e-07]]),
'J_fd': array([[8.e-07]]),
'abs error': _ErrorData(forward=1.0587911840678754e-22, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=1.3234889800848445e-16, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=8e-07, reverse=0.0, fd=7.999999999999999e-07),
'vals_at_max_abs': _ErrorData(forward=(8e-07, 7.999999999999999e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(8e-07, 7.999999999999999e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}}},
'comp2': {('f_xy', 'x'): {'J_fwd': array([[38.]]),
'J_rev': array([[38.]]),
'J_fd': array([[38.00000104]]),
'abs error': _ErrorData(forward=1.0409276001155376e-06, reverse=1.0409276001155376e-06, fwd_rev=0.0),
'rel error': _ErrorData(forward=2.739283083162063e-08, reverse=2.739283083162063e-08, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=38.0, reverse=38.0, fd=38.0000010409276),
'vals_at_max_abs': _ErrorData(forward=(38.0, 38.0000010409276), reverse=(38.0, 38.0000010409276), fwd_rev=(38.0, 38.0)),
'vals_at_max_rel': _ErrorData(forward=(38.0, 38.0000010409276), reverse=(38.0, 38.0000010409276), fwd_rev=(38.0, 38.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True},
('f_xy', 'y'): {'J_fwd': array([[30.]]),
'J_rev': array([[30.]]),
'J_fd': array([[30.000001]]),
'abs error': _ErrorData(forward=1.0042822395917028e-06, reverse=1.0042822395917028e-06, fwd_rev=0.0),
'rel error': _ErrorData(forward=3.3476073532409224e-08, reverse=3.3476073532409224e-08, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=30.0, reverse=30.0, fd=30.00000100428224),
'vals_at_max_abs': _ErrorData(forward=(30.0, 30.00000100428224), reverse=(30.0, 30.00000100428224), fwd_rev=(30.0, 30.0)),
'vals_at_max_rel': _ErrorData(forward=(30.0, 30.00000100428224), reverse=(30.0, 30.00000100428224), fwd_rev=(30.0, 30.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True}}}
Directional Derivatives#
You can also specify that an input or set of inputs be checked using a directional derivative. For vector inputs, this means that, instead of calculating the derivative with respect to each element of the array, we calculate the derivative with respect to a linear combination of all array indices. For finite difference and complex step, the step value is applied simultaneously to all elements of the vector. This is a much quicker check because it only requires a single execution of the component for the variable rather than one for each element of the array.
ArrayComp
class definition
class ArrayComp(om.ExplicitComponent):
def setup(self):
J1 = np.array([[1.0, 3.0, -2.0, 7.0],
[6.0, 2.5, 2.0, 4.0],
[-1.0, 0.0, 8.0, 1.0],
[1.0, 4.0, -5.0, 6.0]])
self.J1 = J1
self.J2 = J1 * 3.3
self.Jb = J1.T
# Inputs
self.add_input('x1', np.zeros([4]))
self.add_input('x2', np.zeros([4]))
self.add_input('bb', np.zeros([4]))
# Outputs
self.add_output('y1', np.zeros([4]))
self.exec_count = 0
self.set_check_partial_options('x*', directional=True)
def setup_partials(self):
self.declare_partials(of='*', wrt='*')
def compute(self, inputs, outputs):
"""
Execution.
"""
outputs['y1'] = self.J1.dot(inputs['x1']) + self.J2.dot(inputs['x2']) + self.Jb.dot(inputs['bb'])
self.exec_count += 1
def compute_partials(self, inputs, partials):
"""
Analytical derivatives.
"""
partials[('y1', 'x1')] = self.J1
partials[('y1', 'x2')] = self.J2
partials[('y1', 'bb')] = self.Jb
import openmdao.api as om
from openmdao.test_suite.components.array_comp import ArrayComp
prob = om.Problem()
model = prob.model
mycomp = model.add_subsystem('mycomp', ArrayComp(), promotes=['*'])
prob.setup()
prob.run_model()
data = prob.check_partials()
-----------------------------
Component: ArrayComp 'mycomp'
-----------------------------
mycomp: 'y1' wrt 'bb'
Max Absolute Error (Jfwd - Jfd) : 0.000000e+00
fwd value: 1.000000e+00
fd value: 1.000000e+00 (fd:forward)
Max Relative Error (Jfwd - Jfd) / Jfd : 0.000000e+00
fwd value: 1.000000e+00
fd value: 1.000000e+00 (fd:forward)
Raw Forward Derivative (Jfwd)
[[ 1. 6. -1. 1. ]
[ 3. 2.5 0. 4. ]
[-2. 2. 8. -5. ]
[ 7. 4. 1. 6. ]]
Raw FD Derivative (Jfd)
[[ 1. 6. -1. 1. ]
[ 3. 2.5 0. 4. ]
[-2. 2. 8. -5. ]
[ 7. 4. 1. 6. ]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mycomp: 'y1' wrt (d)'x1'
Directional Derivative (Jfwd)
[[ 9. ]
[14.5]
[ 8. ]
[ 6. ]]
Directional FD Derivative (Jfd)
[[ 9. ]
[14.5]
[ 8. ]
[ 6. ]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mycomp: 'y1' wrt (d)'x2'
Directional Derivative (Jfwd)
[[29.7 ]
[47.85]
[26.4 ]
[19.8 ]]
Directional FD Derivative (Jfd)
[[29.7 ]
[47.85]
[26.4 ]
[19.8 ]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If your component is matrix-free and you request directional derivatives, then your reverse mode derivatives will be verified using the dot product test described here.
import numpy as np
import openmdao.api as om
class ArrayCompMatrixFree(om.ExplicitComponent):
def setup(self):
J1 = np.array([[1.0, 3.0, -2.0, 7.0],
[6.0, 2.5, 2.0, 4.0],
[-1.0, 0.0, 8.0, 1.0],
[1.0, 4.0, -5.0, 6.0]])
self.J1 = J1
self.J2 = J1 * 3.3
self.Jb = J1.T
# Inputs
self.add_input('x1', np.zeros([4]))
self.add_input('x2', np.zeros([4]))
self.add_input('bb', np.zeros([4]))
# Outputs
self.add_output('y1', np.zeros([4]))
self.set_check_partial_options('*', directional=True)
def compute(self, inputs, outputs):
"""
Execution.
"""
outputs['y1'] = self.J1.dot(inputs['x1']) + self.J2.dot(inputs['x2']) + self.Jb.dot(inputs['bb'])
def compute_jacvec_product(self, inputs, dinputs, doutputs, mode):
"""Returns the product of the incoming vector with the Jacobian."""
if mode == 'fwd':
if 'x1' in dinputs:
doutputs['y1'] += self.J1.dot(dinputs['x1'])
if 'x2' in dinputs:
doutputs['y1'] += self.J2.dot(dinputs['x2'])
if 'bb' in dinputs:
doutputs['y1'] += self.Jb.dot(dinputs['bb'])
elif mode == 'rev':
if 'x1' in dinputs:
dinputs['x1'] += self.J1.T.dot(doutputs['y1'])
if 'x2' in dinputs:
dinputs['x2'] += self.J2.T.dot(doutputs['y1'])
if 'bb' in dinputs:
dinputs['bb'] += self.Jb.T.dot(doutputs['y1'])
prob = om.Problem()
model = prob.model
model.add_subsystem('mycomp', ArrayCompMatrixFree(), promotes=['*'])
prob.setup()
prob.run_model()
data = prob.check_partials()
---------------------------------------
Component: ArrayCompMatrixFree 'mycomp'
---------------------------------------
mycomp: 'y1' wrt (d)'bb'
Max Absolute Error ([rev, fd] Dot Product Test) : 0.000000e+00
rev value: -6.209923e+00
fd value: -6.209923e+00 (fd:forward)
Max Absolute Error ([rev, fwd] Dot Product Test) : 0.000000e+00
rev value: -6.209923e+00
fwd value: -6.209923e+00
Max Relative Error ([rev, fd] Dot Product Test) / Jfd : 0.000000e+00
rev value: -6.209923e+00
fd value: -6.209923e+00 (fd:forward)
Max Relative Error ([rev, fwd] Dot Product Test) / Jfwd : 0.000000e+00
rev value: -6.209923e+00
fwd value: -6.209923e+00
Directional Derivative (Jfwd)
[[ -6.1917151 ]
[ -6.19523953]
[ 10.0345695 ]
[-10.2532671 ]]
Directional Derivative (Jrev)
[[-1.30949872 -1.3006367 -7.82491031 1.908428 ]]
Directional FD Derivative (Jfd)
[[ -6.1917151 ]
[ -6.19523953]
[ 10.0345695 ]
[-10.2532671 ]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mycomp: 'y1' wrt (d)'x1'
Max Absolute Error ([rev, fd] Dot Product Test) : 0.000000e+00
rev value: 1.941700e+00
fd value: 1.941700e+00 (fd:forward)
Max Absolute Error ([rev, fwd] Dot Product Test) : 4.440892e-16
rev value: 1.941700e+00
fwd value: 1.941700e+00
Max Relative Error ([rev, fd] Dot Product Test) / Jfd : 0.000000e+00
rev value: 1.941700e+00
fd value: 1.941700e+00 (fd:forward)
Max Relative Error ([rev, fwd] Dot Product Test) / Jfwd : 2.287116e-16
rev value: 1.941700e+00
fwd value: 1.941700e+00
Directional Derivative (Jfwd)
[[-6.04681465]
[-9.15573091]
[-3.16118463]
[-4.56166906]]
Directional Derivative (Jrev)
[[ 1.2965835 -0.72620864 -4.83583423 -0.96803128]]
Directional FD Derivative (Jfd)
[[-6.04681465]
[-9.15573091]
[-3.16118463]
[-4.56166906]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mycomp: 'y1' wrt (d)'x2'
Max Absolute Error ([rev, fd] Dot Product Test) : 1.776357e-15
rev value: -7.921137e+00
fd value: -7.921137e+00 (fd:forward)
Max Absolute Error ([rev, fwd] Dot Product Test) : 8.881784e-16
rev value: -7.921137e+00
fwd value: -7.921137e+00
Max Relative Error ([rev, fd] Dot Product Test) / Jfd : 2.242553e-16
rev value: -7.921137e+00
fd value: -7.921137e+00 (fd:forward)
Max Relative Error ([rev, fwd] Dot Product Test) / Jfwd : 1.121276e-16
rev value: -7.921137e+00
fwd value: -7.921137e+00
Directional Derivative (Jfwd)
[[-2.63752617]
[-2.42169174]
[10.40034492]
[-4.35767723]]
Directional Derivative (Jrev)
[[ 4.27872555 -2.39648851 -15.95825297 -3.19450323]]
Directional FD Derivative (Jfd)
[[-2.63752617]
[-2.42169174]
[10.40034492]
[-4.35767723]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Changing Global Settings For Whole Model#
You can change the settings globally for all approximations used for all components. This is done by passing in a value for any of the following arguments:
Name |
Description |
---|---|
method |
Method for check: “fd” for finite difference, “cs” for complex step. |
form |
Finite difference form for check, can be “forward”, “central”, or backward. |
step |
Step size for finite difference check. |
step_calc |
When “abs”, the step is absolute. A relative step can also be chosen with one of the values in table below. |
minimum_step |
Minimum allowable step when using one of the relative step_calc options. |
If you need to scale the finite difference step by the variable’s magnitude, the following additional choices for “step_calc” are available:
step_calc |
Step size is scaled by |
---|---|
“rel_avg” |
Average absolute value of the vector. |
“rel_element” |
Absolute value of each vector element. |
“rel_legacy” |
Norm of the vector. |
“rel” |
Same as “rel__avg”. |
Note
The global check options take precedence over the ones defined on a component.
Usage Examples#
import openmdao.api as om
from openmdao.core.tests.test_check_partials import ParaboloidTricky
from openmdao.test_suite.components.paraboloid_mat_vec import ParaboloidMatVec
prob = om.Problem()
prob.model.add_subsystem('comp', ParaboloidTricky())
prob.model.add_subsystem('comp2', ParaboloidMatVec())
prob.model.connect('comp.f_xy', 'comp2.x')
prob.set_solver_print(level=0)
prob.setup()
prob.run_model()
prob.check_partials(step=1e-2, compact_print=True)
----------------------------------
Component: ParaboloidTricky 'comp'
----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -6.0000e-07 | 4.9644e-14 | -6.0000e-07 | -6.0000e-07 | 8.2740e-08 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 8.0000e-07 | 8.0000e-07 | 6.6192e-14 | 8.0000e-07 | 8.0000e-07 | 8.2740e-08 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
-----------------------------------
Component: ParaboloidMatVec 'comp2'
-----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+====================+
| f_xy | x | 3.8000e+01 | 3.8010e+01 | 1.0000e-02 | 3.8000e+01 | 3.8010e+01 | 1.0000e-02 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8010e+01 | 2.6309e-04 | 3.8000e+01 | 3.8010e+01 | 2.6309e-04 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | >ABS_TOL >REL_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------------+
| f_xy | y | 3.0000e+01 | 3.0010e+01 | 1.0000e-02 | 3.0000e+01 | 3.0010e+01 | 1.0000e-02 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0010e+01 | 3.3322e-04 | 3.0000e+01 | 3.0010e+01 | 3.3322e-04 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | >ABS_TOL >REL_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------------+
##################################################################
Sub Jacobian with Largest Relative Error: ParaboloidMatVec 'comp2'
##################################################################
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+============+
| f_xy | y | 3.0000e+01 | 3.0010e+01 | 1.0000e-02 | 3.0000e+01 | 3.0010e+01 | 1.0000e-02 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0010e+01 | 3.3322e-04 | 3.0000e+01 | 3.0010e+01 | 3.3322e-04 | 3.0000e+01 | 3.0000e+01 | 0.0 |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
{'comp': {('f_xy', 'x'): {'J_fwd': array([[-6.e-07]]),
'J_fd': array([[-6.0000005e-07]]),
'abs error': _ErrorData(forward=4.964422262660536e-14, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=8.274036419837383e-08, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=6e-07, reverse=0.0, fd=6.000000496442226e-07),
'vals_at_max_abs': _ErrorData(forward=(-6e-07, -6.000000496442226e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(-6e-07, -6.000000496442226e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}},
('f_xy', 'y'): {'J_fwd': array([[8.e-07]]),
'J_fd': array([[8.00000066e-07]]),
'abs error': _ErrorData(forward=6.619229683547381e-14, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=8.274036419837383e-08, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=8e-07, reverse=0.0, fd=8.000000661922968e-07),
'vals_at_max_abs': _ErrorData(forward=(8e-07, 8.000000661922968e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(8e-07, 8.000000661922968e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}}},
'comp2': {('f_xy', 'x'): {'J_fwd': array([[38.]]),
'J_rev': array([[38.]]),
'J_fd': array([[38.01]]),
'abs error': _ErrorData(forward=0.010000000008403731, reverse=0.010000000008403731, fwd_rev=0.0),
'rel error': _ErrorData(forward=0.0002630886610997506, reverse=0.0002630886610997506, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=38.0, reverse=38.0, fd=38.010000000008404),
'vals_at_max_abs': _ErrorData(forward=(38.0, 38.010000000008404), reverse=(38.0, 38.010000000008404), fwd_rev=(38.0, 38.0)),
'vals_at_max_rel': _ErrorData(forward=(38.0, 38.010000000008404), reverse=(38.0, 38.010000000008404), fwd_rev=(38.0, 38.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True},
('f_xy', 'y'): {'J_fwd': array([[30.]]),
'J_rev': array([[30.]]),
'J_fd': array([[30.01]]),
'abs error': _ErrorData(forward=0.010000000004311005, reverse=0.010000000004311005, fwd_rev=0.0),
'rel error': _ErrorData(forward=0.0003332222593905221, reverse=0.0003332222593905221, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=30.0, reverse=30.0, fd=30.01000000000431),
'vals_at_max_abs': _ErrorData(forward=(30.0, 30.01000000000431), reverse=(30.0, 30.01000000000431), fwd_rev=(30.0, 30.0)),
'vals_at_max_rel': _ErrorData(forward=(30.0, 30.01000000000431), reverse=(30.0, 30.01000000000431), fwd_rev=(30.0, 30.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True}}}
Here is an example where we check our partials using complex step.
Note
You need to set force_alloc_complex
to True during setup to utilize complex step during a check.
import openmdao.api as om
from openmdao.core.tests.test_check_partials import ParaboloidTricky
from openmdao.test_suite.components.paraboloid_mat_vec import ParaboloidMatVec
prob = om.Problem()
prob.model.add_subsystem('comp', ParaboloidTricky())
prob.model.add_subsystem('comp2', ParaboloidMatVec())
prob.model.connect('comp.f_xy', 'comp2.x')
prob.set_solver_print(level=0)
prob.setup(force_alloc_complex=True)
prob.run_model()
prob.check_partials(method='cs', compact_print=True)
----------------------------------
Component: ParaboloidTricky 'comp'
----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -6.0000e-07 | 0.0000e+00 | -6.0000e-07 | -6.0000e-07 | 0.0000e+00 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 8.0000e-07 | 8.0000e-07 | 1.0588e-22 | 8.0000e-07 | 8.0000e-07 | 1.3235e-16 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
-----------------------------------
Component: ParaboloidMatVec 'comp2'
-----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 3.0000e+01 | 3.0000e+01 | 3.5527e-15 | 3.0000e+01 | 3.0000e+01 | 3.5527e-15 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0000e+01 | 1.1842e-16 | 3.0000e+01 | 3.0000e+01 | 1.1842e-16 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
#################################################################
Sub Jacobian with Largest Relative Error: ParaboloidTricky 'comp'
#################################################################
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) |
+===============+================+=============+=============+=============+=============+=============+============+
| f_xy | y | 8.0000e-07 | 8.0000e-07 | 1.0588e-22 | 8.0000e-07 | 8.0000e-07 | 1.323e-16 |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
{'comp': {('f_xy', 'x'): {'J_fwd': array([[-6.e-07]]),
'J_fd': array([[-6.e-07]]),
'abs error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=0.0, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=6e-07, reverse=0.0, fd=6e-07),
'vals_at_max_abs': _ErrorData(forward=(-6e-07, -6e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(-6e-07, -6e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}},
('f_xy', 'y'): {'J_fwd': array([[8.e-07]]),
'J_fd': array([[8.e-07]]),
'abs error': _ErrorData(forward=1.0587911840678754e-22, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=1.3234889800848445e-16, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=8e-07, reverse=0.0, fd=7.999999999999999e-07),
'vals_at_max_abs': _ErrorData(forward=(8e-07, 7.999999999999999e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(8e-07, 7.999999999999999e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}}},
'comp2': {('f_xy', 'x'): {'J_fwd': array([[38.]]),
'J_rev': array([[38.]]),
'J_fd': array([[38.]]),
'abs error': _ErrorData(forward=0.0, reverse=0.0, fwd_rev=0.0),
'rel error': _ErrorData(forward=0.0, reverse=0.0, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=38.0, reverse=38.0, fd=38.0),
'vals_at_max_abs': _ErrorData(forward=(38.0, 38.0), reverse=(38.0, 38.0), fwd_rev=(38.0, 38.0)),
'vals_at_max_rel': _ErrorData(forward=(38.0, 38.0), reverse=(38.0, 38.0), fwd_rev=(38.0, 38.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True},
('f_xy', 'y'): {'J_fwd': array([[30.]]),
'J_rev': array([[30.]]),
'J_fd': array([[30.]]),
'abs error': _ErrorData(forward=3.552713678800501e-15, reverse=3.552713678800501e-15, fwd_rev=0.0),
'rel error': _ErrorData(forward=1.1842378929335005e-16, reverse=1.1842378929335005e-16, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=30.0, reverse=30.0, fd=29.999999999999996),
'vals_at_max_abs': _ErrorData(forward=(30.0, 29.999999999999996), reverse=(30.0, 29.999999999999996), fwd_rev=(30.0, 30.0)),
'vals_at_max_rel': _ErrorData(forward=(30.0, 29.999999999999996), reverse=(30.0, 29.999999999999996), fwd_rev=(30.0, 30.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True}}}
In this example, we check our partials with finite difference, but we use central differencing for more accuracy.
import openmdao.api as om
from openmdao.core.tests.test_check_partials import ParaboloidTricky
from openmdao.test_suite.components.paraboloid_mat_vec import ParaboloidMatVec
prob = om.Problem()
prob.model.add_subsystem('comp', ParaboloidTricky())
prob.model.add_subsystem('comp2', ParaboloidMatVec())
prob.model.connect('comp.f_xy', 'comp2.x')
prob.set_solver_print(level=0)
prob.setup()
prob.run_model()
prob.check_partials(form='central', compact_print=True)
----------------------------------
Component: ParaboloidTricky 'comp'
----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -5.9863e-07 | 1.3677e-09 | -6.0000e-07 | -5.9863e-07 | 2.2848e-03 | >REL_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 8.0000e-07 | 8.0114e-07 | 1.1369e-09 | 8.0000e-07 | 8.0114e-07 | 1.4192e-03 | >REL_TOL |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
-----------------------------------
Component: ParaboloidMatVec 'comp2'
-----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(fwd val) | a(fd val) | a(fwd-fd) | a(rev val) | a(rchk val) | a(rev-fd) | a(fwd val) | a(rev val) | a(fwd-rev) | r(fwd val) | r(fd val) | r(fwd-fd) | r(rev val) | r(rchk val) | r(rev-fd) | r(fwd val) | r(rev val) | r(fwd-rev) | error desc |
+===============+================+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+=============+============+
| f_xy | x | 3.8000e+01 | 3.8000e+01 | 4.6168e-08 | 3.8000e+01 | 3.8000e+01 | 4.6168e-08 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | 3.8000e+01 | 3.8000e+01 | 1.2149e-09 | 3.8000e+01 | 3.8000e+01 | 1.2149e-09 | 3.8000e+01 | 3.8000e+01 | 0.0000e+00 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
| f_xy | y | 3.0000e+01 | 3.0000e+01 | 9.5224e-09 | 3.0000e+01 | 3.0000e+01 | 9.5224e-09 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | 3.0000e+01 | 3.0000e+01 | 3.1741e-10 | 3.0000e+01 | 3.0000e+01 | 3.1741e-10 | 3.0000e+01 | 3.0000e+01 | 0.0000e+00 | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+------------+
#################################################################
Sub Jacobian with Largest Relative Error: ParaboloidTricky 'comp'
#################################################################
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) |
+===============+================+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | -5.9863e-07 | 1.3677e-09 | -6.0000e-07 | -5.9863e-07 | 0.002285 |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
{'comp': {('f_xy', 'x'): {'J_fwd': array([[-6.e-07]]),
'J_fd': array([[-5.98632255e-07]]),
'abs error': _ErrorData(forward=1.3677451221155663e-09, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=0.0022847835394278477, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=6e-07, reverse=0.0, fd=5.986322548778844e-07),
'vals_at_max_abs': _ErrorData(forward=(-6e-07, -5.986322548778844e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(-6e-07, -5.986322548778844e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}},
('f_xy', 'y'): {'J_fwd': array([[8.e-07]]),
'J_fd': array([[8.01136935e-07]]),
'abs error': _ErrorData(forward=1.1369345695129958e-09, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=0.0014191513590918411, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=8e-07, reverse=0.0, fd=8.01136934569513e-07),
'vals_at_max_abs': _ErrorData(forward=(8e-07, 8.01136934569513e-07), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(8e-07, 8.01136934569513e-07), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1}}},
'comp2': {('f_xy', 'x'): {'J_fwd': array([[38.]]),
'J_rev': array([[38.]]),
'J_fd': array([[38.00000005]]),
'abs error': _ErrorData(forward=4.616777005139738e-08, reverse=4.616777005139738e-08, fwd_rev=0.0),
'rel error': _ErrorData(forward=1.214941315665954e-09, reverse=1.214941315665954e-09, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=38.0, reverse=38.0, fd=38.00000004616777),
'vals_at_max_abs': _ErrorData(forward=(38.0, 38.00000004616777), reverse=(38.0, 38.00000004616777), fwd_rev=(38.0, 38.0)),
'vals_at_max_rel': _ErrorData(forward=(38.0, 38.00000004616777), reverse=(38.0, 38.00000004616777), fwd_rev=(38.0, 38.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True},
('f_xy', 'y'): {'J_fwd': array([[30.]]),
'J_rev': array([[30.]]),
'J_fd': array([[30.00000001]]),
'abs error': _ErrorData(forward=9.522409527562559e-09, reverse=9.522409527562559e-09, fwd_rev=0.0),
'rel error': _ErrorData(forward=3.1741365081800053e-10, reverse=3.1741365081800053e-10, fwd_rev=0.0),
'magnitude': _MagnitudeData(forward=30.0, reverse=30.0, fd=30.00000000952241),
'vals_at_max_abs': _ErrorData(forward=(30.0, 30.00000000952241), reverse=(30.0, 30.00000000952241), fwd_rev=(30.0, 30.0)),
'vals_at_max_rel': _ErrorData(forward=(30.0, 30.00000000952241), reverse=(30.0, 30.00000000952241), fwd_rev=(30.0, 30.0)),
'denom_idx': {'fwd': 1, 'rev': 1, 'fwd_rev': 1},
'matrix_free': True}}}
In this example, we use a relative step-size. This is sometimes needed for casese where an input variable’s value can be in a wide range of orders of magnitude, and we don’t want the step size to become to small or large for it.
import openmdao.api as om
from openmdao.core.tests.test_check_partials import ParaboloidTricky
prob = om.Problem()
prob.model.add_subsystem('comp', ParaboloidTricky())
prob.set_solver_print(level=0)
prob.setup()
prob.run_model()
prob.check_partials(step_calc='rel', compact_print=True)
----------------------------------
Component: ParaboloidTricky 'comp'
----------------------------------
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) | error desc |
+===============+================+=============+=============+=============+=============+=============+============+============+
| f_xy | x | -6.0000e-07 | 0.0000e+00 | 6.0000e-07 | -6.0000e-07 | 0.0000e+00 | nan | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+------------+
| f_xy | y | 8.0000e-07 | 0.0000e+00 | 8.0000e-07 | 8.0000e-07 | 0.0000e+00 | nan | |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+------------+
#################################################################
Sub Jacobian with Largest Relative Error: ParaboloidTricky 'comp'
#################################################################
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
| 'of' variable | 'wrt' variable | a(calc val) | a(fd val) | a(calc-fd) | r(calc val) | r(fd val) | r(calc-fd) |
+===============+================+=============+=============+=============+=============+=============+============+
| f_xy | x | -6.0000e-07 | 0.0000e+00 | 6.0000e-07 | -6.0000e-07 | 0.0000e+00 | nan |
+---------------+----------------+-------------+-------------+-------------+-------------+-------------+------------+
{'comp': {('f_xy', 'x'): {'J_fwd': array([[-6.e-07]]),
'J_fd': array([[0.]]),
'abs error': _ErrorData(forward=6e-07, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=nan, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=6e-07, reverse=0.0, fd=0.0),
'vals_at_max_abs': _ErrorData(forward=(-6e-07, 0.0), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(-6e-07, 0.0), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 0, 'rev': 1, 'fwd_rev': 1}},
('f_xy', 'y'): {'J_fwd': array([[8.e-07]]),
'J_fd': array([[0.]]),
'abs error': _ErrorData(forward=8e-07, reverse=None, fwd_rev=None),
'rel error': _ErrorData(forward=nan, reverse=None, fwd_rev=None),
'magnitude': _MagnitudeData(forward=8e-07, reverse=0.0, fd=0.0),
'vals_at_max_abs': _ErrorData(forward=(8e-07, 0.0), reverse=None, fwd_rev=None),
'vals_at_max_rel': _ErrorData(forward=(8e-07, 0.0), reverse=None, fwd_rev=None),
'denom_idx': {'fwd': 0, 'rev': 1, 'fwd_rev': 1}}}}
Finally, in this example, we have a vector input whose elements differ by several orders of magnitude, and whose middle element is sometimes zero. If you try to scale the step size by a variable that is zero, you end up with a step size equal to zero, which causes division by zero during computation. To prevent this, OpenMDAO defines a minimum step size of 1e-12. You can change this value by setting the minimum_step
argument to a new value whenever you set the step_calc
argument. Here, we also use the ‘rel_element’ step_calc so that each element computes its own step size relative to the magnitude of that single element.
import numpy as np
import openmdao.api as om
class FDComp(om.ExplicitComponent):
def initialize(self):
self.options.declare('vec_size', types=int, default=1)
def setup(self):
nn = self.options['vec_size']
self.add_input('x_element', np.ones((nn, )))
self.add_output('y', np.ones((nn, )))
def setup_partials(self):
self.declare_partials('*', 'x_element')
self.set_check_partial_options('x_element', method='fd', step_calc='rel_element', minimum_step=1e-15)
def compute(self, inputs, outputs):
x = inputs['x_element']
outputs['y'] = 0.5 * x ** 2
def compute_partials(self, inputs, partials):
x = inputs['x_element']
partials['y', 'x_element'] = np.diag(x)
prob = om.Problem()
model = prob.model
model.add_subsystem('comp', FDComp(vec_size=3))
prob.setup(force_alloc_complex=True)
x = np.array([1e10, 0.0, 1e-10])
prob.set_val('comp.x_element', x)
prob.run_model()
totals = prob.check_partials()
------------------------
Component: FDComp 'comp'
------------------------
comp: 'y' wrt 'x_element'
Max Absolute Error (Jfwd - Jfd) : 5.000397e+03 *
fwd value: 1.000000e+10
fd value: 1.000001e+10 (fd:forward)
Max Relative Error (Jfwd - Jfd) / Jfd : nan
fwd value: 0.000000e+00
fd value: 5.000000e-16 (fd:forward)
Raw Forward Derivative (Jfwd)
[[1.e+10 0.e+00 0.e+00]
[0.e+00 0.e+00 0.e+00]
[0.e+00 0.e+00 1.e-10]]
Raw FD Derivative (Jfd)
[[1.0000005e+10 0.0000000e+00 0.0000000e+00]
[0.0000000e+00 5.0000000e-16 0.0000000e+00]
[0.0000000e+00 0.0000000e+00 1.0000050e-10]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -