Source code for pycif.plugins.modes.adjtl_test.testing_TL

import numpy as np
import copy
from logging import info


[docs] def testing_TL_linearity(self, accuracy): """Verify that the tangent-linear operator is linear: ``TL(λ·dx) == λ·TL(dx)``. Runs the TL operator twice — once for ``dx`` and once for ``λ·dx`` — and prints the ratio of the two scalar products. The ratio should equal 1 to machine precision for a truly linear operator. Args: self (Plugin): mode plugin with all configuration attributes. accuracy (float): machine epsilon (``np.finfo(np.float64).eps``). """ # Working directory workdir = self.workdir # Control vector controlvect = self.controlvect # Observation operator obsoper = self.obsoperator # Obsvervation vector obsvect = self.obsvect # Simulation window datei = self.datei datef = self.datef # Scaling factor lambdalin = getattr(self, 'lambdalin', 0.1) # Running the tangent linear code of the model at x for incr info("Testing the linearity of the tangent-linear") obsvect = obsoper.obsoper( controlvect, obsvect, 'tl', datei=datei, datef=datef, workdir=workdir, reload_results=getattr(self, 'reload_results', False), run_id=0) # Computing TL_x(incr) * lambda scaleprod1 = lambdalin * np.nansum(obsvect.dy) # Running the tangent linear code of the model at x for lambda * incr controlvect.dx *= lambdalin obsvect = obsoper.obsoper(controlvect, obsvect, 'tl', datei=datei, datef=datef, workdir=workdir, reload_results=getattr(self, 'reload_results', False), run_id=1) # Computing TL_x(lambda * incr) scaleprod2 = np.nansum(obsvect.dy) # Final verbose info('Machine accuracy: {}'.format(accuracy)) info('lambda TL_H(x)(dx) = {:.17E}'.format(scaleprod1)) info('TL_H(x)(lambda.dx), = {:.17E}'.format(scaleprod2)) info( "Result of TL linearity test: {:.17E} = 1 for lambda = {:.17E} ?".format( scaleprod1 / scaleprod2, lambdalin)) info('The difference is {:.1E} times the machine accuracy' .format(np.abs(scaleprod1 - scaleprod2) / accuracy / scaleprod2))
[docs] def testing_TL_Taylor(self, accuracy): """Run a Taylor-expansion test of the tangent-linear operator. Checks the first-order convergence property: ``‖H(x + λ·dx) − H(x) − TL(λ·dx)‖ = O(λ²)``. Iterates ``taylor_iter`` times, halving ``λ`` by factor ``lambdalin`` each time, and prints a summary table of norms and ratios. Args: self (Plugin): mode plugin with all configuration attributes. accuracy (float): machine epsilon (``np.finfo(np.float64).eps``). """ # Working directory workdir = self.workdir # Control vector controlvect = self.controlvect # Observation operator obsoper = self.obsoperator # Obsvervation vector obsvect = self.obsvect # Simulation window datei = self.datei datef = self.datef # Computes forward model with basic inputs obsvect = obsoper.obsoper(controlvect, obsvect, 'fwd', datei=datei, datef=datef, workdir=workdir, reload_results=getattr(self, 'reload_results', False), run_id=0) scaleprod0 = copy.deepcopy(obsvect.ysim) info(f'H(x) = {np.nanmean(scaleprod0):.17E} +/- {np.nanstd(scaleprod0):.17E}') # number of Taylor's loops: nloops = getattr(self, 'taylor_iter', 1) # Scaling factor lambdalin = getattr(self, 'lambdalin', 0.1) # Loops on smaller and smaller incr lambdataylor = lambdalin x0 = copy.deepcopy(controlvect.x) dx0 = copy.deepcopy(controlvect.dx) ratios = [] differences = [] list_scaleprod1 = [] list_scaleprod2 = [] list_lambdataylor = [] for i in range(nloops): list_lambdataylor.append(lambdataylor) # Computes perturbed forward model at x + lambda * dx controlvect.x = x0 + lambdataylor * dx0 obsvect = obsoper.obsoper( controlvect, obsvect, 'fwd', datei=datei, datef=datef, workdir=workdir, reload_results=getattr(self, 'reload_results', False), run_id=i + 1) scaleprod1 = copy.deepcopy(obsvect.ysim) list_scaleprod1.append(scaleprod1) info(f'H(x+lambda*incr) = {np.nanmean(scaleprod1):.17E} +/- {np.nanstd(scaleprod1):.17E}') # Computes TL at x for lambda * dx controlvect.x = x0 controlvect.dx = lambdataylor * dx0 obsvect = obsoper.obsoper( controlvect, obsvect, 'tl', datei=datei, datef=datef, workdir=workdir, reload_results=getattr(self, 'reload_results', False), run_id=i + 100) scaleprod2 = copy.deepcopy(obsvect.dy) list_scaleprod2.append(scaleprod2) info(f'TL_H(x)(lambda.dx) = {np.nanmean(scaleprod2):.17E} +/- {np.nanstd(scaleprod2):.17E}') ratios.append((scaleprod1 - scaleprod0) / scaleprod2) differences.append(np.abs((scaleprod1 - scaleprod0) - scaleprod2)) # info('Ratio = {:.17E} for lambda = {:.17E}'.format(ratios[i], # lambdataylor)) lambdataylor *= lambdalin info("Summary:") info("H(x) = {:.17E} ".format(np.nansum(scaleprod0 ** 2) ** 0.5)) info("lambda , || TL_H(x)(lambda.dx) || , < H(x+lambda*incr) - H(x) | TL_H(x)(lambda.dx) > , (1 - X) / lambda ") info("\n".join( [f"{lambdataylor:.17E} , " f"{np.nansum(scaleprod2 ** 2):.17E} " f"{np.nansum((scaleprod1 - scaleprod0) * scaleprod2):.17E} " f"{1 - (np.nansum((scaleprod1 - scaleprod0) * scaleprod2) / np.nansum(scaleprod2 ** 2)):.17E}" for scaleprod1, scaleprod2, lambdataylor in zip(list_scaleprod1, list_scaleprod2, list_lambdataylor) ] ) ) print(__file__) import code code.interact(local=dict(locals(), **globals()))