Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", 3.11, 3.12]
python-version: ["3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v4
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ at NORCE Norwegian Research Centre AS.

## Installation

PET requires Python 3.12 through 3.14. The standard installation includes EnIF
and EnIF-MDA with their dependencies.

Before installing ensure you have python3 pre-requisites. On a Debian system run:

```
Expand Down Expand Up @@ -139,8 +142,9 @@ Some basic plotting functionality is provided [here](https://github.com/Python-E

## Tutorials

- A PIPT tutorial is found [here](https://python-ensemble-toolbox.github.io/PET/tutorials/pipt/TinyBox/tutorial_pipt)
- A POPT tutorial is found [here](https://python-ensemble-toolbox.github.io/PET/tutorials/popt/5Spot/tutorial_popt)
- A PIPT tutorial is found [here](https://python-ensemble-toolbox.github.io/PET/tutorials/pipt/tutorial_pipt)
- A POPT tutorial is found [here](https://python-ensemble-toolbox.github.io/PET/tutorials/popt/tutorial_popt)
- [EnIF and EnIF-MDA](docs/tutorials/enif.md): installation, analysis settings and parameter graphs.

## Suggested readings:

Expand Down
5 changes: 3 additions & 2 deletions docs/tutorials/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ Here are some tutorials.

## Running PIPT and POPT

- [`tutorial_pipt.ipynb`](pipt/TinyBox/tutorial_pipt): Tutorial for running PIPT
- [`tutorial_popt.ipynb`](popt/5Spot/tutorial_popt): Tutorial for running POPT
- [`tutorial_pipt.ipynb`](pipt/tutorial_pipt): Tutorial for running PIPT
- [`tutorial_pipt.ipynb`](popt/tutorial_popt): Tutorial for running POPT
- [EnIF and EnIF-MDA](enif.md): Information-filter analyses and parameter graphs

## Data structures

Expand Down
118 changes: 118 additions & 0 deletions docs/tutorials/enif.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Ensemble information filter (EnIF)

PET provides the original, single-update EnIF and an EnIF-MDA variant. Both
use the sparse regression and precision estimation from ERT's
[`_enif_update.py`](https://github.com/equinor/ert/blob/main/src/ert/analysis/_enif_update.py)
through `graphite-maps`.

## Installation

Install PET from your checkout, including EnIF and its dependencies:

```sh
python -m pip install -e .
```

PET requires Python 3.12 through 3.14, matching its `graphite-maps` dependency.

## Select the analysis

Keep your existing ensemble, observation and simulator settings. For one EnIF
update, set these entries in `dataassim`:

```yaml
daalg: [enif, enif]
analysis: full
```

For EnIF-MDA, use:

```yaml
daalg: [enif, enif]
analysis: mda
mda:
tot_assim_steps: 3
inflation_param: [2, 4, 4]
```

The corresponding classes are `enif_full` and `enif_mda` in
`pipt.update_schemes.enif`. PET's `pipt_init.init_da` loads them through the
existing configuration interface.

Both variants assimilate all selected `assimindex` entries together. Standard
EnIF performs one update with inflation 1; it does not need `mda` settings.
EnIF-MDA reruns the simulator and refits the regression and state precision
after each update.

MDA requires positive, finite inflation factors satisfying
`sum(1 / alpha) = 1`. If you omit `inflation_param`, PET uses
`tot_assim_steps` for each factor. A scalar factor repeats across the schedule.
The schedule retains its original indexing on restart.

## Parameter graphs

EnIF estimates a separate prior precision block for each state in `idX`.
By default:

- A state with `grid` metadata in `prior_<state>` uses nearest-neighbour
connectivity. PET's prior parser converts `grid` to `nx`, `ny` and `nz`.
- A state without grid metadata uses independent graph nodes.

The regular-grid ordering matches PET's layered prior generator:
`row = z * nx * ny + x * ny + y` (y varies fastest). For imported ensembles
with a different ordering, reduced active-cell arrays or irregular geometry,
provide a graph whose node numbers match the imported parameter rows.

You can configure graphs and neighbourhood sizes under `enif`:

```yaml
enif:
parameter_graphs:
perm: perm_graph.npz
neighbourhood_expansion: 2
neighbor_propagation_order: 15
```

Write a graph file as a symmetric sparse adjacency array with
`scipy.sparse.save_npz`. For example, for five parameters arranged in a chain:

```python
import networkx as nx
from scipy import sparse

graph = nx.path_graph(5)
sparse.save_npz('perm_graph.npz', nx.to_scipy_sparse_array(graph, format='csc'))
```

Python configurations can also supply NetworkX graphs or SciPy sparse
adjacency arrays directly in `parameter_graphs`. Use local node numbers
`0` through `number_of_parameter_rows - 1` for each state. Graph weights do
not affect the fit; EnIF uses connectivity.

EnIF excludes rows containing non-finite values and rows with zero ensemble
spread from estimation. It removes their graph nodes without connecting
neighbours across the resulting gaps. The analysis gives those rows a zero
increment, then applies PET's configured state limits.

## Update and diagnostics

EnIF uses PET's perturbed observations, random-number stream, state clipping,
forecast loop and misfit reporting. It scales observation covariance by the
current MDA factor once. It also estimates the unexplained response variance,
as in ERT. For a correlated observation covariance, it whitens the observations,
forecasts and perturbations before fitting the response map.

The EnIF-specific update and helpers live in `pipt/update_schemes/enif.py`.
The scheme inherits PET's `esmdaMixIn` lifecycle and returns an additive
`step`, following the existing update-method interface. It uses the direct
sparse solver, matching ERT's non-iterative transport setting.

For `analysisdebug`, the scheme exposes `H`, `Prec_u`, `Prec_eps` and
`Prec_posterior`. These matrices use standardized, retained state rows;
`enif_active_rows` maps them back to the full state. With correlated observation
errors, `H` and `Prec_eps` use whitened observation coordinates.

This scheme requires at least two ensemble members and positive observation
variances. It does not support PET's covariance localization, local analysis,
multilevel ensembles or `emp_cov` sample input. Use parameter graphs to specify
spatial dependence.
13 changes: 8 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "PET"
version = "1.0"
version = "0.2"
description = "Python Ensemble Toolbox"
authors = [
{ name = "Data assimilation and optimization group" }
Expand All @@ -15,15 +15,15 @@ maintainers = [
]
license = { file = "LICENSE" }
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.12,<3.15"
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Scientific/Engineering",
]
dependencies = [
Expand All @@ -33,7 +33,10 @@ dependencies = [
"h5py",
"tqdm",
"PyWavelets",
"geostat @ git+https://github.com/Python-Ensemble-Toolbox/Geostatistics@3f9f0c876815db140fae3404d322892190cb6728",
"psutil",
"geostat @ git+https://github.com/Python-Ensemble-Toolbox/Geostatistics@main",
"graphite-maps>=0.0.11,<0.1",
"pytest",
"pandas",
"p_tqdm",
"tomli",
Expand Down
Loading
Loading