dapper 1.6.0__tar.gz → 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dapper-1.7.0/PKG-INFO +29 -0
- {dapper-1.6.0 → dapper-1.7.0}/README.md +36 -35
- {dapper-1.6.0 → dapper-1.7.0}/dapper/__init__.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/__init__.py +17 -9
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/baseline.py +42 -38
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/ensemble.py +311 -262
- dapper-1.7.0/dapper/da_methods/extended.py +113 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/other.py +56 -46
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/particle.py +157 -150
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/variational.py +117 -103
- {dapper-1.6.0 → dapper-1.7.0}/dapper/dpr_config.py +7 -5
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/DoublePendulum/__init__.py +23 -16
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/DoublePendulum/demo.py +19 -9
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/DoublePendulum/settings101.py +6 -7
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Id/__init__.py +3 -2
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Ikeda/__init__.py +15 -16
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Ikeda/demo.py +8 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Ikeda/some_settings_01.py +8 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/KS/__init__.py +53 -46
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/KS/bocquet2019.py +8 -7
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/KS/compare_schemes.py +14 -15
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/KS/demo.py +13 -13
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LA/__init__.py +20 -20
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LA/demo.py +1 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LA/evensen2009.py +8 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LA/raanes2015.py +19 -16
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LA/small.py +8 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz05/__init__.py +28 -21
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz05/demo.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz05/settings01.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/__init__.py +4 -5
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/anderson2010rhf.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/demo.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/extras.py +9 -11
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/mandel2016.py +9 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/ramgraber2022.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/sakov2012.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/wiljes2017.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz84/__init__.py +6 -7
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz84/demo.py +8 -9
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz84/pajonk2012.py +7 -7
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/__init__.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/anderson2009.py +14 -9
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/bocquet2010.py +4 -4
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/bocquet2010_m40.py +3 -2
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/bocquet2015loc.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/demo.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/extras.py +16 -13
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/frei2013bridging.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/miyoshi2011.py +13 -10
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/pinheiro2019.py +7 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/sakov2008.py +7 -7
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/spantini2019.py +8 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/spectral_obs.py +10 -11
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/todter2015.py +5 -5
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96s/__init__.py +23 -16
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96s/grudzien2020.py +3 -3
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LorenzUV/__init__.py +26 -22
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LorenzUV/demo.py +6 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LorenzUV/illust_LorenzUV.py +54 -44
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LorenzUV/illust_parameterizations.py +47 -37
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LorenzUV/lorenz96.py +11 -11
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LorenzUV/wilks05.py +14 -14
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LotkaVolterra/__init__.py +14 -10
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LotkaVolterra/demo.py +2 -2
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/LotkaVolterra/settings101.py +7 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/__init__.py +62 -40
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/counillon2009.py +3 -3
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/demo.py +12 -10
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/illust_obs.py +8 -8
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/sakov2008.py +12 -12
- dapper-1.7.0/dapper/mods/README.md +94 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/VL20/__init__.py +28 -23
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/VL20/demo.py +4 -3
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/__init__.py +50 -29
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/explore_props.py +90 -80
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/integration.py +2 -2
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/utils.py +26 -15
- {dapper-1.6.0 → dapper-1.7.0}/dapper/stats.py +125 -112
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/chronos.py +78 -58
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/colors.py +26 -20
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/datafiles.py +20 -14
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/linalg.py +5 -5
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/liveplotting.py +389 -347
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/localization.py +54 -46
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/matrices.py +76 -74
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/multiproc.py +15 -6
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/progressbar.py +22 -13
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/randvars.py +38 -36
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/remote/autoscaler.py +131 -91
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/remote/uplink.py +69 -49
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/rounding.py +3 -3
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/seeding.py +6 -4
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/series.py +57 -44
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/viz.py +101 -92
- {dapper-1.6.0 → dapper-1.7.0}/dapper/xp_launch.py +71 -43
- {dapper-1.6.0 → dapper-1.7.0}/dapper/xp_process.py +145 -83
- dapper-1.7.0/dapper.egg-info/PKG-INFO +29 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper.egg-info/requires.txt +7 -12
- {dapper-1.6.0 → dapper-1.7.0}/examples/basic_1.py +6 -8
- {dapper-1.6.0 → dapper-1.7.0}/examples/basic_2.py +9 -1
- dapper-1.7.0/pyproject.toml +133 -0
- {dapper-1.6.0 → dapper-1.7.0}/setup.py +56 -54
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_HMMs.py +3 -3
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_TLMs.py +16 -3
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_data.py +18 -18
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_example_2.py +2 -2
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_iEnKS.py +53 -49
- dapper-1.7.0/tests/test_localization.py +64 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_matrices.py +1 -1
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_plotting.py +14 -15
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_round2.py +49 -55
- dapper-1.6.0/PKG-INFO +0 -83
- dapper-1.6.0/dapper/da_methods/extended.py +0 -114
- dapper-1.6.0/dapper/mods/README.md +0 -110
- dapper-1.6.0/dapper.egg-info/PKG-INFO +0 -83
- dapper-1.6.0/pyproject.toml +0 -143
- dapper-1.6.0/tests/test_localization.py +0 -56
- {dapper-1.6.0 → dapper-1.7.0}/LICENCE.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/README.md +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/da_methods/README.md +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/dpr_config.yaml +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz63/bocquet2012.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz84/harder.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/hoteit2015.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/raanes2016.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/Lorenz96/todter2015_G.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/Makefile +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/README.md +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/__init__.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/calc.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/data.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/helmholtz.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/interface.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/nfw.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/parameters.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_cou09_ens.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_cou09_truth.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_counillon2009_ens.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_counillon2009_truth.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_sak08.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_sakov2008.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_sample_generation.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/prms_test_model.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/qg.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/qgflux.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/qgstep.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/f90/utils.f90 +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/mods/QG/governing_eqn.png +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/__init__.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/remote/README.md +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper/tools/remote/__init__.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper.egg-info/SOURCES.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper.egg-info/dependency_links.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/dapper.egg-info/top_level.txt +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/setup.cfg +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/__init__.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_demos.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_operator.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_printing.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_randvars.py +0 -0
- {dapper-1.6.0 → dapper-1.7.0}/tests/test_rng.py +0 -0
dapper-1.7.0/PKG-INFO
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dapper
|
|
3
|
+
Version: 1.7.0
|
|
4
|
+
Summary: DAPPER benchmarks the performance of data assimilation (DA) methods.
|
|
5
|
+
Author: Patrick N. Raanes
|
|
6
|
+
Author-email: patrick.n.raanes@gmail.com
|
|
7
|
+
Project-URL: Documentation, https://nansencenter.github.io/DAPPER/
|
|
8
|
+
Project-URL: Source, https://github.com/nansencenter/DAPPER
|
|
9
|
+
Project-URL: Tracker, https://github.com/nansencenter/DAPPER/issues
|
|
10
|
+
Keywords: data-assimilation enkf kalman-filtering state-estimation particle-filter kalman bayesian-methods bayesian-filter chaos
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Provides-Extra: Qt
|
|
20
|
+
Provides-Extra: debug
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Provides-Extra: lint
|
|
23
|
+
Provides-Extra: build
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
License-File: LICENCE.txt
|
|
26
|
+
|
|
27
|
+
It is usually best to install from source (github),
|
|
28
|
+
so that you the code is readily available to play with.
|
|
29
|
+
See full README on [github](https://github.com/nansencenter/DAPPER).
|
|
@@ -28,19 +28,18 @@ and then estimate that truth given the models and noisy observations.
|
|
|
28
28
|
|
|
29
29
|
[Install](#installation), then
|
|
30
30
|
read, run and try to understand `examples/basic_{1,2,3}.py`.
|
|
31
|
-
Some of the examples
|
|
32
|
-
|
|
31
|
+
Some of the examples also exist as Jupyter notebooks, and can be run in the cloud
|
|
32
|
+
*without installation* (but requiring Google login): [](http://colab.research.google.com/github/nansencenter/DAPPER).
|
|
33
33
|
This [screencast](https://www.youtube.com/watch?v=YtalK0Zkzvg&t=6475s)
|
|
34
|
-
provides an
|
|
34
|
+
provides an overview to DAPPER.
|
|
35
35
|
The [documentation](https://nansencenter.github.io/DAPPER)
|
|
36
|
-
includes general guidelines and the API,
|
|
37
|
-
but
|
|
38
|
-
If
|
|
36
|
+
includes general guidelines and the API reference,
|
|
37
|
+
but most users must expect to read the code as well.
|
|
38
|
+
If used towards a publication, please cite as
|
|
39
39
|
*The experiments used (inspiration from) DAPPER [ref], version 1.6.0*,
|
|
40
|
-
where [ref] points to [](https://doi.org/10.21105/joss.05150).
|
|
41
|
+
Also see the interactive [tutorials on DA theory](https://github.com/nansencenter/DA-tutorials)
|
|
42
|
+
with Python.
|
|
44
43
|
|
|
45
44
|
## Highlights
|
|
46
45
|
|
|
@@ -50,26 +49,30 @@ through a variety of typical [test cases](#test-cases-models) and statistics. It
|
|
|
50
49
|
(b) facilitates comparative studies, thus promoting the
|
|
51
50
|
(a) reliability and
|
|
52
51
|
(b) relevance of the results.
|
|
53
|
-
For example,
|
|
54
|
-
making use of built-in tools for experiment and result management,
|
|
52
|
+
For example, the figure below is generated by `examples/basic_3.py`,
|
|
55
53
|
reproduces figure 5.7 of [these lecture notes](http://cerea.enpc.fr/HomePages/bocquet/teaching/assim-mb-en.pdf).
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
DAPPER is
|
|
55
|
+
(c) open source, written in Python, and
|
|
56
|
+
(d) focuses on readability;
|
|
57
|
+
this promotes the
|
|
58
|
+
(c) reproduction and
|
|
59
|
+
(d) dissemination of the underlying science,
|
|
61
60
|
and makes it easy to adapt and extend.
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
DAPPER demonstrates how to parallelise ensemble forecasts (e.g., the QG model),
|
|
65
|
+
local analyses (e.g., the LETKF), and independent experiments (e.g., `examples/basic_3.py`).
|
|
66
|
+
It includes a battery of diagnostics and statistics,
|
|
67
|
+
which all get averaged over subdomains (e.g., "ocean" and "land") and then in time.
|
|
67
68
|
Confidence intervals are computed, including correction for auto-correlations,
|
|
68
69
|
and used for uncertainty quantification, and significant digits printing.
|
|
69
70
|
Several diagnostics are included in the on-line "liveplotting" illustrated below,
|
|
70
71
|
which may be paused for further interactive inspection.
|
|
72
|
+
In summary, DAPPER is well suited for teaching and fundamental DA research.
|
|
73
|
+
Also see its [drawbacks](#similar-projects).
|
|
71
74
|
|
|
72
|
-

|
|
73
76
|
|
|
74
77
|
<!-- Non-highlighted features:
|
|
75
78
|
- Time sequences use via `tools.chronos.Chronology` and `tools.chronos.Ticker`.
|
|
@@ -79,12 +82,9 @@ which may be paused for further interactive inspection.
|
|
|
79
82
|
provides input flexibility/overloading,
|
|
80
83
|
lazy eval that facilitates the use of non-diagonal
|
|
81
84
|
covariance matrices (whether sparse or full).
|
|
85
|
+
- built-in tools for experiment and result management,
|
|
82
86
|
-->
|
|
83
87
|
|
|
84
|
-
In summary, DAPPER is well suited for teaching and fundamental DA research.
|
|
85
|
-
Also see its [drawbacks](#similar-projects).
|
|
86
|
-
|
|
87
|
-
|
|
88
88
|
## Installation
|
|
89
89
|
|
|
90
90
|
Successfully tested on Linux/Mac/Windows.
|
|
@@ -98,12 +98,12 @@ open the [Anaconda terminal](https://docs.conda.io/projects/conda/en/latest/user
|
|
|
98
98
|
and run the following commands:
|
|
99
99
|
|
|
100
100
|
```sh
|
|
101
|
-
conda create --yes --name dapper-env python=3.
|
|
101
|
+
conda create --yes --name dapper-env python=3.12
|
|
102
102
|
conda activate dapper-env
|
|
103
103
|
python --version
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
Ensure the printed version is
|
|
106
|
+
Ensure the printed version is as desired.
|
|
107
107
|
*Keep using the same terminal for the commands below.*
|
|
108
108
|
|
|
109
109
|
### Install
|
|
@@ -114,19 +114,17 @@ Ensure the printed version is 3.9 or more.
|
|
|
114
114
|
|
|
115
115
|
- Download and unzip (or `git clone`) DAPPER.
|
|
116
116
|
- Move the resulting folder wherever you like,
|
|
117
|
-
and `cd` into it
|
|
118
|
-
|
|
119
|
-
- `pip install -e '.[dev]'`
|
|
120
|
-
You can omit `[dev]` if you don't need to do serious development.
|
|
117
|
+
and `cd` into it *(ensure you're in the folder with a `setup.py` file)*.
|
|
118
|
+
- `pip install -e '.'`
|
|
121
119
|
|
|
122
120
|
#### *Or*: Install as library
|
|
123
121
|
|
|
124
122
|
*Do you just want to run a script that requires DAPPER?* Then
|
|
125
123
|
|
|
126
|
-
- If the script comes with a `requirements.txt` file, then do
|
|
124
|
+
- If the script comes with a `requirements.txt` file that lists DAPPER, then do
|
|
127
125
|
`pip install -r path/to/requirements.txt`.
|
|
128
126
|
- If not, hopefully you know the version of DAPPER needed. Run
|
|
129
|
-
`pip install dapper==1.
|
|
127
|
+
`pip install dapper==1.6.0` to get version `1.6.0` (as an example).
|
|
130
128
|
|
|
131
129
|
#### *Finally*: Test the installation
|
|
132
130
|
|
|
@@ -174,7 +172,7 @@ The particle filter is tuned with "effective-N monitoring",
|
|
|
174
172
|
"regularization/jittering" strength, and more.
|
|
175
173
|
|
|
176
174
|
For a list of ready-made experiments with suitable,
|
|
177
|
-
tuned settings for a given method (e.g
|
|
175
|
+
tuned settings for a given method (e.g., the `iEnKS`), use:
|
|
178
176
|
|
|
179
177
|
```sh
|
|
180
178
|
grep -r "xp.*iEnKS" dapper/mods
|
|
@@ -183,6 +181,9 @@ grep -r "xp.*iEnKS" dapper/mods
|
|
|
183
181
|
|
|
184
182
|
## Test cases (models)
|
|
185
183
|
|
|
184
|
+
Simple models facilitate the reliability, reproducibility,
|
|
185
|
+
and interpretability of experiment results.
|
|
186
|
+
|
|
186
187
|
Model | Lin | TLM** | PDE? | Phys.dim. | State len | Lyap≥0 | Implementer
|
|
187
188
|
----------- | --- | ----- | ---- | --------- | --------- | ------ | ----------
|
|
188
189
|
Id | Yes | Yes | No | N/A | * | 0 | Raanes
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
.. include:: ./README.md
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
|
|
@@ -82,7 +83,7 @@ def da_method(*default_dataclasses):
|
|
|
82
83
|
def set_field(name, type_, val):
|
|
83
84
|
"""Set the inherited (i.e. default, i.e. has value) field."""
|
|
84
85
|
# Ensure annotations
|
|
85
|
-
cls.__annotations__ = getattr(cls,
|
|
86
|
+
cls.__annotations__ = getattr(cls, "__annotations__", {})
|
|
86
87
|
# Set annotation
|
|
87
88
|
cls.__annotations__[name] = type_
|
|
88
89
|
# Set value
|
|
@@ -102,7 +103,7 @@ def da_method(*default_dataclasses):
|
|
|
102
103
|
# Define the new assimilate method (has bells and whistles)
|
|
103
104
|
def assimilate(self, HMM, xx, yy, desc=None, fail_gently=False, **stat_kwargs):
|
|
104
105
|
# Progressbar name
|
|
105
|
-
pb_name_hook = self.da_method if desc is None else desc
|
|
106
|
+
pb_name_hook = self.da_method if desc is None else desc # noqa
|
|
106
107
|
|
|
107
108
|
# Init stats
|
|
108
109
|
self.stats = dapper.stats.Stats(self, HMM, xx, yy, **stat_kwargs)
|
|
@@ -120,7 +121,7 @@ def da_method(*default_dataclasses):
|
|
|
120
121
|
# Don't use _print_cropped_traceback here -- It would
|
|
121
122
|
# crop out errors in the DAPPER infrastructure itself.
|
|
122
123
|
raise
|
|
123
|
-
self.stat("duration", time.time()-time0)
|
|
124
|
+
self.stat("duration", time.time() - time0)
|
|
124
125
|
|
|
125
126
|
# Overwrite the assimilate method with the new one
|
|
126
127
|
try:
|
|
@@ -128,12 +129,14 @@ def da_method(*default_dataclasses):
|
|
|
128
129
|
except AttributeError as error:
|
|
129
130
|
raise AttributeError(
|
|
130
131
|
"Classes decorated by da_method()"
|
|
131
|
-
" must define a method called 'assimilate'."
|
|
132
|
+
" must define a method called 'assimilate'."
|
|
133
|
+
) from error
|
|
132
134
|
cls.assimilate = functools.wraps(_assimilate)(assimilate)
|
|
133
135
|
|
|
134
136
|
# Shortcut for register_stat
|
|
135
137
|
def stat(self, name, value):
|
|
136
138
|
dapper.stats.register_stat(self.stats, name, value)
|
|
139
|
+
|
|
137
140
|
cls.stat = stat
|
|
138
141
|
|
|
139
142
|
# Make self.__class__.__name__ an attrib.
|
|
@@ -141,6 +144,7 @@ def da_method(*default_dataclasses):
|
|
|
141
144
|
cls.da_method = cls.__name__
|
|
142
145
|
|
|
143
146
|
return cls
|
|
147
|
+
|
|
144
148
|
return dataclass_with_defaults
|
|
145
149
|
|
|
146
150
|
|
|
@@ -155,15 +159,17 @@ def _print_cropped_traceback(ERR):
|
|
|
155
159
|
msg = "Traceback (most recent call last):\n"
|
|
156
160
|
try:
|
|
157
161
|
# If in IPython, use its coloring functionality
|
|
158
|
-
__IPYTHON__ # type: ignore
|
|
162
|
+
__IPYTHON__ # type: ignore # noqa: B018
|
|
159
163
|
except (NameError, ImportError):
|
|
160
164
|
msg += "".join(traceback.format_tb(ERR.__traceback__))
|
|
161
165
|
else:
|
|
162
166
|
from IPython.core.debugger import Pdb
|
|
167
|
+
|
|
163
168
|
pdb_instance = Pdb()
|
|
164
169
|
pdb_instance.curframe = inspect.currentframe()
|
|
165
170
|
|
|
166
171
|
import dapper.da_methods
|
|
172
|
+
|
|
167
173
|
keep = False
|
|
168
174
|
for frame in traceback.walk_tb(ERR.__traceback__):
|
|
169
175
|
if keep:
|
|
@@ -175,10 +181,12 @@ def _print_cropped_traceback(ERR):
|
|
|
175
181
|
return msg
|
|
176
182
|
|
|
177
183
|
msg = crop_traceback(ERR) + "\nError message: " + str(ERR)
|
|
178
|
-
msg += (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
msg += (
|
|
185
|
+
"\n\nResuming execution."
|
|
186
|
+
"\nIf instead you wish to raise the exceptions as usual,"
|
|
187
|
+
"\nwhich will halt the execution (and enable post-mortem debug),"
|
|
188
|
+
"\nthen use `fail_gently=False`"
|
|
189
|
+
)
|
|
182
190
|
print(msg, file=sys.stderr)
|
|
183
191
|
|
|
184
192
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Many are based on `bib.raanes2016thesis`.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from typing import Callable, Optional
|
|
6
7
|
|
|
7
8
|
import numpy as np
|
|
@@ -25,14 +26,14 @@ class Climatology:
|
|
|
25
26
|
|
|
26
27
|
def assimilate(self, HMM, xx, yy):
|
|
27
28
|
muC = np.mean(xx, 0)
|
|
28
|
-
AC
|
|
29
|
-
PC
|
|
29
|
+
AC = xx - muC
|
|
30
|
+
PC = CovMat(AC, "A")
|
|
30
31
|
|
|
31
32
|
self.stats.assess(0, mu=muC, Cov=PC)
|
|
32
33
|
self.stats.trHK[:] = 0
|
|
33
34
|
|
|
34
35
|
for k, ko, _, _ in progbar(HMM.tseq.ticker):
|
|
35
|
-
fau =
|
|
36
|
+
fau = "u" if ko is None else "fau"
|
|
36
37
|
self.stats.assess(k, ko, fau, mu=muC, Cov=PC)
|
|
37
38
|
|
|
38
39
|
|
|
@@ -49,13 +50,13 @@ class OptInterp:
|
|
|
49
50
|
|
|
50
51
|
# Compute "climatological" Kalman gain
|
|
51
52
|
muC = np.mean(xx, 0)
|
|
52
|
-
AC
|
|
53
|
-
PC
|
|
53
|
+
AC = xx - muC
|
|
54
|
+
PC = (AC.T @ AC) / (xx.shape[0] - 1)
|
|
54
55
|
|
|
55
56
|
# Setup scalar "time-series" covariance dynamics.
|
|
56
57
|
# ONLY USED FOR DIAGNOSTICS, not to affect the Kalman gain.
|
|
57
|
-
L
|
|
58
|
-
SM = fit_sigmoid(1/2, L, 0)
|
|
58
|
+
L = series.estimate_corr_length(AC.ravel(order="F"))
|
|
59
|
+
SM = fit_sigmoid(1 / 2, L, 0)
|
|
59
60
|
|
|
60
61
|
# Init
|
|
61
62
|
mu = muC
|
|
@@ -63,19 +64,19 @@ class OptInterp:
|
|
|
63
64
|
|
|
64
65
|
for k, ko, t, dt in progbar(HMM.tseq.ticker):
|
|
65
66
|
# Forecast
|
|
66
|
-
mu = HMM.Dyn(mu, t-dt, dt)
|
|
67
|
+
mu = HMM.Dyn(mu, t - dt, dt)
|
|
67
68
|
if ko is not None:
|
|
68
|
-
self.stats.assess(k, ko,
|
|
69
|
+
self.stats.assess(k, ko, "f", mu=muC, Cov=PC)
|
|
69
70
|
|
|
70
71
|
# Analysis
|
|
71
|
-
H
|
|
72
|
-
KG
|
|
73
|
-
mu = muC + KG@(yy[ko] - HMM.Obs(ko)(muC))
|
|
72
|
+
H = HMM.Obs(ko).linear(muC)
|
|
73
|
+
KG = mrdiv(PC @ H.T, H @ PC @ H.T + HMM.Obs(ko).noise.C.full)
|
|
74
|
+
mu = muC + KG @ (yy[ko] - HMM.Obs(ko)(muC))
|
|
74
75
|
|
|
75
|
-
P
|
|
76
|
-
SM = fit_sigmoid(P.trace()/PC.trace(), L, k)
|
|
76
|
+
P = (Id - KG @ H) @ PC
|
|
77
|
+
SM = fit_sigmoid(P.trace() / PC.trace(), L, k)
|
|
77
78
|
|
|
78
|
-
self.stats.assess(k, ko, mu=mu, Cov=2*PC*SM(k))
|
|
79
|
+
self.stats.assess(k, ko, mu=mu, Cov=2 * PC * SM(k))
|
|
79
80
|
|
|
80
81
|
|
|
81
82
|
@da_method()
|
|
@@ -88,27 +89,27 @@ class Var3D:
|
|
|
88
89
|
"""
|
|
89
90
|
|
|
90
91
|
B: Optional[np.ndarray] = None
|
|
91
|
-
xB: float
|
|
92
|
+
xB: float = 1.0
|
|
92
93
|
|
|
93
94
|
def assimilate(self, HMM, xx, yy):
|
|
94
95
|
Id = np.eye(HMM.Nx)
|
|
95
96
|
if isinstance(self.B, np.ndarray):
|
|
96
97
|
# compare ndarray 1st to avoid == error for ndarray
|
|
97
98
|
B = self.B.astype(float)
|
|
98
|
-
elif self.B in (None,
|
|
99
|
+
elif self.B in (None, "clim"):
|
|
99
100
|
# Use climatological cov, estimated from truth
|
|
100
101
|
B = np.cov(xx.T)
|
|
101
|
-
elif self.B ==
|
|
102
|
+
elif self.B == "eye":
|
|
102
103
|
B = Id
|
|
103
104
|
else:
|
|
104
105
|
raise ValueError("Bad input B.")
|
|
105
106
|
B *= self.xB
|
|
106
107
|
|
|
107
108
|
# ONLY USED FOR DIAGNOSTICS, not to change the Kalman gain.
|
|
108
|
-
CC = 2*np.cov(xx.T)
|
|
109
|
-
L
|
|
110
|
-
P
|
|
111
|
-
SM = fit_sigmoid(P.trace()/CC.trace(), L, 0)
|
|
109
|
+
CC = 2 * np.cov(xx.T)
|
|
110
|
+
L = series.estimate_corr_length(center(xx)[0].ravel(order="F"))
|
|
111
|
+
P = HMM.X0.C.full
|
|
112
|
+
SM = fit_sigmoid(P.trace() / CC.trace(), L, 0)
|
|
112
113
|
|
|
113
114
|
# Init
|
|
114
115
|
mu = HMM.X0.mu
|
|
@@ -116,20 +117,20 @@ class Var3D:
|
|
|
116
117
|
|
|
117
118
|
for k, ko, t, dt in progbar(HMM.tseq.ticker):
|
|
118
119
|
# Forecast
|
|
119
|
-
mu = HMM.Dyn(mu, t-dt, dt)
|
|
120
|
-
P
|
|
120
|
+
mu = HMM.Dyn(mu, t - dt, dt)
|
|
121
|
+
P = CC * SM(k)
|
|
121
122
|
|
|
122
123
|
if ko is not None:
|
|
123
|
-
self.stats.assess(k, ko,
|
|
124
|
+
self.stats.assess(k, ko, "f", mu=mu, Cov=P)
|
|
124
125
|
|
|
125
126
|
# Analysis
|
|
126
|
-
H
|
|
127
|
-
KG = mrdiv(B@H.T, H@B@H.T + HMM.Obs(ko).noise.C.full)
|
|
128
|
-
mu = mu + KG@(yy[ko] - HMM.Obs(ko)(mu))
|
|
127
|
+
H = HMM.Obs(ko).linear(mu)
|
|
128
|
+
KG = mrdiv(B @ H.T, H @ B @ H.T + HMM.Obs(ko).noise.C.full)
|
|
129
|
+
mu = mu + KG @ (yy[ko] - HMM.Obs(ko)(mu))
|
|
129
130
|
|
|
130
131
|
# Re-calibrate fit_sigmoid with new W0 = Pa/B
|
|
131
|
-
P = (Id - KG@H) @ B
|
|
132
|
-
SM = fit_sigmoid(P.trace()/CC.trace(), L, k)
|
|
132
|
+
P = (Id - KG @ H) @ B
|
|
133
|
+
SM = fit_sigmoid(P.trace() / CC.trace(), L, k)
|
|
133
134
|
|
|
134
135
|
self.stats.assess(k, ko, mu=mu, Cov=P)
|
|
135
136
|
|
|
@@ -151,14 +152,17 @@ def fit_sigmoid(Sb, L, kb):
|
|
|
151
152
|
- `b` to match values of `S(kb)` and `Sb`
|
|
152
153
|
"""
|
|
153
154
|
|
|
154
|
-
def sigmoid(k):
|
|
155
|
-
|
|
155
|
+
def sigmoid(k):
|
|
156
|
+
return 1 / (1 + np.exp(-k)) # normalized sigmoid
|
|
157
|
+
|
|
158
|
+
def inv_sig(s):
|
|
159
|
+
return np.log(s / (1 - s)) # its inverse
|
|
156
160
|
|
|
157
|
-
a = 1/L
|
|
161
|
+
a = 1 / L
|
|
158
162
|
b = inv_sig(Sb)
|
|
159
163
|
|
|
160
164
|
def S(k):
|
|
161
|
-
return sigmoid(b + a*(k-kb))
|
|
165
|
+
return sigmoid(b + a * (k - kb))
|
|
162
166
|
|
|
163
167
|
return S
|
|
164
168
|
|
|
@@ -176,9 +180,9 @@ class Persistence:
|
|
|
176
180
|
prev = xx[0]
|
|
177
181
|
self.stats.assess(0, mu=prev)
|
|
178
182
|
for k, ko, _t, _dt in progbar(HMM.tseq.ticker):
|
|
179
|
-
self.stats.assess(k, ko,
|
|
183
|
+
self.stats.assess(k, ko, "fu", mu=xx[k - 1])
|
|
180
184
|
if ko is not None:
|
|
181
|
-
self.stats.assess(k, ko,
|
|
185
|
+
self.stats.assess(k, ko, "a", mu=prev)
|
|
182
186
|
prev = xx[k]
|
|
183
187
|
|
|
184
188
|
|
|
@@ -196,6 +200,6 @@ class PreProg:
|
|
|
196
200
|
def assimilate(self, HMM, xx, yy):
|
|
197
201
|
self.stats.assess(0, mu=self.schedule(0, xx, yy))
|
|
198
202
|
for k, ko, _t, _dt in progbar(HMM.tseq.ticker):
|
|
199
|
-
self.stats.assess(k, ko,
|
|
203
|
+
self.stats.assess(k, ko, "fu", mu=self.schedule(k, xx, yy))
|
|
200
204
|
if ko is not None:
|
|
201
|
-
self.stats.assess(k, ko,
|
|
205
|
+
self.stats.assess(k, ko, "a", mu=self.schedule(k, xx, yy))
|