Skip to content

localization⚓︎

Localization package for PIPT.

AutoAdaptiveLocalization ⚓︎

Bases: LocalizationBase

Adaptive localization strategy and engine implementation.

__call__(X, Y, parameters=None, prior_info=None) ⚓︎

Calculate truncated cross-covariance matrix.

Parameters:

Name Type Description Default
X (ndarray, shape(nx, ne))

State perturbation ensemble.

required
Y (ndarray, shape(ny, ne))

Projected predicted data ensemble.

required
parameters list[str]

Ordered list of parameters corresponding to blocks in X.

None
prior_info dict

Prior information for each parameter. If provided, prior_info[param]["active"] specifies the number of active variables associated with the parameter.

None

Returns:

Type Description
(ndarray, shape(nx, ny))

Tapered matrix containing the tapering coefficients for the cross-covariance between X and Y.

__init__(info, rng=None) ⚓︎

Initialize the AutoAdaptiveLocalization instance.

All configuration is supplied through the info dictionary, which maps directly to a [dataassim.localization] table in a TOML config file.

Parameters:

Name Type Description Default
info dict or list

Localization configuration. Recognised keys:

field : list of int, required Grid dimensions. For a 3-D reservoir use [nz, nx, ny]; for a 2-D field [nx, ny] is sufficient. Only the product (total cell count) is used by this class.

actnum : str, optional Path to a .npz file whose first array is a boolean mask of active cells. When supplied, only active cells are counted toward default_num_active. Default: None (all cells are considered active).

threshold : {"adaptive", "fixed", "universal"}, optional Method used to compute the correlation threshold below which a correlation is deemed indistinguishable from sampling noise:

- ``"adaptive"`` — threshold = ``cutoff * sigma``, where *sigma*
  is estimated column-wise from shuffled correlations via the
  MAD estimator. The ``cutoff`` parameter controls how many noise
  standard deviations to use as the cut-off.
- ``"fixed"`` — threshold equals ``cutoff`` directly; no noise
  estimation is performed. Use when you want a deterministic,
  reproducible cut-off independent of the ensemble.
- ``"universal"`` — threshold = ``sqrt(2 * log(N)) * sigma``;
  adapts automatically to ensemble size without requiring
  ``cutoff`` to be tuned.

Default: ``"adaptive"``.

cutoff : float, optional Threshold value or noise multiplier (interpretation depends on threshold). Larger values suppress more correlations. Default: 0.3.

type : {"hard", "soft", "sigm"}, optional Tapering strategy applied once the threshold is known:

- ``"hard"`` — binary mask: 1 where |r| ≥ threshold, 0
  elsewhere. Sharp cut-off, computationally efficient.
- ``"soft"`` — smooth rational-function taper that transitions
  gradually around the threshold. Avoids discontinuities in
  the localization operator.
- ``"sigm"`` — sigmoid-based taper; similar smoothness to
  ``"soft"`` but with a different shape near the transition.

Default: ``"hard"``.
required

Examples:

Minimal TOML block inside [dataassim] using fixed thresholding:

[dataassim.localization]
name       = "autoadaloc"
field      = [1, 20, 20]   # [nz, nx, ny]
threshold  = "fixed"
cutoff     = 0.4
type       = "hard"

Noise-adaptive thresholding with a smooth taper:

[dataassim.localization]
name       = "autoadaloc"
field      = [2, 30, 40]   # two-layer, 30×40 lateral grid
actnum     = "active_cells.npz"
threshold  = "universal"   # adapts to ensemble size automatically
type       = "soft"

Large state vector — skip forming the full cross-covariance:

[dataassim.localization]
name       = "autoadaloc"
field      = [5, 100, 100]
threshold  = "fixed"
cutoff     = 0.3
type       = "hard"

corr_matrix(X, Y, eps=1e-06) ⚓︎

Compute the correlation matrix between two ensemble matrices X and Y.

Parameters:

Name Type Description Default
X (ndarray, shape(nx, ne))
required
Y (ndarray, shape(ny, ne))
required
eps float

Small value to avoid division by zero when computing standard deviations.

1e-6

Returns:

Name Type Description
corr (ndarray, shape(nx, ny))

The correlation matrix between X and Y.

rational_function(distance, length_scale) ⚓︎

Piecewise rational taper of distance at length_scale: 1 inside the scale, decaying to 0 at twice the scale.

rational_function_sigmoid(distance, length_scale) ⚓︎

A steep sigmoid taper switching at length_scale.

tapering_function(corr_values, corr_values_shuffled) ⚓︎

Compute tapering coefficients from sample correlations.

The tapering coefficients are used to suppress correlations that are indistinguishable from noise. A noise level is estimated for each observation variable from the corresponding shuffled correlations using the median absolute deviation (MAD),

sigma = median(|r_shuffled|) / 0.6745

which provides a robust estimate of the standard deviation under the assumption of Gaussian noise.

Depending on the localization settings, the correlation threshold is computed using one of the following methods:

  • "adaptive" (default): threshold = cutoff * sigma
  • "fixed": threshold = cutoff
  • "universal": threshold = sqrt(2 log(N)) * sigma

Tapering can then be applied using one of three strategies:

  • "hard" (default): correlations above the threshold are assigned a taper value of 1, otherwise 0.
  • "soft": smooth tapering based on rational_function.
  • "sigm": sigmoid-based tapering using rational_function_sigmoid.

Parameters:

Name Type Description Default
corr_values ndarray of shape (nx, ny)

Sample correlation matrix.

required
corr_values_shuffled ndarray of shape (nx, ny)

Correlation matrix computed from shuffled or randomized ensembles. Used to estimate the noise level of the correlations.

required

Returns:

Type Description
ndarray of shape (nx, ny)

Tapering coefficients in the interval [0, 1]. These coefficients can be applied element-wise to the correlation matrix to reduce the influence of correlations attributed to sampling noise.

DistanceLocalization ⚓︎

Bases: LocalizationBase

Distance-based localization strategy for sparse mask projection.

Follows the same init/call pattern as AutoAdaptiveLocalization: - All configuration is parsed and stored at __init__ time. - __call__ assembles and returns the sparse localization operator.

Parameters:

Name Type Description Default
info dict or list

Localization configuration. Must contain:

  • field: [nz, nx, ny] grid dimensions.
  • actnum: path to .npz file with active-cell mask (optional).
  • taper_func: kernel type -- "gc", "fb", or "region" (default: "region").

Plus one of: - a .csv key or comma-separated inline rows specifying entries, or - a .pkl / .p key pointing to a pre-built entries dict.

required
data DataFrame

Observed data with time indices as rows and data types as columns.

None
parameters list of str

State parameter names used as defaults in __call__.

None
ensemble_size int

Ensemble size; used by the Furrer-Bengtsson kernel.

None
prior_info dict

Per-parameter prior information (nx, ny, nz). Used to build zero masks for unconfigured parameters.

None

__call__(curr_data=None, curr_time=None, curr_param=None) ⚓︎

Build the sparse localization operator for the current assimilation step.

Parameters:

Name Type Description Default
curr_data list of str

Data types to include. Defaults to self.data_types.

None
curr_time list

Time indices to include. Defaults to self.data_indices.

None
curr_param list of str

State parameters to update. Defaults to self.parameters.

None

Returns:

Type Description
scipy.sparse matrix, shape (n_active_cells, n_obs)

Sparse localization operator.

__init__(info, data=None, parameters=None, ensemble_size=None, prior_info=None) ⚓︎

Initialize the DistanceLocalization instance.

Spatial localization entries — one per (data_type, time, parameter) combination — are supplied either via an external CSV file or as comma-separated inline rows embedded in the info dict key. All info keys map directly to the [dataassim.localization] table in a TOML config file.

Parameters:

Name Type Description Default
info dict or list

Localization configuration. Recognised keys:

field : list of int, required Grid dimensions [nz, nx, ny]. Used to size the spatial kernel arrays and to lay out the flattened cell vectors.

actnum : str, optional Path to a .npz file whose first array is a boolean mask of active cells. When supplied, only active cells appear in the output localization operator. Default: None.

taper_func : {"gc", "fb", "region"}, optional Spatial kernel applied at each observation location:

- ``"gc"`` — **Gaspari-Cohn** fifth-order piecewise
  polynomial. Compact support extends to ``2 × radius``
  grid cells. Values lie in [0, 1] with a smooth,
  differentiable profile. The standard choice for
  distance-based localization in geoscience DA.
- ``"fb"`` — **Furrer-Bengtsson** ensemble-size-aware
  taper. Weights are scaled by ensemble size *Ne* so
  that larger ensembles produce sharper localization.
  Values lie in [0, Ne/(Ne+2)]. Pass ``ensemble_size``
  to control *Ne* (default 50).
- ``"region"`` — Binary point kernel: weight 1 at the
  single nearest cell, 0 everywhere else. Equivalent to
  assigning one observation to exactly one grid cell.

Default: ``"region"``.

entries : str, list, or dict, optional Localization entries configuration. Three formats are supported:

- **str**: Path to a CSV file containing one entry per line
  (see *CSV row format* in Notes).
- **list**: List of entry dicts or CSV row strings. Dicts must
  contain ``"taper"``, ``"x"``, ``"y"``, ``"radius"``,
  ``"data_type"``, ``"time"``, ``"param"`` (plus optional
  ``"z"``, ``"z_range"``, ``"aniso"``, ``"rotation"``).
  Wildcard ``"*"`` can be used to expand entries across all
  known values for that field.
- **dict**: Pre-built ``{(data_type, time, param): LocalizationEntry}``
  dict (rarely used; prefer the other formats).
required
data DataFrame

Observed data whose index contains the assimilation time steps (must match the time field in each CSV row) and whose columns are the data-type names (e.g. "WOPR PRO1"). Required for __call__ to produce output.

None
parameters list of str

Ordered list of state parameter names (e.g. ["permx", "poro"]). Determines which parameters receive a localization mask and the stacking order in the output.

None
ensemble_size int

Ensemble size Ne. Only affects the Furrer-Bengtsson kernel (taper_func = "fb"). Default: None ("fb" falls back to Ne = 50).

None
prior_info dict

Per-parameter grid sizes. Required only when a parameter appears in parameters but has no localization entry in the CSV; such parameters receive an all-zero weight column whose length is taken from this dict::

{"poro": {"nx": 20, "ny": 20, "nz": 1}}
None
Notes

CSV row format

Each entry is a single space-separated line with 11 fields (or 12 if the data-type name contains a space)::

taper  x_pos  y_pos  z_pos  radius  z_range  aniso  rotation  data_type  time  param

For two-word data types (e.g. WOPR PRO1) use 12 fields::

taper  x_pos  y_pos  z_pos  radius  z_range  aniso  rotation  word1  word2  time  param

Field descriptions:

  • taper — kernel tag: gc, fb, or region.
  • x_pos — observation x-cell index on the grid (0-based), along the nx axis.
  • y_pos — observation y-cell index on the grid (0-based), along the ny axis.
  • z_pos — observation layer index on the grid (0-based).
  • radius — kernel half-radius in grid cells. For gc the full support spans 2 × radius cells from the center.
  • z_range":" to spread the kernel across all nz layers, or an integer to restrict it to that single layer.
  • aniso — anisotropy ratio (x-axis scaling factor). Use 1.0 for isotropic kernels; 2.0 compresses the kernel to half-width in the x-direction.
  • rotation — clockwise rotation of the kernel in degrees. Use 0.0 for axis-aligned kernels.
  • data_type — observation type name, case-insensitive. Must match a column in the data DataFrame.
  • time — assimilation time step; must match an index value of the data DataFrame.
  • param — state parameter name, case-insensitive. Must appear in the parameters list.

Examples:

TOML config using an external CSV file (recommended for many observation types or time steps):

[dataassim.localization]
name       = "distance_loc"
field      = [1, 20, 20]    # [nz, nx, ny]
taper_func = "gc"
"loc_entries.csv" = true    # key = filename; value is ignored

Example loc_entries.csv (Gaspari-Cohn, isotropic, all layers):

gc 10 10 0  6 : 1.0  0.0  pressure    400.0 permx
gc 10 10 0  6 : 1.0  0.0  pressure    800.0 permx
gc  5 15 0  4 : 1.0  0.0  wopr pro1   400.0 permx
gc  5 15 0  4 : 2.0 30.0  wopr pro1   800.0 permx

TOML config using the Furrer-Bengtsson kernel with active-cell mask and anisotropic entries in the CSV:

[dataassim.localization]
name       = "distance_loc"
field      = [2, 30, 40]    # two-layer, 30×40 lateral grid
taper_func = "fb"
actnum     = "active.npz"
"loc_entries.csv" = true

loc_entries.csv restricting each observation to layer 0 only (z_range = 0) with anisotropic, rotated kernel:

fb  8 12 0 6 0 2.0 45.0 wopr pro1 400.0 permx
fb 15  5 0 8 0 1.0  0.0 wwct pro2 400.0 permx

Python config using the entries key with a list of dicts (modern preferred approach):

info = {
    "field": [1, 20, 20],
    "taper_func": "gc",
    "entries": [
        {
            "taper": "gc",
            "x": 10, "y": 10, "z": 0,
            "radius": 6,
            "z_range": ":",
            "aniso": 1.0, "rotation": 0.0,
            "data_type": "pressure",
            "time": 400.0,
            "param": "permx",
        },
        {
            "taper": "gc",
            "x": 5, "y": 15, "z": 0,
            "radius": 4,
            "z_range": ":",
            "aniso": 1.0, "rotation": 0.0,
            "data_type": "wopr pro1",
            "time": 400.0,
            "param": "permx",
        },
    ]
}

Wildcard expansion in entries (apply one config to all data types):

info = {
    "field": [1, 20, 20],
    "taper_func": "gc",
    "entries": [
        {
            "taper": "gc",
            "x": 10, "y": 10, "z": 0,
            "radius": 6,
            "z_range": ":",
            "aniso": 1.0, "rotation": 0.0,
            "data_type": "*",      # expands to all data types
            "time": "*",           # expands to all times
            "param": "permx",
        },
    ]
}

FurrerBengtssonKernel ⚓︎

Furrer-Bengtsson ensemble-size-aware taper kernel.

build(radius, anisotropy_ratio, rotation_deg, field_shape, ensemble_size=None) ⚓︎

Taper weights around a datum: Furrer-Bengtsson decay over radius cells, adjusted for the ensemble size.

GaspariCohnKernel ⚓︎

Gaspari-Cohn compactly supported smooth taper kernel.

build(radius, anisotropy_ratio, rotation_deg, field_shape, ensemble_size=None) ⚓︎

Taper weights around a datum: smooth Gaspari-Cohn decay over radius cells, stretched by anisotropy_ratio.

LocalAnalysisLocalization ⚓︎

Bases: LocalizationBase

Local-analysis strategy carrying mode-specific localization metadata.

__init__(info, data_indices=None, data_types=None, parameters=None, ensemble_size=None) ⚓︎

Initialize the LocalAnalysisLocalization instance.

Parameters:

Name Type Description Default
info dict or list

Localization configuration information.

required
data_indices list

Indices of the data to be assimilated.

None
data_types list

Types of the data to be assimilated.

None
parameters list

List of free parameters for the assimilation.

None
ensemble_size int

Size of the ensemble used in the assimilation.

None

LocalizationBase ⚓︎

Bases: ABC

Shared base for localization engines and workflow strategies.

config_common(info) ⚓︎

Configure the common localization parameters for all strategies.

Parameters:

Name Type Description Default
info dict or list

Localization configuration information. - field: list of integers specifying the localization field dimensions. - actnum: optional path to a .npz file containing the actnum array

required

LocalizationConfigBuilder ⚓︎

Build normalized localization configuration and precomputed masks.

build(data_index, data_types, parameters, ne) ⚓︎

Build the localization info dictionary used by strategies.

RegionKernel ⚓︎

Binary region kernel - full weight (1) everywhere within range.

build(radius=None, anisotropy_ratio=1.0, rotation_deg=0.0, field_shape=None, ensemble_size=None) ⚓︎

Weight 1 everywhere within radius (stretched by anisotropy_ratio), 0 outside.

available_localizations() ⚓︎

The registered localization names, sorted.

build_localization_instance(parsed_info, data_indices=None, data_types=None, parameters=None, ensemble_size=None, data=None, prior_info=None, rng=None) ⚓︎

Create the localization strategy the config names.

rng is the run's random stream, for strategies that draw (the auto-adaptive one shuffles the ensemble to estimate a noise level).

normalize_parsed_info(parsed_info) ⚓︎

Normalize localization input to dictionary form, naming the mode if it does not.

parse_init_args(data_indices=None, data_types=None, parameters=None, ensemble_size=None) ⚓︎

Parse constructor arguments using canonical keyword names.

register_localization(name, builder, *, overwrite=False) ⚓︎

Make a localization strategy selectable as localization = {name = ...}.

Parameters:

Name Type Description Default
name str

The value of the config's name key.

required
builder callable

Called as builder(info=..., data_indices=..., data_types=..., parameters=..., ensemble_size=..., data=..., prior_info=..., rng=...); it may ignore what it does not need. Returns the strategy object, which the analyses use through its name attribute and by calling it.

required
overwrite bool

Allow replacing an existing entry. Off by default, so two packages claiming the same name is an error rather than a load-order lottery.

False