tlm_adjoint.verification

This module implements Taylor remainder convergence testing using the approach described in

  • P. E. Farrell, D. A. Ham, S. W. Funke, and M. E. Rognes, ‘Automated derivation of the adjoint of high-level transient finite element programs’, SIAM Journal on Scientific Computing 35(4), pp. C369–C393, 2013, doi: 10.1137/120873558

Specifically for a sufficiently regular functional \(J\), via Taylor’s theorem we have, for some direction \(\zeta\) and with perturbation magnitude controlled by \(\varepsilon\),

\[\left| J \left( m + \varepsilon \right) - J \left( m \right) \right| = O \left( \varepsilon \right),\]
\[\left| J \left( m + \varepsilon \right) - J \left( m \right) - \varepsilon dJ \left( m; \zeta \right) \right| = O \left( \varepsilon^2 \right),\]

where here \(dJ \left( m; \zeta \right)\) denotes the directional derivative of \(J\) with respect to \(m\) with direction \(\zeta\). Here we refer to the quantity appearing on the left-hand-side in the first case as the ‘uncorrected Taylor remainder magnitude’, and the quantity appearing on the left-hand-side in the second case as the ‘corrected Taylor remainder magnitude’

A Taylor remainder convergence test considers some direction, and a number of different values for \(\varepsilon\), and investigates the convergence rates of the uncorrected and corrected Taylor remainder magnitudes, with the directional derivative computed using a tangent-linear or adjoint. In a successful verification the uncorrected Taylor remainder magnitude is observed to converge to zero at first order, while the corrected Taylor remainder magnitude is observed to converge to zero at second order.

There are a number of ways that a Taylor remainder convergence test can fail, including:

  • The computed derivative is incorrect. This is the case that the test is designed to find, and indicates an error in the tangent-linear or adjoint calculation.

  • The considered values of \(\varepsilon\) are too large, and the asymptotic convergence orders are not observable.

  • The considered values of \(\varepsilon\) are too small, and iterative solver tolerances or floating point roundoff prevent the convergence orders being observable.

  • The convergence order is higher than expected. For example if the directional derivative is zero then the uncorrected Taylor remainder magnitude can converge at higher than first order.

In principle higher order derivative calculations can be tested by considering more terms in the Taylor expansion of the functional. In practice the corresponding higher order convergence rate can mean that iterative solver tolerances or floating point roundoff effects are more problematic. Instead, one can verify the derivative of a derivative, by redefining \(J\) to be a directional derivative of some other functional \(K\), with the directional derivative computed using a tangent-linear. A successful verification then once again corresponds to second order convergence of the corrected Taylor remainder magnitude.

The functions defined in this module log the uncorrected and corrected Taylor remainder magnitudes, and also log the observed orders computed using a power law fit between between consecutive pairs of values of \(\varepsilon\). Logging is performed on a logging module logger, with name ‘tlm_adjoint.verification’ and with severity logging.INFO. The minimum order computed for the corrected Taylor remainder magnitude is returned.

A typical test considers tangent-linears and adjoints up to the relevant order, e.g. to verify Hessian calculations

min_order = taylor_test_tlm(forward, M, 1)
assert min_order > 1.99

min_order = taylor_test_tlm_adjoint(forward, M, 1)
assert min_order > 1.99

min_order = taylor_test_tlm_adjoint(forward, M, 2)
assert min_order > 1.99

Module Contents

tlm_adjoint.verification.taylor_test(forward, M, J_val, *, dJ=None, ddJ=None, seed=0.01, dM=None, M0=None, size=5)

Perform a Taylor remainder convergence test.

Originally aimed for similar behaviour to the taylor_test function in dolfin-adjoint 2017.1.0.

Uncorrected and corrected Taylor remainder magnitudes are computed by repeatedly re-running the forward and evaluating the functional. The perturbation direction \(\zeta\) is defined by the dM argument. \(\varepsilon\) is set equal to

\[\varepsilon = 2^{-p} \eta \quad \text{ for } p \in \left\{ 0, \ldots, P - 1 \right\},\]

where the norm appearing here is defined to be the \(l_\infty\) norm of the control value degree of freedom vector. The argument seed sets the value of \(\eta\), and the argument size sets the value of \(P\).

Parameters:
  • forward – A callable which accepts one or more variable arguments, and which returns a variable defining the forward functional \(J\).

  • M – A variable or a Sequence of variables defining the control \(m\).

  • J_val – A scalar defining the value of the functional \(J\) for control value defined by M0.

  • dJ – A variable or a Sequence of variables defining a value for the derivative of the functional with respect to the control. Required if ddJ is not supplied.

  • ddJ – A Hessian used to compute the Hessian action on the considered perturbation direction. If supplied then a higher order corrected Taylor remainder magnitude is computed. If dJ is not supplied, also computes the first order directional derivative.

  • seed – Defines the value of \(\eta\). Controls the magnitude of the perturbation.

  • dM – Defines the perturbation direction \(\zeta\). If not provided then the direction used has degrees of freedom real and (in the complex case) complex components set using numpy.random.random(), scaled by the \(l_\infty\) norm of the degree of freedom vector for M if this is non-zero.

  • M0 – Defines the value of the control at which the functional and derivatives are evaluated. M is used if not supplied.

  • size – The number of values of \(\varepsilon\) to consider.

Returns:

The minimum order observed, via a power law fit between consecutive pairs of values of \(\varepsilon\), in the calculations for the corrected Taylor remainder magnitude. In a successful verification this should be close to 2 if ddJ is not supplied, and close to 3 if ddJ is supplied.

tlm_adjoint.verification.taylor_test_tlm(forward, M, tlm_order, *, seed=0.01, dMs=None, size=5, manager=None)

Perform a Taylor remainder convergence test for a functional \(J\) defined to the (tlm_order - 1) th derivative of some functional \(K\). The tlm_order th derivative of \(K\), appearing in the corrected Taylor remainder magnitude, is computed using a tlm_order th order tangent-linear.

Parameters:
  • forward – A callable which accepts one or more variable arguments, and which returns a variable defining the forward functional \(K\).

  • M – A variable or a Sequence of variables defining the control \(m\) and its value.

  • tlm_order – An int defining the tangent-linear order to test.

  • seed – Controls the perturbation magnitude. See taylor_test().

  • dMs – A Sequence of length tlm_order whose elements are each a variable or a Sequence of variables. The functional \(J\) appearing in the definition of the Taylor remainder magnitudes is defined to be a (tlm_adjoint - 1) th derivative, defined by successively taking the derivative of \(K\) with respect to the control and with directions defined by the dM[:-1] (with the directions considered in order). The perturbation direction \(\zeta\) is defined by dM[-1] – see taylor_test(). By default dMs[:-1] have real and (in the complex case) complex components set using numpy.random.random(), and the default for dMs[-1] is set as described in taylor_test() (see the dM argument).

  • size – The number of values of \(\varepsilon\) to consider. See taylor_test().

  • manager – An EquationManager used to create an internal manager via EquationManager.new(). manager() is used if not supplied.

Returns:

The minimum order observed, via a power law fit between consecutive pairs of values of \(\varepsilon\), in the calculations for the corrected Taylor remainder magnitude. In a successful verification this should be close to 2.

tlm_adjoint.verification.taylor_test_tlm_adjoint(forward, M, adjoint_order, *, seed=0.01, dMs=None, size=5, manager=None)

Perform a Taylor remainder convergence test for a functional \(J\) defined to the (adjoint_order - 1) th derivative of some functional \(K\). The adjoint_order th derivative of \(K\), appearing in the corrected Taylor remainder magnitude, is computed using an adjoint associated with an (adjoint_order - 1) th order tangent-linear.

Parameters:
  • forward – A callable which accepts one or more variable arguments, and which returns a variable defining the forward functional \(K\).

  • M – A variable or a Sequence of variables defining the control \(m\) and its value.

  • adjoint_order – An int defining the adjoint order to test.

  • seed – Controls the perturbation magnitude. See taylor_test().

  • dMs – A Sequence of length adjoint_order whose elements are each a variable or a Sequence of variables. The functional \(J\) appearing in the definition of the Taylor remainder magnitudes is defined to be a (adjoint_order - 1) th derivative, defined by successively taking the derivative of \(K\) with respect to the control and with directions defined by the dM[:-1] (with the directions considered in order). The perturbation direction \(\zeta\) is defined by dM[-1] – see taylor_test(). By default dMs[:-1] have real and (in the complex case) complex components set using numpy.random.random(), and the default for dMs[-1] is set as described in taylor_test() (see the dM argument).

  • size – The number of values of \(\varepsilon\) to consider. See taylor_test().

  • manager – An EquationManager used to create an internal manager via EquationManager.new(). manager() is used if not supplied.

Returns:

The minimum order observed, via a power law fit between consecutive pairs of values of \(\varepsilon\), in the calculations for the corrected Taylor remainder magnitude. In a successful verification this should be close to 2.