dapper 1.5.1__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.5.1 → dapper-1.7.0}/PKG-INFO +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/README.md +59 -45
- {dapper-1.5.1 → dapper-1.7.0}/dapper/README.md +4 -4
- {dapper-1.5.1 → dapper-1.7.0}/dapper/__init__.py +2 -2
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/README.md +2 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/__init__.py +17 -9
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/baseline.py +42 -38
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/ensemble.py +320 -268
- dapper-1.7.0/dapper/da_methods/extended.py +113 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/other.py +63 -54
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/particle.py +179 -166
- {dapper-1.5.1 → dapper-1.7.0}/dapper/da_methods/variational.py +127 -110
- {dapper-1.5.1 → dapper-1.7.0}/dapper/dpr_config.py +7 -5
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/DoublePendulum/__init__.py +23 -16
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/DoublePendulum/demo.py +19 -9
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/DoublePendulum/settings101.py +6 -7
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Id/__init__.py +3 -2
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Ikeda/__init__.py +15 -16
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Ikeda/demo.py +8 -8
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Ikeda/some_settings_01.py +8 -8
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/KS/__init__.py +53 -46
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/KS/bocquet2019.py +8 -7
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/KS/compare_schemes.py +14 -15
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/KS/demo.py +13 -13
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LA/__init__.py +22 -20
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LA/demo.py +1 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LA/evensen2009.py +8 -8
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LA/raanes2015.py +19 -16
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LA/small.py +8 -8
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz05/__init__.py +28 -21
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz05/demo.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz05/settings01.py +6 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/__init__.py +4 -5
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/anderson2010rhf.py +6 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/bocquet2012.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/demo.py +6 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/extras.py +9 -11
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/mandel2016.py +9 -6
- dapper-1.7.0/dapper/mods/Lorenz63/ramgraber2022.py +37 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/sakov2012.py +6 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz63/wiljes2017.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz84/__init__.py +6 -7
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz84/demo.py +8 -9
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz84/pajonk2012.py +7 -7
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/__init__.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/anderson2009.py +14 -9
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/bocquet2010.py +4 -4
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/bocquet2010_m40.py +3 -2
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/bocquet2015loc.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/demo.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/extras.py +16 -13
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/frei2013bridging.py +6 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/miyoshi2011.py +13 -10
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/pinheiro2019.py +7 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/sakov2008.py +7 -7
- dapper-1.7.0/dapper/mods/Lorenz96/spantini2019.py +41 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/spectral_obs.py +10 -11
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/todter2015.py +5 -5
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/todter2015_G.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96s/__init__.py +25 -17
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96s/grudzien2020.py +3 -3
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LorenzUV/__init__.py +26 -22
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LorenzUV/demo.py +6 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LorenzUV/illust_LorenzUV.py +54 -44
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LorenzUV/illust_parameterizations.py +47 -37
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LorenzUV/lorenz96.py +11 -11
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LorenzUV/wilks05.py +14 -14
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LotkaVolterra/__init__.py +14 -10
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LotkaVolterra/demo.py +2 -2
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/LotkaVolterra/settings101.py +7 -8
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/__init__.py +63 -41
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/counillon2009.py +3 -3
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/demo.py +12 -10
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/README.md +36 -32
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/illust_obs.py +8 -8
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/sakov2008.py +41 -34
- dapper-1.7.0/dapper/mods/README.md +94 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/VL20/__init__.py +28 -23
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/VL20/demo.py +4 -3
- dapper-1.7.0/dapper/mods/__init__.py +258 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/explore_props.py +90 -80
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/integration.py +4 -3
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/utils.py +26 -15
- {dapper-1.5.1 → dapper-1.7.0}/dapper/stats.py +126 -115
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/chronos.py +78 -58
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/colors.py +26 -20
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/datafiles.py +21 -15
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/linalg.py +5 -5
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/liveplotting.py +434 -383
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/localization.py +59 -61
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/matrices.py +87 -76
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/multiproc.py +15 -6
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/progressbar.py +22 -13
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/randvars.py +47 -45
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/remote/README.md +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/remote/autoscaler.py +131 -91
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/remote/uplink.py +69 -49
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/rounding.py +3 -3
- dapper-1.7.0/dapper/tools/seeding.py +31 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/series.py +57 -44
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/viz.py +101 -92
- {dapper-1.5.1 → dapper-1.7.0}/dapper/xp_launch.py +71 -43
- {dapper-1.5.1 → dapper-1.7.0}/dapper/xp_process.py +145 -83
- {dapper-1.5.1 → dapper-1.7.0}/dapper.egg-info/PKG-INFO +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/dapper.egg-info/SOURCES.txt +3 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper.egg-info/requires.txt +7 -12
- {dapper-1.5.1 → dapper-1.7.0}/examples/basic_1.py +8 -10
- {dapper-1.5.1 → dapper-1.7.0}/examples/basic_2.py +11 -3
- dapper-1.7.0/pyproject.toml +133 -0
- {dapper-1.5.1 → dapper-1.7.0}/setup.py +56 -55
- dapper-1.7.0/tests/test_HMMs.py +58 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_TLMs.py +16 -3
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_data.py +18 -18
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_example_2.py +44 -39
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_iEnKS.py +53 -49
- dapper-1.7.0/tests/test_localization.py +64 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_matrices.py +1 -1
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_plotting.py +14 -15
- dapper-1.7.0/tests/test_rng.py +22 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_round2.py +49 -55
- dapper-1.5.1/dapper/da_methods/extended.py +0 -114
- dapper-1.5.1/dapper/mods/README.md +0 -110
- dapper-1.5.1/dapper/mods/__init__.py +0 -200
- dapper-1.5.1/dapper/tools/seeding.py +0 -68
- dapper-1.5.1/pyproject.toml +0 -143
- dapper-1.5.1/tests/test_HMMs.py +0 -59
- dapper-1.5.1/tests/test_localization.py +0 -56
- {dapper-1.5.1 → dapper-1.7.0}/LICENCE.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/dpr_config.yaml +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz84/harder.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/hoteit2015.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/Lorenz96/raanes2016.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/Makefile +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/__init__.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/calc.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/data.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/helmholtz.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/interface.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/nfw.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/parameters.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_cou09_ens.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_cou09_truth.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_counillon2009_ens.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_counillon2009_truth.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_sak08.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_sakov2008.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_sample_generation.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/prms_test_model.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/qg.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/qgflux.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/qgstep.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/f90/utils.f90 +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/mods/QG/governing_eqn.png +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/__init__.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper/tools/remote/__init__.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper.egg-info/dependency_links.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/dapper.egg-info/top_level.txt +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/setup.cfg +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/__init__.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_demos.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_operator.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_printing.py +0 -0
- {dapper-1.5.1 → dapper-1.7.0}/tests/test_randvars.py +0 -0
|
@@ -10,10 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
<img src="/docs/imgs/logo_wtxt.png" align="left" width="250"/>
|
|
12
12
|
|
|
13
|
-
DAPPER is a set of templates for **benchmarking** the performance of
|
|
14
|
-
|
|
15
|
-
The tests provide experimental support and guidance for
|
|
16
|
-
new developments in DA.
|
|
13
|
+
DAPPER is a set of templates for **benchmarking** the performance of **data assimilation** (DA) methods.
|
|
14
|
+
The numerical experiments provide support and guidance for new developments in DA.
|
|
17
15
|
The typical set-up is a **synthetic (twin) experiment**, where you
|
|
18
16
|
specify a dynamic model and an observational model,
|
|
19
17
|
and use these to generate a synthetic truth (multivariate time series),
|
|
@@ -30,19 +28,18 @@ and then estimate that truth given the models and noisy observations.
|
|
|
30
28
|
|
|
31
29
|
[Install](#installation), then
|
|
32
30
|
read, run and try to understand `examples/basic_{1,2,3}.py`.
|
|
33
|
-
Some of the examples
|
|
34
|
-
|
|
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).
|
|
35
33
|
This [screencast](https://www.youtube.com/watch?v=YtalK0Zkzvg&t=6475s)
|
|
36
|
-
provides an
|
|
34
|
+
provides an overview to DAPPER.
|
|
37
35
|
The [documentation](https://nansencenter.github.io/DAPPER)
|
|
38
|
-
includes general guidelines and the API,
|
|
39
|
-
but
|
|
40
|
-
If
|
|
41
|
-
*The experiments used (inspiration from) DAPPER [ref], version 1.
|
|
42
|
-
where [ref] points to [ DAPPER [ref], version 1.6.0*,
|
|
40
|
+
or similar, 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.
|
|
46
43
|
|
|
47
44
|
## Highlights
|
|
48
45
|
|
|
@@ -52,26 +49,30 @@ through a variety of typical [test cases](#test-cases-models) and statistics. It
|
|
|
52
49
|
(b) facilitates comparative studies, thus promoting the
|
|
53
50
|
(a) reliability and
|
|
54
51
|
(b) relevance of the results.
|
|
55
|
-
For example,
|
|
56
|
-
making use of built-in tools for experiment and result management,
|
|
52
|
+
For example, the figure below is generated by `examples/basic_3.py`,
|
|
57
53
|
reproduces figure 5.7 of [these lecture notes](http://cerea.enpc.fr/HomePages/bocquet/teaching/assim-mb-en.pdf).
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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,
|
|
63
60
|
and makes it easy to adapt and extend.
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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.
|
|
69
68
|
Confidence intervals are computed, including correction for auto-correlations,
|
|
70
69
|
and used for uncertainty quantification, and significant digits printing.
|
|
71
70
|
Several diagnostics are included in the on-line "liveplotting" illustrated below,
|
|
72
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).
|
|
73
74
|
|
|
74
|
-

|
|
75
76
|
|
|
76
77
|
<!-- Non-highlighted features:
|
|
77
78
|
- Time sequences use via `tools.chronos.Chronology` and `tools.chronos.Ticker`.
|
|
@@ -81,12 +82,9 @@ which may be paused for further interactive inspection.
|
|
|
81
82
|
provides input flexibility/overloading,
|
|
82
83
|
lazy eval that facilitates the use of non-diagonal
|
|
83
84
|
covariance matrices (whether sparse or full).
|
|
85
|
+
- built-in tools for experiment and result management,
|
|
84
86
|
-->
|
|
85
87
|
|
|
86
|
-
In summary, DAPPER is well suited for teaching and fundamental DA research.
|
|
87
|
-
Also see its [drawbacks](#similar-projects).
|
|
88
|
-
|
|
89
|
-
|
|
90
88
|
## Installation
|
|
91
89
|
|
|
92
90
|
Successfully tested on Linux/Mac/Windows.
|
|
@@ -100,12 +98,12 @@ open the [Anaconda terminal](https://docs.conda.io/projects/conda/en/latest/user
|
|
|
100
98
|
and run the following commands:
|
|
101
99
|
|
|
102
100
|
```sh
|
|
103
|
-
conda create --yes --name dapper-env python=3.
|
|
101
|
+
conda create --yes --name dapper-env python=3.12
|
|
104
102
|
conda activate dapper-env
|
|
105
103
|
python --version
|
|
106
104
|
```
|
|
107
105
|
|
|
108
|
-
Ensure the printed version is
|
|
106
|
+
Ensure the printed version is as desired.
|
|
109
107
|
*Keep using the same terminal for the commands below.*
|
|
110
108
|
|
|
111
109
|
### Install
|
|
@@ -116,19 +114,17 @@ Ensure the printed version is 3.9 or more.
|
|
|
116
114
|
|
|
117
115
|
- Download and unzip (or `git clone`) DAPPER.
|
|
118
116
|
- Move the resulting folder wherever you like,
|
|
119
|
-
and `cd` into it
|
|
120
|
-
|
|
121
|
-
- `pip install -e '.[dev]'`
|
|
122
|
-
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 '.'`
|
|
123
119
|
|
|
124
120
|
#### *Or*: Install as library
|
|
125
121
|
|
|
126
122
|
*Do you just want to run a script that requires DAPPER?* Then
|
|
127
123
|
|
|
128
|
-
- 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
|
|
129
125
|
`pip install -r path/to/requirements.txt`.
|
|
130
126
|
- If not, hopefully you know the version of DAPPER needed. Run
|
|
131
|
-
`pip install dapper==1.
|
|
127
|
+
`pip install dapper==1.6.0` to get version `1.6.0` (as an example).
|
|
132
128
|
|
|
133
129
|
#### *Finally*: Test the installation
|
|
134
130
|
|
|
@@ -176,7 +172,7 @@ The particle filter is tuned with "effective-N monitoring",
|
|
|
176
172
|
"regularization/jittering" strength, and more.
|
|
177
173
|
|
|
178
174
|
For a list of ready-made experiments with suitable,
|
|
179
|
-
tuned settings for a given method (e.g
|
|
175
|
+
tuned settings for a given method (e.g., the `iEnKS`), use:
|
|
180
176
|
|
|
181
177
|
```sh
|
|
182
178
|
grep -r "xp.*iEnKS" dapper/mods
|
|
@@ -185,6 +181,9 @@ grep -r "xp.*iEnKS" dapper/mods
|
|
|
185
181
|
|
|
186
182
|
## Test cases (models)
|
|
187
183
|
|
|
184
|
+
Simple models facilitate the reliability, reproducibility,
|
|
185
|
+
and interpretability of experiment results.
|
|
186
|
+
|
|
188
187
|
Model | Lin | TLM** | PDE? | Phys.dim. | State len | Lyap≥0 | Implementer
|
|
189
188
|
----------- | --- | ----- | ---- | --------- | --------- | ------ | ----------
|
|
190
189
|
Id | Yes | Yes | No | N/A | * | 0 | Raanes
|
|
@@ -233,9 +232,7 @@ DAPPER is aimed at research and teaching (see discussion up top).
|
|
|
233
232
|
Example of limitations:
|
|
234
233
|
|
|
235
234
|
- It is not suited for very big models (>60k unknowns).
|
|
236
|
-
-
|
|
237
|
-
(although the `Dyn` and `Obs` models may otherwise be time-dependent).
|
|
238
|
-
- Non-uniform time sequences not fully supported.
|
|
235
|
+
- Non-uniform time sequences.
|
|
239
236
|
|
|
240
237
|
The scope of DAPPER is restricted because
|
|
241
238
|
|
|
@@ -321,7 +318,24 @@ in the development of DAPPER.
|
|
|
321
318
|
[26]: https://github.com/CliMA/EnsembleKalmanProcesses.jl
|
|
322
319
|
|
|
323
320
|
|
|
324
|
-
##
|
|
321
|
+
## Contributing
|
|
322
|
+
|
|
323
|
+
### Issues and Pull requests
|
|
324
|
+
|
|
325
|
+
Do not hesitate to open an issue, whether to report a problem or ask a question.
|
|
326
|
+
It may take some time for us to get back to you,
|
|
327
|
+
since DAPPER is primarily a volunteer effort.
|
|
328
|
+
Please start by perusing the [documentation](https://nansencenter.github.io/DAPPER/dapper.html)
|
|
329
|
+
and searching the issue tracker for similar items.
|
|
330
|
+
|
|
331
|
+
Pull requests are very welcome.
|
|
332
|
+
Examples: adding a new DA method, dynamical models,
|
|
333
|
+
experimental configuration reproducing literature results,
|
|
334
|
+
or improving the features and capabilities of DAPPER.
|
|
335
|
+
Please keep in mind the intentional [limitations](https://github.com/nansencenter/DAPPER#similar-projects)
|
|
336
|
+
and read the [developers guidelines](https://nansencenter.github.io/DAPPER/dev_guide).
|
|
337
|
+
|
|
338
|
+
### Contributors
|
|
325
339
|
|
|
326
340
|
Patrick N. Raanes,
|
|
327
341
|
Yumeng Chen,
|
|
@@ -345,7 +359,7 @@ and the Center for Western Weather and Water Extremes (CW3E).
|
|
|
345
359
|
<img src="./docs/imgs/CW3E-Logo-Horizontal-FullColor.png?raw=true" width="400">
|
|
346
360
|
<!-- markdownlint-restore -->
|
|
347
361
|
|
|
348
|
-
##
|
|
362
|
+
## Publications
|
|
349
363
|
|
|
350
364
|
- [Combining data assimilation and machine learning to emulate a dynamical model from sparse and noisy observations: A case study with the Lorenz 96 model](https://doi.org/10.1016/j.jocs.2020.101171)
|
|
351
365
|
- [Adaptive covariance inflation in the ensemble Kalman filter by Gaussian scale mixtures](https://doi.org/10.1002/qj.3386)
|
|
@@ -5,11 +5,11 @@ the docs for the various modules.
|
|
|
5
5
|
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
8
|
-
See [README/Installation](https://github.com/nansencenter/DAPPER#
|
|
8
|
+
See [README/Installation](https://github.com/nansencenter/DAPPER#installation)
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
|
-
See [README/Getting-started](https://github.com/nansencenter/DAPPER#
|
|
12
|
+
See [README/Getting-started](https://github.com/nansencenter/DAPPER#getting-started)
|
|
13
13
|
|
|
14
14
|
##### Examples
|
|
15
15
|
|
|
@@ -26,8 +26,8 @@ your own **model** or **method**, then
|
|
|
26
26
|
rather than trying to squeeze everything into its templates.
|
|
27
27
|
- If it is relatively simple, however, you may well want to use DAPPER.
|
|
28
28
|
In that case, read this:
|
|
29
|
-
- `mods`
|
|
30
|
-
- `da_methods`
|
|
29
|
+
- `dapper.mods`
|
|
30
|
+
- `dapper.da_methods`
|
|
31
31
|
|
|
32
32
|
Since the generality of DAPPER is
|
|
33
33
|
[limited](https://github.com/nansencenter/DAPPER#similar-projects)
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
.. include:: ./README.md
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "1.
|
|
7
|
+
__version__ = "1.7.0"
|
|
8
8
|
|
|
9
9
|
# A parsimonious list of imports used in the examples
|
|
10
10
|
from .dpr_config import rc
|
|
11
11
|
from .tools.datafiles import find_latest_run, load_xps
|
|
12
12
|
from .tools.rounding import round2sigfig
|
|
13
|
-
from .tools.seeding import set_seed
|
|
13
|
+
from .tools.seeding import rng, set_seed
|
|
14
14
|
from .xp_launch import combinator, seed_and_simulate, xpList
|
|
15
15
|
from .xp_process import xpSpace
|
|
@@ -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(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.noise.C.full)
|
|
128
|
-
mu = mu + KG@(yy[ko] - HMM.Obs(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))
|