Source code for pycif.plugins.simulators.gausscost_flexpart.simul

import numpy as np
import pandas as pd

from logging import info
from .svd import svd_cost


[docs] def simul(self, chi, grad=True, run_id=-1, **kwargs): r"""Evaluate the Gaussian cost function for FLEXPART Lagrangian inversions. Computes .. math:: J(\boldsymbol{\chi}) = \tfrac{1}{2}\boldsymbol{\chi}^\top\boldsymbol{\chi} + \tfrac{1}{2}\sum_i \frac{(H_i\mathbf{x} - y_i)^2} {\sigma_{\varepsilon,i}^2 + \sigma_{b,i}^2} where :math:`\sigma_\varepsilon` and :math:`\sigma_b` are the observation error and background error stored in the datastore columns ``obserror`` and ``obs_bkgerr`` respectively. The adjoint sensitivity is read directly from ``obsvect.dx``. Args: self (Plugin): gausscost FLEXPART simulator plugin instance. chi (np.ndarray): current iterate :math:`\boldsymbol{\chi}`, shape ``(n,)``. grad (bool): if ``True`` (default), compute and return the gradient. run_id (int): unique call identifier for sub-directory naming. **kwargs: forwarded to the obs-operator. Returns: tuple or float: ``(zcost, zgrad)`` when ``grad=True``; ``zcost`` when ``grad=False``. """ # Various variables datei = self.datei datef = self.datef workdir = self.workdir reload_results = getattr(self, 'reload_from_previous', False) # Get the observation operator from extra arguments if not hasattr(self, 'obsoperator'): raise Exception("Observation operator is missing to compute the " "simulator. Please check your setup files") obsoper = self.obsoperator controlvect = self.controlvect # Saving chi to the control vector for later controlvect.chi = chi # Control space contribution of the cost function j_b = 0.5 * np.dot(chi, chi) # Computes forward simulations controlvect.x = controlvect.sqrtbprod(chi, **kwargs) obsvect = obsoper.obsoper(controlvect, 'fwd', datei=self.datei, datef=self.datef, workdir=self.workdir, run_id=run_id, reload_results=reload_results, **kwargs) # Computes the observation term of the cost function # At the moment, this is valid for diagonal observation matrices only # TODO: Include these lines into rinvprod.py, with option for # non-diagonal matrices, eventually departures = obsvect.datastore['sim'] - obsvect.datastore['obs'] j_o = 0.5 * (departures ** 2 / (obsvect.datastore['obserror']**2 + obsvect.datastore['obs_bkgerr']** 2) ).sum() zcost = j_b + j_o towrite = ( "In Simulator {}:\n" " Jb = {:.4E}\n" " Jo = {:.4E}\n" " Total = {:.4E}") \ .format(run_id, j_b, j_o, zcost) info(towrite) # Saves cost function value with open('{}/cost.txt'.format(workdir), 'a') as f: f.write('{},{:.4E},{:.4E},{:.4E}\n'.format(run_id, j_b, j_o, zcost)) # Return only the cost function if grad = False if not grad: return zcost controlvect.dx = obsvect.dx # Observational part of the gradient zgrad_o = controlvect.sqrtbprod_ad(controlvect.dx, **kwargs) # Control part of the gradient zgrad_b = chi zgrad = zgrad_b + zgrad_o # Verbose the norms znorm_grad_b = np.dot(zgrad_b, zgrad_b) ** 0.5 znorm_grad_o = np.dot(zgrad_o, zgrad_o) ** 0.5 info("In Simulator {}:\n" " grad(Jb) = {:.4E}\n" " grad(Jo) = {:.4E}\n" .format(run_id, znorm_grad_b, znorm_grad_o)) return zcost, zgrad