Observation Operators¶
Observation operators map model state to observation space. All of them
satisfy the pipekit-cycle
ObservationOperator Protocol — __call__(state) produces
the predicted observation, and linearize(state) returns the tangent-linear
(Jacobian) operator that the incremental and posterior-covariance machinery
needs. Because conformance is structural, custom operators plug in by
matching that signature; nothing here needs to be subclassed. See
Observation Operators in the Mathematical
Reference for the modelling background.
Core operators¶
LinearObs wraps an explicit observation matrix; MaskedIdentity handles
the ubiquitous "observe a subset of grid points" case (satellite tracks,
sparse sensor networks); AveragingKernel implements the smoothing kernels
of retrieval products such as atmospheric-composition column averages.
vardax — Modular variational data assimilation with learned components.
All public symbols are re-exported from the private _src subpackage so
that user code imports from the top-level namespace:
LinearObs
¶
Bases: Module
H(x) = H_mat @ x.
Examples:
>>> import jax.numpy as jnp, lineax as lx
>>> import vardax as vdx
>>> H = lx.MatrixLinearOperator(jnp.eye(3)[:2])
>>> obs = vdx.LinearObs(H_mat=H)
>>> obs(jnp.array([1.0, 2.0, 3.0]))
Array([1., 2.], dtype=float32)
>>> obs.linearize(jnp.zeros(3)) is H
True
Source code in src/vardax/_src/obs_operators/linear.py
linearize
¶
MaskedIdentity
¶
Bases: Module
\(H(x) = m \odot x\) with optional element-wise mask.
Stateless: no parameters. The mask can be supplied at call time (per-batch) rather than baked in.
Examples:
>>> import jax.numpy as jnp
>>> import vardax as vdx
>>> op = vdx.MaskedIdentity()
>>> x = jnp.array([1.0, 2.0, 3.0])
>>> op(x, mask=jnp.array([1.0, 0.0, 1.0]))
Array([1., 0., 3.], dtype=float32)
>>> type(op.linearize(x)).__name__
'JacobianLinearOperator'
Source code in src/vardax/_src/obs_operators/masked.py
linearize
¶
Tangent-linear operator at x: identity (since \(H\) is linear).
AveragingKernel
¶
Bases: Module
RTM L2-style averaging-kernel obs operator.
Attributes:
| Name | Type | Description |
|---|---|---|
A |
AbstractLinearOperator
|
Averaging kernel matrix, stored as an
|
x_a |
Float[Array, N]
|
Retrieval prior, same shape as the model state. |
h |
Float[Array, N]
|
Weighting vector (often pressure-weighted). |
Source code in src/vardax/_src/obs_operators/averaging_kernel.py
linearize
¶
Tangent-linear operator at x: \(A \cdot \mathrm{diag}(h)\).
Source code in src/vardax/_src/obs_operators/averaging_kernel.py
InterpObs
¶
Bases: Module
Grid → scattered-obs sparse bilinear interpolation.
Build a precomputed sparse (n_obs, 4) weight stencil from a 2-D
grid and an (n_obs, 2) array of obs coordinates. The forward
indexing is pure JAX (so jit / grad / vmap all work);
linearize wraps the same forward as a
lineax.FunctionLinearOperator (its transpose comes from
jax.vjp automatically).
Attributes:
| Name | Type | Description |
|---|---|---|
indices |
Int[Array, 'n_obs 4']
|
|
weights |
Float[Array, 'n_obs 4']
|
|
grid_shape |
tuple[int, int]
|
static |
Source code in src/vardax/_src/obs_operators/interp_obs.py
linearize
¶
Tangent-linear at x: H itself (linear operator).
Wraps __call__ as a lineax.FunctionLinearOperator so it
plugs straight into IncrementalFourDVar's GN Hessian
assembly and LaplaceCovariance. The transpose H^T is
derived via jax.vjp (cached numpy adjoint is no longer
exposed; use op.transpose().mv(y) instead).
The input structure is taken from x.shape so the operator
composes with both 2-D (Ny, Nx) and flat (Ny*Nx,) state
layouts — variational models that carry flat state vectors then
get a flat-shaped H instead of being forced through the
grid shape.
Source code in src/vardax/_src/obs_operators/interp_obs.py
interp_obs_from_coords
¶
interp_obs_from_coords(
grid_coords: tuple[
Float[Array, " Ny"], Float[Array, " Nx"]
],
obs_coords: Float[Array, "n_obs 2"],
*,
order: int = 1,
) -> InterpObs
Build an InterpObs from grid axis arrays + obs locations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid_coords
|
tuple[Float[Array, ' Ny'], Float[Array, ' Nx']]
|
|
required |
obs_coords
|
Float[Array, 'n_obs 2']
|
|
required |
order
|
int
|
interpolation order. Only |
1
|
Returns:
| Type | Description |
|---|---|
InterpObs
|
Configured |
InterpObs
|
|
Source code in src/vardax/_src/obs_operators/interp_obs.py
Multi-instrument fusion¶
Assimilating several instruments at once: each instrument is described by an
InstrumentSpec, registered in an InstrumentRegistry, and
MultiInstrumentFusion stacks the per-instrument operators into a single
observation operator over the concatenated observation vector.
vardax — Modular variational data assimilation with learned components.
All public symbols are re-exported from the private _src subpackage so
that user code imports from the top-level namespace:
InstrumentSpec
¶
Bases: Module
Per-instrument (obs_op, mask, R_op, id) bundle.
Attributes:
| Name | Type | Description |
|---|---|---|
obs_op |
Any
|
|
mask |
Float[Array, ...]
|
Quality mask of shape compatible with the instrument's
observation space. |
R_op |
AbstractLinearOperator
|
Observation-error covariance as a
|
instrument_id |
str
|
Identifier (e.g. |
Source code in src/vardax/_src/obs_operators/multi_instrument.py
InstrumentRegistry
¶
Bases: Module
Keyed lookup of InstrumentSpec by instrument_id.
Attributes:
| Name | Type | Description |
|---|---|---|
entries |
dict[str, InstrumentSpec]
|
|
Source code in src/vardax/_src/obs_operators/multi_instrument.py
MultiInstrumentFusion
¶
Bases: Module
Compose per-instrument operators at the likelihood level.
__call__ returns dict[instrument_id, predicted_obs] — one
array per instrument. The cost function consumes the dict and
sums per-instrument terms with their respective \(R_i^{-1}\).
There is no shared coordinate system; each instrument keeps its
native footprint and resolution.
For strict pipekit_cycle.ObservationOperator contexts where a
single observation vector + single linear operator are required,
call .to_observation_operator() for a flattened wrapper.
Attributes:
| Name | Type | Description |
|---|---|---|
registry |
InstrumentRegistry
|
Per-instrument
|
weights |
dict[str, float] | None
|
Optional |
Source code in src/vardax/_src/obs_operators/multi_instrument.py
linearize
¶
Per-instrument tangent-linear operators.
Returns {instrument_id: H_i'(x)}. The fused tangent linear
is the block-diagonal stack of these — assembled lazily by
the cost function or via to_observation_operator().
Source code in src/vardax/_src/obs_operators/multi_instrument.py
to_observation_operator
¶
Adapt to the strict pipekit_cycle.ObservationOperator protocol.
Returns a wrapper that concatenates per-instrument outputs and
exposes a block-diagonal linear operator. Use this when the
consumer requires a single (state) -> Array signature.