Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
341 commits
Select commit Hold shift + click to select a range
f88fe0e
Comment out log.info
MathiasMNilsen Jan 14, 2026
c8ae932
Reorganize code with ensemble-matrix
MathiasMNilsen Jan 14, 2026
c6ed492
Fix small bug
MathiasMNilsen Jan 14, 2026
fc4668c
Fix bug relating to data_mismatch for multilevel
MathiasMNilsen Jan 15, 2026
3cc09aa
Remove unused imports for multilevel
MathiasMNilsen Jan 15, 2026
5f935aa
Add progbar_settings to multilevel
MathiasMNilsen Jan 15, 2026
2950568
Update popt/update_schemes/linesearch.py
KriFos1 Jan 15, 2026
542c51e
Update pipt/update_schemes/update_methods_ns/hybrid_update.py
KriFos1 Jan 15, 2026
559c9ba
Update pipt/misc_tools/extract_tools.py
KriFos1 Jan 15, 2026
af200ca
Update pipt/loop/ensemble.py
KriFos1 Jan 15, 2026
16ed42e
Update optimize.py
rolfjl Jan 15, 2026
f8f1a74
Fix bugs
MathiasMNilsen Jan 15, 2026
e3cc78e
Merge branch 'main' of github.com:MathiasMNilsen/PET
MathiasMNilsen Jan 15, 2026
b52f83f
Fix bugs
MathiasMNilsen Jan 16, 2026
602bb6b
Update linesearch.py
MathiasMNilsen Jan 16, 2026
fc8bd60
Update ensemble_tools.py
MathiasMNilsen Jan 16, 2026
10ac754
Merge branch 'Python-Ensemble-Toolbox:main' into main
MathiasMNilsen Jan 16, 2026
b227367
update TrustRegion
MathiasMNilsen Jan 21, 2026
32dfeab
Fix serious bug regarding scaling of enX for popt
MathiasMNilsen Jan 21, 2026
1890720
Merge branch 'main' of github.com:MathiasMNilsen/PET
MathiasMNilsen Jan 21, 2026
6673b4e
Remove one-liner
MathiasMNilsen Jan 22, 2026
43eee87
Improve some logic for ensemble gradient
MathiasMNilsen Jan 22, 2026
bfc4ee1
Include adjoints from simulator
MathiasMNilsen Feb 3, 2026
903f262
fix bug
MathiasMNilsen Feb 3, 2026
2d9b20d
Fix iter bug for line-search
MathiasMNilsen Feb 4, 2026
ea5b356
Maake line-search logger fancier
MathiasMNilsen Feb 4, 2026
bc77354
Make line-search logger fancier
MathiasMNilsen Feb 4, 2026
6e2ee74
Update TrustRegion and Logger
MathiasMNilsen Feb 10, 2026
602846a
Include adjoints for LM-EnRML
MathiasMNilsen Feb 11, 2026
4da0778
Small fix
MathiasMNilsen Feb 11, 2026
e0dee27
Merge branch 'main' into main
rolfjl Feb 11, 2026
c9f3d74
Merge branch 'Python-Ensemble-Toolbox:main' into main
MathiasMNilsen Feb 11, 2026
dd4cf6c
Update truncSVD
MathiasMNilsen Mar 3, 2026
6286664
Change order of log_update
MathiasMNilsen Mar 3, 2026
fd9f528
Fix ensemble size handling and staticvar import logic
MathiasMNilsen Mar 4, 2026
c915ef1
Fix bug
MathiasMNilsen Mar 4, 2026
594f6f9
Merge branch 'Python-Ensemble-Toolbox:main' into main
MathiasMNilsen Mar 5, 2026
c941c2a
Update adjoint handling
MathiasMNilsen Mar 12, 2026
9fbdfdd
Fix logic for logging in LM-EnRML
MathiasMNilsen Mar 16, 2026
af8e3c1
Include ensemble_mistfit for LM-EnRML
MathiasMNilsen Mar 16, 2026
3e29201
Include enAdj for ESMDA
MathiasMNilsen Mar 17, 2026
2c84fff
Fix logger table column centering
MathiasMNilsen Mar 17, 2026
2866655
Merge branch 'Python-Ensemble-Toolbox:main' into main
MathiasMNilsen Mar 18, 2026
d80dc61
Add PETDataFrame and PETStateArray data structures
MathiasMNilsen Mar 19, 2026
38454fc
Use PETDataFrame for adjoint ensemble
MathiasMNilsen Mar 19, 2026
d02c50f
Add sampling function to PETStateArray
MathiasMNilsen Mar 23, 2026
b70d7ff
Add tests for PET structures
MathiasMNilsen Mar 24, 2026
f2dcb13
Add CSV reader to PETDataFrame
MathiasMNilsen Mar 25, 2026
ceae3aa
Start to use PETDataFrame for data and predictions
MathiasMNilsen Mar 27, 2026
5326dab
Normalize yes/no key flags to boolean checks
MathiasMNilsen Apr 7, 2026
0ee2f28
Refactor PET matrix/data handling and update structure tests
MathiasMNilsen Apr 7, 2026
fb2ae07
Preserve ensemble metadata in matrix-based update flow
MathiasMNilsen Apr 8, 2026
0d67993
Add DataReader class and some refactoring
MathiasMNilsen Apr 9, 2026
1cebb7b
Include some tests for DataReader
MathiasMNilsen Apr 10, 2026
3d36d1b
Fix popt and add tests
MathiasMNilsen Apr 13, 2026
c65105d
Merge branch 'main' into feature/pet_structures
MathiasMNilsen Apr 13, 2026
909b9b2
Move structures package into src and remove stray test artifact
MathiasMNilsen Apr 13, 2026
4fd6b9e
Fix bug
MathiasMNilsen Apr 13, 2026
31d6e7a
Update Rosenbrock test
MathiasMNilsen Apr 13, 2026
b282f69
Fix bug
MathiasMNilsen Apr 13, 2026
e040a45
Rename some input variable
MathiasMNilsen Apr 13, 2026
4e8c83c
Add adjoint to EnKF
MathiasMNilsen Apr 14, 2026
25d5da6
Add tests for truncSVD
MathiasMNilsen Apr 14, 2026
25a6c59
Move remove_outliers to anlysis_tools
MathiasMNilsen Apr 15, 2026
2386093
Move remove_outliers to anlysis_tools
MathiasMNilsen Apr 15, 2026
57f8927
Fix bugs
MathiasMNilsen Apr 16, 2026
704203a
Fix prediction save
MathiasMNilsen Apr 16, 2026
8289c00
Small fix
MathiasMNilsen Apr 16, 2026
65112c9
Update ML with PET structures
MathiasMNilsen Apr 17, 2026
3cc273c
Fix small bugs
MathiasMNilsen Apr 17, 2026
375ff55
Fix small bugs
MathiasMNilsen Apr 17, 2026
3e25b2e
Fix ML bugs
MathiasMNilsen Apr 21, 2026
37761ec
Add scaling methods for PETDataFrame
MathiasMNilsen Apr 22, 2026
21bf9b2
Add scaling methods for PETDataFrame
MathiasMNilsen Apr 22, 2026
722be26
Include scaling in code
MathiasMNilsen Apr 22, 2026
9278a70
Update Gauss-Newton
MathiasMNilsen Apr 28, 2026
ef6a055
Fix some bugs
MathiasMNilsen Apr 28, 2026
9a1bfd9
Small bugfix
MathiasMNilsen May 5, 2026
779ba74
Add VanderPol simulator for testing
MathiasMNilsen May 5, 2026
13b22ee
Add tests data assimilation workflows
MathiasMNilsen May 5, 2026
5e8c158
Add adjoint in Approx update
MathiasMNilsen May 13, 2026
78c3103
Refactor Assimilate with AI
MathiasMNilsen May 21, 2026
ae1cb8b
Fox bugs for sparse data run
MathiasMNilsen May 21, 2026
e96f6d2
Fix small bug
MathiasMNilsen May 21, 2026
c1e1ce3
Remove old data-reader methods
MathiasMNilsen May 21, 2026
f1a3a70
Save DataFrames as list of records in debug files
MathiasMNilsen May 21, 2026
ced3315
Add report-pont reader
MathiasMNilsen May 22, 2026
3a80298
Refactor config normalization, outlier handling, and remove legacy an…
MathiasMNilsen May 26, 2026
a354c1c
Improve readability of tests
MathiasMNilsen May 26, 2026
d39dc9e
Improve report_point_file_reader to handle int and datetime robustly;…
MathiasMNilsen May 26, 2026
ef60115
Update tests
MathiasMNilsen May 27, 2026
97b70cd
Remove NPV function, it is relocated to SimulatorWraps
MathiasMNilsen May 27, 2026
b419905
small fix
MathiasMNilsen Jul 3, 2026
45d3d3b
Remove npv import
MathiasMNilsen Jul 6, 2026
ce61785
Add new base class for optimization loop
MathiasMNilsen Jul 3, 2026
765d637
Remove scaling from POPT ensembles and cleaned them up.
MathiasMNilsen Jul 6, 2026
a693852
Update TrustRegion
MathiasMNilsen Jul 6, 2026
4a5c87f
Small change in func wrapper
MathiasMNilsen Jul 6, 2026
221584f
Fix bug
MathiasMNilsen Jul 6, 2026
4e2cc8f
Refactor Enopt and test
MathiasMNilsen Jul 6, 2026
c7f80f6
Re-write SmcOpt with AI
MathiasMNilsen Jul 6, 2026
c048932
small test fix
MathiasMNilsen Jul 6, 2026
8d665f7
Improve docstrings for EnOpt and TrustRegion
MathiasMNilsen Jul 7, 2026
fbabf66
Better name structure for PET ensemble
MathiasMNilsen Jul 7, 2026
d279997
Update install dependencies
MathiasMNilsen Jul 7, 2026
01ddc69
Fix install bug
MathiasMNilsen Jul 7, 2026
15dca2c
Fix install bug
MathiasMNilsen Jul 7, 2026
15da17b
Replace row_stack (depricated)
MathiasMNilsen Jul 7, 2026
63af4c0
refactor: introduce pipt.localization package and modernise update sc…
MathiasMNilsen Aug 11, 2026
14debe8
Small logic fix
MathiasMNilsen Aug 11, 2026
fdc4f7f
fix(distance_loc): correct CSV field order, actnum+z_range, and impor…
MathiasMNilsen Aug 12, 2026
5c7959f
Improve localizations
MathiasMNilsen Aug 12, 2026
b7cd6f7
Fix logic
MathiasMNilsen Aug 12, 2026
0ee6f4c
Modernize packaging, tooling, and CI
claude Aug 13, 2026
5cd9c6f
Add pet CLI for validating and converting config files
claude Aug 13, 2026
b52d359
Clean up lint findings and fix latent bugs across src
claude Aug 13, 2026
e0206d0
Merge feature/refactor_loc: adopt pipt.localization package
claude Aug 13, 2026
adc2946
Add AssimilationSchemeBase, the PIPT counterpart to popt's OptimizerBase
claude Aug 13, 2026
751d2c0
Add AnalysisStrategy base, deduplicating the analysis-flavour helpers
claude Aug 13, 2026
8f0b602
Replace importlib scheme dispatch with an explicit registry
claude Aug 13, 2026
994af67
Add algorithm-level scheme constructors, flavour as an argument
claude Aug 13, 2026
3dba9c9
Replace the daalg config key with scheme, and add `pet migrate`
claude Aug 13, 2026
b1ed4dd
Tidy repo root: relocate example CSV, drop stray artifact
claude Aug 13, 2026
52fd87e
Add CHANGELOG documenting the breaking config change
claude Aug 13, 2026
6dbfe0a
Add characterisation tests pinning current numerical output
claude Aug 14, 2026
d6fb280
Split pipt/loop/ensemble.py into a pipt/ensembles/ package
claude Aug 14, 2026
a22162c
Add Phase 8 handover document
claude Aug 14, 2026
83e8855
Preserve formatting and comments in `pet migrate`
claude Aug 14, 2026
d2b0ff2
Move the forecast from the assimilation loop onto the ensemble
claude Aug 14, 2026
ceff647
Add characterisation coverage for es before migrating it
claude Aug 14, 2026
b4417ee
Migrate esmda onto AssimilationSchemeBase
claude Aug 14, 2026
3721753
Migrate lmenrml and gnenrml onto AssimilationSchemeBase
claude Aug 14, 2026
193a91a
Fix enkf's dangling full_cov_data reference and characterise it
claude Aug 17, 2026
c17f93e
Fix ES discarding its own update
claude Aug 17, 2026
3dd91ac
Migrate es and enkf onto AssimilationSchemeBase
claude Aug 17, 2026
3b56980
Delete Assimilate; schemes own their loop
claude Aug 17, 2026
d18cc7c
Make Scheme.assimilate() take what the constructor takes
claude Aug 17, 2026
d531e04
Stop the factory's default from overriding the config's analysis
claude Aug 17, 2026
502f67a
Let an analysis strategy bind to a scheme instead of being mixed in
claude Aug 17, 2026
20962dd
Write strategy attributes through to the bound scheme
claude Aug 17, 2026
c02be5c
Collapse the eighteen scheme classes into five
claude Aug 17, 2026
b25625f
Drive the characterisation cases through Scheme.assimilate()
claude Aug 17, 2026
a8f1b4b
Move the remaining tests onto the class entry points
claude Aug 17, 2026
bd00a6e
Rewrite the scheme and assimilate() docstrings
claude Aug 18, 2026
a467472
Fix the multilevel scheme, which had never completed a run
claude Aug 18, 2026
80e23d9
Reorganise update_schemes by concern
claude Aug 18, 2026
f2d0f88
Bring the documentation back in line with the code
claude Aug 18, 2026
676ddcd
Fix the pipt tutorial
MathiasMNilsen Aug 18, 2026
0dc9b65
Make the prior forecast's misfit available to the iteration-0 artifacts
claude Aug 18, 2026
545b87e
Rename analysisdebug to savedata and its output to assimilation_resul…
claude Aug 18, 2026
275900a
Completed PIPT tutorial
MathiasMNilsen Aug 19, 2026
1336345
Rename the loop methods for the job they do, in both packages
claude Aug 19, 2026
7987cf2
Remake the popt tutorial to match the pipt one
claude Aug 19, 2026
4b70346
Make the popt tutorial's run cells safe to re-execute
claude Aug 19, 2026
8a4f2d5
Stop popt swallowing TypeErrors raised inside the objective
claude Aug 19, 2026
166a9b6
Clear En_<member> scratch folders before each prediction, not only at…
claude Aug 19, 2026
92eed49
Report an objective that fits neither call shape, rather than guessing
claude Aug 19, 2026
ad595a8
Collapse eighteen per-flavour scheme classes into COMPATIBLE_ANALYSES…
MathiasMNilsen Aug 20, 2026
fa7d92a
Check convergence after every attempt, not only accepted iterations
MathiasMNilsen Aug 20, 2026
73fc94a
Replace the popt 3WELL tutorial with a 5SpotLineSearch walkthrough
MathiasMNilsen Aug 20, 2026
008d37f
Move the pipt tutorial into TinyBox/, add a GN-EnRML/margis example
MathiasMNilsen Aug 20, 2026
8edae63
Remove stale Phase 8 handover doc
MathiasMNilsen Aug 20, 2026
c16df9a
Make logit/logger_name real options, defaulting to ASSIM.log
MathiasMNilsen Aug 24, 2026
ab20d4c
Replace scheme->ensemble __getattr__ with declared properties; unify …
MathiasMNilsen Aug 24, 2026
dff6dc1
Report the criterion that stopped a converged EnRML run; fix lint
MathiasMNilsen Aug 24, 2026
8f1efe6
Finish check_state_convergence: snapshot enX_old in the loop
MathiasMNilsen Aug 24, 2026
b945dcd
Trim inline commentary in scheme_base to the load-bearing parts
MathiasMNilsen Aug 24, 2026
2ce5fde
Assign step_accepted directly from update_step()
MathiasMNilsen Aug 24, 2026
c77ecf7
add localization tutorials
MathiasMNilsen Aug 24, 2026
9c05db8
Add tutorials for writing a new analysis and a new scheme
MathiasMNilsen Aug 24, 2026
0d1a2f6
Move after_analysis off the scheme base
MathiasMNilsen Aug 24, 2026
40931ed
Replace the optional-hooks table with the actual call order
MathiasMNilsen Aug 24, 2026
b15df91
Document what update_step() must leave behind
MathiasMNilsen Aug 24, 2026
b249dce
Return a StepReport from update_step() instead of a bool
MathiasMNilsen Aug 24, 2026
838c11d
Rename data_misfit to data_misfit_mean on the schemes
MathiasMNilsen Aug 24, 2026
f684b0c
Fix a docstring the data_misfit_mean rename missed
MathiasMNilsen Aug 24, 2026
6b87184
Move the state commit into StepReport and the loop
MathiasMNilsen Aug 24, 2026
5166c49
Say why enX_temp is cleared, and drop an import the change orphaned
MathiasMNilsen Aug 24, 2026
0ac5454
Pass the state to forecast instead of parking it in enX_temp
MathiasMNilsen Aug 24, 2026
9de972b
Update the scheme tutorial's prose for the forecast(state) change
MathiasMNilsen Aug 24, 2026
a6cfc04
Add the state field to the tutorial's StepReport snippet
MathiasMNilsen Aug 24, 2026
a5440d4
Move the shared log_update row to the scheme base
MathiasMNilsen Aug 24, 2026
a2a173c
Give the scheme tutorial a config it actually reads
MathiasMNilsen Aug 24, 2026
5c06046
Bring the scheme checklist in line with the contract
MathiasMNilsen Aug 24, 2026
5f67d0d
Make the tutorial scheme log its iterations
MathiasMNilsen Aug 24, 2026
16b5676
Trim the loop's commentary back to what a reader can get wrong
MathiasMNilsen Aug 24, 2026
bae3533
Tidy the execution counts in the auto-adaptive localization tutorial
MathiasMNilsen Aug 24, 2026
841ff69
Move the extending tutorials under pipt
MathiasMNilsen Aug 25, 2026
8de7339
Add comments
MathiasMNilsen Aug 25, 2026
5d5de88
Move the inner damping loop into update_step, and scoring into score()
MathiasMNilsen Aug 28, 2026
a371527
Keep at least the requested energy fraction in truncSVD
MathiasMNilsen Sep 7, 2026
6391524
Fix the idX offset for the second and later prior variables
MathiasMNilsen Sep 7, 2026
45badac
Move a replaced member's adjoint together with its state
MathiasMNilsen Sep 7, 2026
82d7387
Stop the analyses allocating what they never use
MathiasMNilsen Sep 7, 2026
03fc1bd
Import QA/QC, wavelets and geostat only where they are used
MathiasMNilsen Sep 7, 2026
fe7f90d
Drop mako, psutil and six; pin geostat to a commit
MathiasMNilsen Sep 7, 2026
c1669df
Drop two full-ensemble copies that nothing reads
MathiasMNilsen Sep 7, 2026
cdff13d
Remove code with no callers
MathiasMNilsen Sep 7, 2026
2e2c8f6
Make co_lm_enrml and gn_enrml thin names for the algorithms they were
MathiasMNilsen Sep 7, 2026
af394aa
Run every test in a temporary directory; seed the pipeline tests
MathiasMNilsen Sep 7, 2026
e0eb2bd
Root the API reference at src and rewrite the developer guide for thi…
MathiasMNilsen Sep 7, 2026
e55ce9a
Give every module a docstring so the API reference lists it
MathiasMNilsen Sep 7, 2026
d4006de
Pin the five untested scheme/analysis pairs in the golden suite
MathiasMNilsen Sep 7, 2026
fb89d9c
Remove the twelve analysis_tools functions nothing calls
MathiasMNilsen Sep 7, 2026
e2d96e1
Clip through PETStateArray in EnKF; drop the duplicate clipper and th…
MathiasMNilsen Sep 7, 2026
f73b275
Let esmda_hybrid inherit update_step and check_convergence
MathiasMNilsen Sep 7, 2026
3039b08
Write down the simulator contract as ensemble.protocols.ForwardSimulator
MathiasMNilsen Sep 7, 2026
2b41a93
Record the unwhitened subspace anomalies as a known issue, with a str…
MathiasMNilsen Sep 7, 2026
9dc4222
Include pet_cli in the standalone-import check
MathiasMNilsen Sep 7, 2026
01767a6
Whiten the predicted anomalies in the subspace analysis
MathiasMNilsen Sep 8, 2026
24f1b80
Score EnKF and ES against the data covariance, not its square root
MathiasMNilsen Sep 8, 2026
9efdf2f
Apply the state scaling in the approx and full analyses
MathiasMNilsen Sep 8, 2026
34961d6
Replace a crashed member's state along with its prediction; make the …
MathiasMNilsen Sep 8, 2026
0d8796a
Place localization kernels with their own axes
MathiasMNilsen Sep 8, 2026
7b1688b
Refuse the unsupported screendata option with an explanation
MathiasMNilsen Sep 8, 2026
9b2254e
Fix five verified bugs in popt's numerical subroutines
MathiasMNilsen Sep 8, 2026
acb5637
Fix six small crash and correctness bugs across misc, simulator and pipt
MathiasMNilsen Sep 8, 2026
1318945
Port QA/QC to the ensemble's frames
MathiasMNilsen Sep 8, 2026
dfd9c70
Return analysis results instead of writing them onto the scheme
MathiasMNilsen Sep 8, 2026
f6b4324
Collapse LM-EnRML and GN-EnRML onto one IterativeEnRML base
MathiasMNilsen Sep 8, 2026
236bf41
Let schemes take a ready-made ensemble; select localization from a re…
MathiasMNilsen Sep 8, 2026
2a1b976
Give each log file its own logger; raise instead of exiting; create f…
MathiasMNilsen Sep 8, 2026
7a199fd
Draw every random number from the ensemble's stream; add a `seed` option
MathiasMNilsen Sep 8, 2026
ce1ce58
Honour restart_sim_results.pkl only on a restart; fix popt's save_pre…
MathiasMNilsen Sep 8, 2026
6c9c9bc
Let OptimizerBase own the choreography around a step
MathiasMNilsen Sep 8, 2026
fff9583
Unify restart on RestartMixin: one checkpoint the scheme writes and r…
MathiasMNilsen Sep 8, 2026
8d59232
Split calc_prediction into orchestration and four named steps
MathiasMNilsen Sep 8, 2026
0895fbd
Remove the uncalled module-level readers from read_input_csv
MathiasMNilsen Sep 9, 2026
c44529f
Add DataLayout; build the observation vector from it
MathiasMNilsen Sep 9, 2026
d4767ea
Fill the prediction matrix directly from the member outputs
MathiasMNilsen Sep 9, 2026
2469fae
Keep the forecast as the members returned it; adjoints as an array
MathiasMNilsen Sep 9, 2026
4cbed9f
Build the observation variance from the layout; retire construct_data…
MathiasMNilsen Sep 9, 2026
b4f273e
Replace PETStateArray with a plain state array and a StateLayout
MathiasMNilsen Sep 9, 2026
fb590f1
Tutorials: describe the layout-ordered matrices, not the frame flatten
MathiasMNilsen Sep 9, 2026
5c1e370
Move StateLayout into layout.py
MathiasMNilsen Sep 17, 2026
c1f9619
Compress seismic vintages as the prediction matrix is filled
MathiasMNilsen Sep 17, 2026
4e85819
Drop the schemes' max_iter attribute; keep maxiter
MathiasMNilsen Sep 17, 2026
6a0d4ac
max_iter counts update iterations, not the prior forecast
MathiasMNilsen Sep 17, 2026
54cbb06
One configuration boundary: normalise once, validate by key
MathiasMNilsen Sep 17, 2026
4285094
Document the configuration and the architecture; a public popt API
MathiasMNilsen Sep 17, 2026
d49a323
Merge upstream/main: reconcile the restructuring with upstream's 15 c…
MathiasMNilsen Sep 17, 2026
3ecbb0c
Write the PET log file as UTF-8
MathiasMNilsen Sep 17, 2026
5019717
Record an HPC extraction failure against its own member, not the batch
MathiasMNilsen Sep 17, 2026
0f336b3
Converge the outer EPF loop on the constraint violation, not the step…
MathiasMNilsen Sep 17, 2026
c894f3e
Understand a LOCALIZATION block that names no mode
MathiasMNilsen Sep 17, 2026
9fc7010
Build the distance localization operator over the active cells
MathiasMNilsen Sep 17, 2026
7306525
Read a pickled localization file into localization entries
MathiasMNilsen Sep 17, 2026
d77d72b
Add the subspace2 analysis: Gauss-Newton on the ensemble transform
MathiasMNilsen Sep 17, 2026
1ccd840
Restore GenOpt and CMA on the current optimizer base
MathiasMNilsen Sep 17, 2026
f45657b
Let the optimizer reject a crashed evaluation instead of ending the run
MathiasMNilsen Sep 17, 2026
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
22 changes: 17 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# - Compute test coverage and submit to coveralls.io
# - Also config for macOS and/or Windows
# - Also config for conda
# - Lint

name: CI tests

Expand All @@ -19,6 +18,19 @@ on:
- '*'

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install ruff
run: python -m pip install ruff
- name: Run ruff
run: ruff check src tests

bundled:

runs-on: ubuntu-latest
Expand All @@ -28,15 +40,15 @@ jobs:
python-version: ["3.10", 3.11, 3.12]

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools
python -m pip install -e .
python -m pip install -e ".[dev]"
- name: Launch tests
run: |
pytest
pytest --cov=src --cov-report=term
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,6 @@ docs-generated/

# mergetoolfiles
*.orig

# Stray test artifact
PET-test-log
973 changes: 973 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

82 changes: 73 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ at NORCE Norwegian Research Centre AS.
Before installing ensure you have python3 pre-requisites. On a Debian system run:

```
sudo upt-get update
sudo apt-get update
sudo apt-get install python3
sudo apt-get install python3-pip
sudo apt-get install python3-venv
Expand All @@ -41,12 +41,6 @@ python3 -m venv venv-PET
source venv-PET/bin/activate
```

Some additional features might be not part of your default installation and need to be set in the Python (virtual) environment manually:

```
python3 -m pip install wheel
```

If you do not install PET inside a virtual environment,
you may have to include the `--user` option in the following
(to install to your local Python site packages, usually located in `~/.local`).
Expand All @@ -61,6 +55,76 @@ python3 -m pip install -e .
- The `-e` option installs PET such that changes to it take effect immediately
(without re-installation).

To also install the tools needed for running tests and linting locally:

```sh
python3 -m pip install -e ".[dev]"
```

## Documentation

The [configuration reference](docs/configuration.md) lists every key of the
`dataassim`, `ensemble`, `optim` and `simulator` sections; the
[architecture page](docs/architecture.md) explains how a run is put together
and where a new scheme, analysis, localization, optimizer or simulator goes.

## Command-line interface

Installing PET also installs a `pet` command for working with config files:

```sh
pet validate my_config.toml # check a config file for missing/invalid keys
pet convert my_case.pipt # convert a legacy .pipt/.popt file to .toml (or --to yaml)
pet migrate my_config.toml # update a config file to the current schema
pet version # print the installed PET version
```

### Config schema change: `daalg` becomes `scheme`

The analysis flavour is a parameter of an algorithm, not a separate algorithm,
so the two-element `daalg` key has been replaced by a single `scheme` key:

```toml
# before # after
[dataassim] [dataassim]
daalg = ["esmda", "esmda"] scheme = "esmda"
analysis = "approx" analysis = "approx"
```

`pet migrate` performs this rewrite in place, keeping the original as
`<config>.bak`. Use `--dry-run` to preview. Loading a config that still uses
`daalg` raises an error pointing at the command. For a legacy `.pipt`/`.popt`
file, convert first and then migrate:

```sh
pet convert my_case.pipt && pet migrate my_case.toml
```

The same change is reflected in the Python API, where one constructor per
algorithm now takes the flavour as an argument:

```python
from pipt import ESMDA, available_schemes

scheme = ESMDA(cfg_da, cfg_en, sim) # flavour comes from the config's `analysis`
result = scheme.run_assimilation() # the scheme owns its iteration loop

available_schemes() # every valid (scheme, analysis) pair
```

`analysis=` overrides the config when passed. `ESMDA.assimilate(cfg_da, cfg_en,
sim)` is the one-line form for when the scheme object is not needed afterwards;
it returns the same `AssimilationResult`, whose `x` is the posterior ensemble.

The eighteen per-flavour classes this used to produce (`esmda_approx`,
`lmenrml_full`, ...) are gone: each was a one-line subclass pinning the
flavour a constructor argument already expresses. Use `ESMDA(..., analysis=
"approx")` and friends instead.

Running a data-assimilation or optimization job itself is still done from a
Python driver script that wires up your forward simulator/cost function -- see
the tutorials below.

## Examples

PET needs to be set up with a configuration file. See the example [repository](https://github.com/Python-Ensemble-Toolbox/Examples) for inspiration.
Expand All @@ -75,8 +139,8 @@ 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/tutorial_pipt)
- A POPT tutorial is found [here](https://python-ensemble-toolbox.github.io/PET/tutorials/popt/tutorial_popt)
- 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)

## Suggested readings:

Expand Down
134 changes: 134 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Architecture

PET is three layers. `ensemble` is the foundation: the base ensemble that runs
a forward simulator over the members, the checkpoint mixin, the loggers, the
`ForwardSimulator` protocol. `pipt` (data assimilation) and `popt`
(optimisation) build on it and never import each other; `ensemble` imports
neither. `misc` holds the data structures and the observed-data reader,
`input_output` the configuration boundary, `simulator` the analytical models
and the wrappers around external simulators.

## A run

1. **Configuration.** `input_output.read_config.read(file)` returns the
problem, simulator and ensemble sections as plain dictionaries in one
canonical form (`input_output.config.normalize`); `validate` says what a run
would fail on. A dictionary built in a script gets the same treatment when
the ensemble is constructed. See the [configuration reference](configuration.md).
2. **Ensemble.** `pipt.ensembles.AssimilationEnsemble(keys_da, keys_en, sim)`
draws or loads the prior (`(nx, ne)` array; its variable rows are a
`StateLayout`), reads the observations, fixes the **data layout** and
builds the observation vector and variance in that order, and sets up
localization and compression. It owns the random stream (`seed`).
3. **Scheme.** `ESMDA(keys_da, keys_en, sim, analysis="approx")` and the
other schemes build the ensemble (or take one passed as `ensemble=`), bind
an analysis object, and `run_assimilation()`: forecast the prior, then call
`update_step()` until a criterion fires or `maxiter` updates are done.
`ESMDA.assimilate(...)` is the one-line form.
4. **Result.** An `AssimilationResult` (`x`, `data_misfit`,
`prior_data_misfit`, `nit`, `success`, `message`, `why_stop`), a
`dict` subclass with attribute access like SciPy's `OptimizeResult`.

## The scheme contract

`pipt.update_schemes.core.AssimilationScheme` owns the loop, the convergence
checks (`misfit_tol`, `step_tol`, plus the scheme's own `check_convergence`),
the run table, restart, QA/QC and saving. A scheme supplies:

- `update_step() -> StepReport(accepted, state, misfit, why_stop)`: one
iteration, retries included (LM-EnRML re-damps inside it). The loop commits
the returned state and misfit; a scheme never assigns them itself.
- `score()`: the per-member data misfit of the current forecast.
- `log_columns()`: its columns of the run table.
- Hooks: `after_prior_forecast`, `after_analysis`, `after_forecast`,
`after_accepted_iteration`, `after_loop`.
- `COMPATIBLE_ANALYSES`: the analysis flavours it accepts.
- `RESTART_ATTRIBUTES`: the attributes a checkpoint must carry for it.

Registration is one line: `register_scheme(name, analysis, cls)` in
`pipt.update_schemes.registry` (`available_schemes()` lists every pair). The
iterative family shares `IterativeEnRML`, where LM-EnRML and GN-EnRML differ
only in ten small hooks around their control parameter.

## Analyses

An analysis (`pipt.update_schemes.analysis`) is a class with
`update(enX, enY, enE, **kwargs) -> AnalysisResult`, returning exactly one of
a state-space `step`, a weight-space `w_step` or a `W_step`. The scheme turns
it into a proposal with `propose_state(result, step_scale)`. The flavours are
`approx`, `full`, `subspace`, `margis` and the multilevel `hybrid`;
`register_analysis` adds one. Analyses read what they need from the scheme:
`state_scaling`, `scale_data`, `proj`, `cov_data`, `trunc_energy`, `lam`.

## Data on the analysis path

Everything the analyses see is a matrix in one fixed row order:

- `DataLayout` (`misc.structures`): the order of the data vector, computed
once from the observed frame -- label-major, then data type, empty cells
skipped. The ensemble exposes `obs_vector` and `obs_variance` built from it.
- `PredictedData`: the `(nd, ne)` forecast filled directly from each member's
simulator output through the layout, scaled as the observations were, with
compressed vintages reduced on the way in. `pred_data.matrix` is what the
schemes read; `pred_data.to_frame()` is the frame view.
- Adjoints: an `(nd, nx, ne)` array in the same rows, when the simulator
computes them.
- `StateLayout`: the `{variable: (start, stop)}` rows of the state array; the
ensemble's `state_layout` converts to and from dictionaries, builds member
inputs for the simulator, and clips to the prior's limits.

`PETDataFrame` remains as the table observed data arrive in and results are
saved as; it is built from the matrices on demand, never on the analysis path.

## Forecast

`BaseEnsemble.calc_prediction(enX)` runs one level: member inputs
(`_simulator_input`), a backend (`_run_members`: in sequence, a local process
pool, or the wrapper's HPC queue), crash replacement, adjoint splitting, and
the raw outputs kept as `member_outputs`. `ForecastMixin.forecast` then fills
`pred_data`, corrects multilevel levels, applies the `scale` option and saves
what was asked for. Outlier replacement (`OutlierMixin`) reorders the raw
outputs and the state together.

A simulator is anything satisfying `ensemble.protocols.ForwardSimulator`: an
`input_dict` and `run_fwd_sim(state, member_index)` returning one dict per
report point (or a DataFrame), `False` on failure, or `(output, adjoint)`.
`simulator/vanderpol.py` is the smallest complete example.

## Restart, random numbers, logging

- One checkpoint per run, on `RestartMixin` (`ensemble.checkpoint`): the
loop's bookkeeping, the scheme's `RESTART_ATTRIBUTES`, and the ensemble's
state, prior, forecast, scaling and random stream, so a resumed run
continues the interrupted one exactly. Driven by `restart`, `restartsave`,
`restart_file`.
- Every draw comes from `ensemble.rng`: a private `RandomState` when the
config gives a `seed`, otherwise NumPy's global stream as before.
`misc.sampling.gen_real` is the Gaussian sampler.
- One named logger per log file (`ensemble.logger.PetLogger`); `NullLogger`
stands in when logging is off.

## popt

`popt.optimization_methods.OptimizerBase` has the same shape as the scheme
base: it owns the loop, the starting evaluation, the callback, result
recording, the log and the function, state and projected-gradient checks. An
optimizer implements `update_step()`, committing an improving point with
`_commit_step(x, f, jac=..., hess=...)` and returning a `StepReport(accepted,
message)`, and `log_columns()`. `EnOpt`, `LineSearch`, `TrustRegion` and
`SmcOpt` are exported from `popt`, as are the ensembles that estimate
gradients and Hessians (`GaussianEnsemble`, `GeneralizedEnsemble`).

## Where a new piece goes

| Adding | Do |
| --- | --- |
| a scheme | subclass `AssimilationScheme` (or `IterativeEnRML`), implement `update_step`/`score`/`log_columns`, declare `COMPATIBLE_ANALYSES`, `register_scheme` |
| an analysis | subclass `AnalysisBase`, implement `update` returning `AnalysisResult`, `register_analysis` |
| a localization | a builder taking `info` (and `rng`, `data`, ...), `register_localization` |
| an optimizer | subclass `OptimizerBase`, implement `update_step` with `_commit_step`, `log_columns` |
| a simulator | a class with `input_dict` and `run_fwd_sim`; see the protocol's docstring for the optional hooks |
| a config key | read it from the normalised section; add it to `KNOWN_DATAASSIM`/`KNOWN_ENSEMBLE` in `input_output.config` and to the [configuration reference](configuration.md) |

The two notebooks under *Extending PIPT* in the tutorials walk through the
first two.
Loading
Loading