Source code for pycif.plugins.obsoperators.random.obsoper
import datetime
import os
from ....utils import path
from logging import info, debug
import numpy as np
[docs]
def obsoper(
self,
controlvect,
obsvect,
mode,
run_id=0,
datei=datetime.datetime(1979, 1, 1),
datef=datetime.datetime(2100, 1, 1),
workdir="./",
reload_results=False,
check_transforms=False,
ignore_exceptions=False,
force_fetch_results=False,
**kwargs
):
"""Apply the random observation operator in forward, tangent-linear or adjoint mode.
Implements a simple matrix–vector product using the random matrix
``self.H_matrix`` built by :func:`~pycif.plugins.obsoperators.random.ini_data`.
Because no physical model is involved, the operator is instantaneous and
exact in all three modes.
**Forward** (``mode='fwd'``):
.. math::
\\mathbf{y}_\\text{sim} = \\mathbf{H}\\,\\mathbf{x}
Sets ``obsvect.ysim`` and returns *obsvect*.
**Tangent-linear** (``mode='tl'``):
.. math::
\\mathbf{y}_\\text{sim} = \\mathbf{H}\\,\\mathbf{x}, \\qquad
\\delta\\mathbf{y} = \\mathbf{H}\\,\\delta\\mathbf{x}
Sets both ``obsvect.ysim`` and ``obsvect.dy``; returns *obsvect*.
**Adjoint** (``mode='adj'``):
.. math::
\\delta\\mathbf{x} = \\mathbf{H}^\\top\\,\\delta\\mathbf{y}
Sets ``controlvect.dx``; returns *controlvect*.
Args:
self (ObsOperator): plugin instance; must have ``H_matrix`` set by a
prior call to :func:`~pycif.plugins.obsoperators.random.ini_data`.
controlvect (ControlVect): control-vector object. ``controlvect.x``
is read in ``fwd`` / ``tl`` modes; ``controlvect.dx`` is read in
``tl`` mode and written in ``adj`` mode.
obsvect (ObsVect): observation-vector object. ``obsvect.ysim`` is
written in ``fwd`` / ``tl`` modes; ``obsvect.dy`` is read in
``adj`` mode and written in ``tl`` mode.
mode (str): execution mode — one of ``'fwd'``, ``'tl'``, or ``'adj'``.
run_id (int, optional): run identifier (unused; present for interface
compatibility). Defaults to ``0``.
datei (datetime.datetime, optional): simulation start date (unused;
present for interface compatibility).
Defaults to ``datetime.datetime(1979, 1, 1)``.
datef (datetime.datetime, optional): simulation end date (unused;
present for interface compatibility).
Defaults to ``datetime.datetime(2100, 1, 1)``.
workdir (str, optional): working directory (unused; present for
interface compatibility). Defaults to ``"./"``
reload_results (bool, optional): reload pre-computed results (unused).
Defaults to ``False``.
check_transforms (bool, optional): validate transform consistency
(unused). Defaults to ``False``.
ignore_exceptions (bool, optional): swallow non-fatal errors (unused).
Defaults to ``False``.
force_fetch_results (bool, optional): if ``True``, raise
:exc:`IOError` immediately to signal that results must be fetched
from a previous run rather than recomputed. Defaults to ``False``.
**kwargs: additional keyword arguments (ignored).
Returns:
ObsVect: in ``'fwd'`` and ``'tl'`` modes — the updated *obsvect*.
ControlVect: in ``'adj'`` mode — the updated *controlvect*.
Raises:
IOError: if ``force_fetch_results`` is ``True``.
"""
if force_fetch_results:
raise IOError
if mode == "fwd":
obsvect.ysim = np.dot(self.H_matrix, controlvect.x)
return obsvect
elif mode == "tl":
obsvect.ysim = np.dot(self.H_matrix, controlvect.x)
obsvect.dy = np.dot(self.H_matrix, controlvect.dx)
return obsvect
elif mode == "adj":
controlvect.dx = np.dot(self.H_matrix.T, obsvect.dy)
return controlvect