openghg_inversions.native_covariance#

Labelled matrix-free covariance actions on a native latitude/longitude grid.

The native scaling perturbation is denoted by x and its covariance by B = Cov(x). A covariance action applies B to labelled right-hand sides without constructing the dense native N x N matrix. The initial implementation uses

B = sigma**2 * (K_lat kron K_lon),

where K_axis[i, j] = exp(-abs(q_i - q_j) / ell_axis). Grid arrays use row-major (latitude, longitude) vectorisation, so the action on a field X is K_lat @ X @ K_lon.T. The default correlation length is 1.5 degrees; it is an introductory configurable value, not a universal scientific constant.

Both SeparableExponentialCovariance.apply() and SeparableExponentialCovariance.solve() preserve all input dimensions, coordinates, name, and attributes. An unblocked action materialises the two one-dimensional covariance factors and their Cholesky factors, rather than the dense native covariance. Optional native-grid class labels replace B by the blocked action B_class = sum_c M_c B M_c, where M_c is the diagonal indicator for class c. A blocked action additionally stores one native-grid boolean mask per class, but does not construct the diagonal M_c matrices or the dense native covariance. Apply and solve eagerly convert each labelled right-hand side to a NumPy array; they do not preserve lazy Dask execution. Unblocked solves use the separable Cholesky factors; multi-class solves use matrix-free conjugate gradients. The linear operator reports the flattened N x N shape required by SciPy but does not materialise that matrix: each iteration applies the separable kernel once per class through masked native-grid work arrays. Grouping coordinates by class would expose a block-diagonal matrix, but arbitrary class blocks are dense principal submatrices and are not generally separable. The iterative solve therefore preserves the O(N + n_lat**2 + n_lon**2) storage bound, at the cost of repeated per-class kernel applications; highly imbalanced classes can consequently have noticeable computational overhead. Distances are coordinate-wise degrees, not geodesic or longitude-wrapped distances. A missing coordinate units attr is interpreted as degrees for compatibility with existing OGI grids.

SeparableExponentialCovariance is an ordinary slotted, identity-based object. Construction owns eager coordinate and class-label copies; array properties return borrowed values whose in-place mutation is unsupported. Scalar configuration properties are read-only, so changed parameters require explicit reconstruction.

class openghg_inversions.native_covariance.InvertibleNativeCovarianceAction(*args, **kwargs)#

Bases: NativeCovarianceAction, Protocol

Positive-definite native covariance action with a compatible inverse.

In addition to NativeCovarianceAction semantics, B is positive definite and solve() implements the inverse compatible with apply() on the same labelled native state.

solve(rhs: DataArray) DataArray#

Return labelled B^-1 rhs while preserving the input layout.

Parameters:

rhs – Labelled array containing every native dimension.

Returns:

The covariance solve with the dimensions, coordinates, name, and attributes of rhs preserved.

Raises:
  • TypeError – If rhs is not an xarray data array.

  • ValueError – If native dimensions or coordinates are missing or misaligned, or if values are non-numeric or non-finite.

  • numpy.linalg.LinAlgError – If an iterative solve fails.

class openghg_inversions.native_covariance.NativeCovarianceAction(*args, **kwargs)#

Bases: Protocol

Structural interface for a labelled self-adjoint PSD covariance action.

Implementations represent a real, self-adjoint positive-semidefinite operator B on the labelled native state. They must preserve RHS layout and labels and return finite real values for finite real inputs. Consumers may trust these semantic guarantees without globally materializing or certifying the matrix-free operator.

apply(rhs: DataArray) DataArray#

Apply B to labelled RHS arrays containing every native dimension.

Parameters:

rhs – Labelled array containing every native dimension.

Returns:

The covariance action with the dimensions, coordinates, name, and attributes of rhs preserved.

Raises:
  • TypeError – If rhs is not an xarray data array.

  • ValueError – If native dimensions or coordinates are missing or misaligned, or if values are non-numeric or non-finite.

property native_dims: tuple[str, ...]#

Native dimensions consumed by the action.

class openghg_inversions.native_covariance.SeparableExponentialCovariance(latitude: DataArray | None = None, longitude: DataArray | None = None, sigma: float = 1.0, correlation_length: float = 1.5, latitude_correlation_length: float | None = None, longitude_correlation_length: float | None = None, class_labels: DataArray | None = None)#

Bases: object

Separable exponential covariance over labelled latitude and longitude.

Parameters:
  • latitude – One-dimensional latitude coordinate in degrees.

  • longitude – One-dimensional longitude coordinate in degrees.

  • sigma – Strictly positive native-cell marginal standard deviation, in native-state units (dimensionless for RHIME scaling perturbations).

  • correlation_length – Shared fallback correlation length in degrees.

  • latitude_correlation_length – Optional latitude-specific length in degrees.

  • longitude_correlation_length – Optional longitude-specific length in degrees.

  • class_labels – Optional native-grid labels defining spatial covariance blocks. Cells with different labels have zero cross-covariance.

Notes

Construction copies and owns the two small coordinate vectors and any class labels because cached factors and masks depend on them. Array properties return borrowed values; callers must not mutate them in place. Configuration properties are read-only. Instances are ordinary slotted objects with identity-based equality and hashing.

Raises:
  • ValueError – If coordinates, units, or covariance parameters are invalid.

  • numpy.linalg.LinAlgError – If a one-dimensional covariance factor is not numerically positive definite.

apply(rhs: DataArray) DataArray#

Apply B while preserving the labelled layout of rhs.

The right-hand side is eagerly converted to a NumPy array before the covariance action is evaluated.

Parameters:

rhs – Array containing both native dimensions and any number of additional right-hand-side dimensions.

Returns:

B rhs with dimensions and coordinates identical to rhs.

Raises:
  • TypeError – If rhs is not an xarray data array.

  • ValueError – If native dimensions or coordinates are missing or misaligned, or if values are non-numeric or non-finite.

property class_labels: BorrowedDataArray | None#

Borrow the owned class labels, if any; in-place mutation is unsupported.

property correlation_length: float#

Read-only shared fallback correlation length in degrees.

classmethod from_dataset(dataset: Dataset) SeparableExponentialCovariance#

Restore a covariance action from to_dataset() output.

Parameters:

dataset – Versioned covariance configuration dataset.

Returns:

Reconstructed covariance action.

Raises:
  • ValueError – If the schema or version is unsupported, required coordinates are missing, or serialized constructor values are invalid.

  • KeyError – If a required covariance parameter attribute is missing.

property latitude: BorrowedDataArray#

Borrow the owned latitude coordinate; in-place mutation is unsupported.

property latitude_correlation_length: float#

Read-only resolved latitude correlation length in degrees.

property latitude_correlation_length_explicit: bool#

Whether the latitude length was configured independently.

property longitude: BorrowedDataArray#

Borrow the owned longitude coordinate; in-place mutation is unsupported.

property longitude_correlation_length: float#

Read-only resolved longitude correlation length in degrees.

property longitude_correlation_length_explicit: bool#

Whether the longitude length was configured independently.

property native_dims: tuple[str, str]#

Latitude and longitude dimension names in vectorisation order.

schema = 'openghg_inversions.separable_exponential_covariance'#
schema_version = 1#
property sigma: float#

Read-only native-cell marginal standard deviation.

solve(rhs: DataArray) DataArray#

Solve B result = rhs without constructing the native matrix.

The separable case uses one-dimensional Cholesky factors. A covariance with multiple classes uses conjugate gradients with a matrix-free blocked covariance action.

Parameters:

rhs – Array containing both native dimensions and any number of additional right-hand-side dimensions.

Returns:

B^-1 rhs with dimensions and coordinates identical to rhs.

Raises:
  • TypeError – If rhs is not an xarray data array.

  • ValueError – If native dimensions or coordinates are missing or misaligned, or if values are non-numeric or non-finite.

  • numpy.linalg.LinAlgError – If a class-blocked iterative solve does not converge.

to_dataset() Dataset#

Serialize reproducible coordinates and resolved configuration.

Returns:

A versioned dataset containing the native coordinates, resolved covariance parameters, and optional class labels. Boolean blocked state is represented as a NetCDF-safe 0 or 1 attribute.