Test of the adjoint adj-tl_test/std#

Description#

Test suite for the adjoint and tangent-linear operators.

Running at least the adjoint test is mandatory before any variational inversion, because a broken adjoint produces a wrong gradient and silently diverges. This mode offers four complementary tests selected via the testtype parameter.

Mathematical framework#

Let \(\mathbf{H} = \partial\mathcal{H}/\partial\mathbf{x}\) be the Jacobian of the (possibly non-linear) observation operator \(\mathcal{H}\) evaluated at the linearisation point \(\mathbf{x}_b\), and let \(\mathbf{H}^*\) be its adjoint (transpose for real-valued operators).

Adjoint test — testtype = 'adj'#

Verifies the fundamental identity

\[\langle \mathbf{H}\,\delta\mathbf{x},\,\mathbf{H}\,\delta\mathbf{x} \rangle = \langle \delta\mathbf{x},\,\mathbf{H}^* \mathbf{H}\,\delta\mathbf{x} \rangle\]

where the left-hand side is computed with the tangent-linear operator and the right-hand side with the adjoint. The ratio

\[r = \frac{\langle \delta\mathbf{x},\,\mathbf{H}^*\mathbf{H}\,\delta\mathbf{x} \rangle} {\langle \mathbf{H}\,\delta\mathbf{x},\,\mathbf{H}\,\delta\mathbf{x} \rangle}\]

must satisfy \(|r - 1| \lesssim \mathcal{O}(\varepsilon_\mathrm{mach})\). The mode reports \(|r-1|/\varepsilon_\mathrm{mach}\); values up to a few tens are acceptable.

When use_forward = True, \(\mathbf{H}\,\delta\mathbf{x}\) is approximated by finite differences \(\mathcal{H}(\mathbf{x}_b + \delta\mathbf{x}) - \mathcal{H}(\mathbf{x}_b)\), which is only valid if \(\mathcal{H}\) is linear.

TL linearity test — testtype = 'tllinearity'#

Checks that the tangent-linear operator is genuinely linear:

\[\mathbf{H}(\lambda\,\delta\mathbf{x}) = \lambda\,\mathbf{H}(\delta\mathbf{x})\]

The ratio of the two scalar sums should equal 1 to machine precision.

TL Taylor test — testtype = 'tltaylor'#

Verifies the first-order Taylor expansion:

\[\mathcal{H}(\mathbf{x}_b + \lambda\,\delta\mathbf{x}) - \mathcal{H}(\mathbf{x}_b) = \mathbf{H}(\lambda\,\delta\mathbf{x}) + \mathcal{O}(\lambda^2)\]

The test iterates with decreasing \(\lambda\) (multiplied by lambdalin at each step) and checks that the residual decreases as \(\lambda^2\).

Symmetry test — testtype = 'adj_sym'#

For two independent random vectors \(\mathbf{u}\) and \(\mathbf{v}\), checks that \(\mathbf{H}^*\mathbf{H}\) and \(\mathbf{H}^*\mathbf{R}^{-1}\mathbf{H}\) are symmetric:

\[\langle \mathbf{H}^*\mathbf{H}\,\mathbf{u},\,\mathbf{v} \rangle = \langle \mathbf{H}^*\mathbf{H}\,\mathbf{v},\,\mathbf{u} \rangle\]

Test spaces#

When testspace = 'control', increments live in the control space \(\delta\mathbf{x} \in \mathbb{R}^n\) directly.

When testspace = 'chi', increments are expressed in the reduced space \(\boldsymbol{\chi} \in \mathbb{R}^n\) defined by \(\delta\mathbf{x} = \mathbf{L}\boldsymbol{\chi}\) where \(\mathbf{L} = \mathbf{B}^{1/2}\) is the square root of the background error covariance matrix. This tests the full chain \(\mathbf{L}^* \mathbf{H}^* \mathbf{H} \mathbf{L}\).

Practical guidance#

  • Run the adjoint test before the first inversion on any new configuration.

  • Use a shortened period if forward runs are expensive, but include calendar edge cases (month of February, year boundaries, etc.).

  • testspace = 'chi' is recommended before any inversion that uses spatial or temporal error correlations (\(\mathbf{B} \neq \mathbf{I}\)).

YAML arguments#

The following arguments are used to configure the plugin. pyCIF will return an exception at the initialization if mandatory arguments are not specified, or if any argument does not fit accepted values or type:

increments : float, mandatory

Perturbation scale relative to the prior standard deviation: \(\delta\mathbf{x} = \mathrm{increments} \cdot \sigma_{\mathbf{x}}\).

incrmode : “cst” or “rand”, optional, default “cst”

Type of increments to use in the test.

  • “cst”: Increments are the same for all dimensions of the control vector

  • “rand”: Increments are selected randomly with a Normal distribution centered to zero with standard deviation ${increments}

testspace : “control” or “chi”, optional, default “control”

Space in which the test increment is defined.

  • “control”: Increment in control space \(\mathbf{x}\).

  • “chi”: Increment in the reduced \(\boldsymbol{\chi}\) space (\(\delta\mathbf{x} = \mathbf{B}^{1/2}\boldsymbol{\chi}\)); recommended when using spatial/temporal error correlations.

testtype : “adj” or “tltaylor” or “tllinearity” or “adj_sym”, optional, default “adj”

Which test to run (see module docstring for equations).

  • “adj”: Full adjoint identity test: \(\langle H\delta x, H\delta x\rangle = \langle \delta x, H^*H\delta x\rangle\).

  • “tltaylor”: Taylor-expansion test: first-order residual decreases as \(O(\lambda^2)\).

  • “tllinearity”: Linearity test: \(H(\lambda\,\delta x) = \lambda\,H(\delta x)\).

  • “adj_sym”: Symmetry test: \(\langle H^*Hu,v\rangle = \langle H^*Hv,u\rangle\).

reload_results : bool, optional, default False

Skip already-completed operator runs and reload their results from disk.

random_seed : int, optional, default 0

NumPy random seed for drawing increments; used only with incrmode = 'rand'.

check_transforms : bool, optional, default False

Run the adjoint test independently for each transform in the pipeline. Results are logged to the main pyCIF log and to $workdir/check_transforms.log, one line per transform.

use_forward : bool, optional, default False

Approximate the TL by finite differences \(\mathcal{H}(x_b+\delta x)-\mathcal{H}(x_b)\). Valid only for linear operators.

taylor_iter : int, optional, default 1

Number of \(\lambda\) halvings in the Taylor test (testtype = 'tltaylor').

lambdalin : float, optional, default 0.1

Multiplicative factor applied to the increment at each iteration of the Taylor and linearity tests.

Requirements#

The current plugin requires the present plugins to run properly:

Requirement name

Requirement type

Explicit definition

Any valid

Default name

Default version

obsvect

ObsVect

False

True

standard

std

controlvect

ControlVect

True

True

standard

std

obsoperator

ObsOperator

True

True

standard

std

simulator

Simulator

True

True

gausscost

std

YAML template#

Please find below a template for a YAML configuration:

 1mode:
 2  plugin:
 3    name: adj-tl_test
 4    version: std
 5    type: mode
 6
 7  # Mandatory arguments
 8  increments: XXXXX  # float
 9
10  # Optional arguments
11  incrmode: XXXXX  # cst|rand
12  testspace: XXXXX  # control|chi
13  testtype: XXXXX  # adj|tltaylor|tllinearity|adj_sym
14  reload_results: XXXXX  # bool
15  random_seed: XXXXX  # int
16  check_transforms: XXXXX  # bool
17  use_forward: XXXXX  # bool
18  taylor_iter: XXXXX  # int
19  lambdalin: XXXXX  # float