mods⚓︎
Contains models included with DAPPER.
See the README section on test cases (models) for a table overview of the included models.
Defining your own model⚓︎
Below is a sugested structuring followed by most models already within DAPPER.
However, you are free to organize your model as you see fit,
as long as it culminates in the definition of one or more mods.HiddenMarkovModel
.
For the sake of modularity,
try not to import stuff from DAPPER outside of mods
and tools.liveplotting
.
- Make a directory:
my_model
. It does not have to reside within thedapper/mods
folder, but make sure to look into some of the other dirs thereunder as examples, for exampledapper/mods/DoublePendulum
. - Make a file:
my_model/__init__.py
to hold the core workings of the model. Further details are given below, but the main work lies in defining astep(x, t, dt)
function (you can name it however you like, butstep
is the convention), to implement the dynamical model/system mapping the statex
from one timet
to anothert + dt
. - Make a file:
my_model/demo.py
to runstep
and visually showcase a simulation of the model without any DA, and verify it's working. - Make a file:
my_model/my_settings_1.py
that defines (or "configures", since there is usually little programming logic and flow taking place) a completemods.HiddenMarkovModel
ready for a synthetic experiment (also called "twin experiment" or OSSE). - Once you've made some experiments you believe are noteworthy you should add a
"suggested settings/tunings" section in comments at the bottom of
my_model/my_settings_1.py
, listing some of the relevant DA method configurations that you tested, along with the RMSE (or other stats) that you obtained for those methods. You will find plenty of examples already in DAPPER, used for cross-referenced with literature to verify the workings of DAPPER (and the reproducibility of publications).
Details on my_model/__init__.py
⚓︎
-
The
step
function must support 2D-array (i.e. ensemble) and 1D-array (single realization) input, and return output of the same number of dimensions (as the input). Seemods.Lorenz63
: use ofens_compatible
.mods.Lorenz96
: use of relatively clever slice notation.-
to abbreviate the indexing elsewhere.mods.LorenzUV
: use of cleverer slice notation:...
(ellipsis). Consider pre-defining the slices like so: -
mods.QG
: use of parallelized for loop (map).
Note
To begin with, test whether the model works on 1 realization, before running it with several (simultaneously). Also, start with a small integration time step, before using more efficient/adventurous time steps. Note that the time step might need to be shorter in assimilation, because it may cause instabilities.
Note
Most models are defined using simple procedural style. However,
mods.LorenzUV
andmods.QG
use OOP, which is perhaps more robust when different control-variable settings are to be investigated. The choice is yours.In parameter estimation problems, the parameters are treated as input variables to the "forward model". This does not necessarily require OOP. See
docs/examples/param_estim.py
. -
Optional: define a suggested/example initial state,
x0
. This facilitates the specification of initial conditions for different synthetic experiments, as random variables centred onx0
. It is also a convenient way just to specify the system size aslen(x0)
. In many experiments, the specific value ofx0
does not matter, because most systems are chaotic, and the average of the stats are computed only fortime > BurnIn > 0
, which will not depend onx0
if the experiment is long enough. Nevertheless, it's often convenient to pre-define a point on the attractor, or basin, or at least ensure "physicality", for quicker spin-up (burn-in). -
Optional: define a number called
Tplot
which defines the (sliding) time window used by the liveplotting of diagnostics. -
Optional: To use the (extended) Kalman filter, or 4D-Var, you will need to define the model linearization, typically called
dstep_dx
. Note: this only needs to support 1D input (single realization).
Modules:
Name | Description |
---|---|
DoublePendulum |
The motion of a pendulum with another pendulum attached to its end. |
Id |
The identity model (that does nothing, i.e. sets |
Ikeda |
The "Ikeda map" is a discrete-time dynamical system of size 2. |
KS |
Kuramoto-Sivashinsky (KS) system: the simplest (?) PDE admitting chaos. |
LA |
Linear advection (i.e. translation) in 1D. |
Lorenz05 |
A multi-scale, smooth version of the classic Lorenz-96. |
Lorenz63 |
The classic exhibitor of chaos, consisting of 3 coupled ODEs. |
Lorenz84 |
A chaotic system of size 3, like Lorenz-63, but with +complex geometry. |
Lorenz96 |
A 1D emulator of chaotic atmospheric behaviour. |
Lorenz96s |
A perfect-random version of Lorenz-96. |
LorenzUV |
The 2-scale/layer/speed coupled version of Lorenz-96. |
LotkaVolterra |
The generalized predator-prey model, with settings for chaotic dynamics. |
QG |
Quasi-geostraphic 2D flow. Described in detail by sakov2008b. |
VL20 |
Single-scale Lorenz-96 with an added thermodynamic component. |
explore_props |
Estimtate the Lyapunov spectrum and other props. of the dynamics of the models. |
integration |
Time stepping (integration) tools. |
pb |
Make |
utils |
Utilities to help define hidden Markov models. |
HiddenMarkovModel
⚓︎
Bases: NicePrint
Container class (with some embellishments) for a Hidden Markov Model (HMM).
Should contain the details necessary to run synthetic DA experiments,
also known as "twin experiment", or OSSE (observing system simulation experiment).
The synthetic truth and observations may then be obtained by running
.simulate
.
Note
Each model included with DAPPER comes with several examples
of model settings from the literature.
See, for example, mods.Lorenz63.sakov2012
.
Warning
These example configs do not necessarily hold a high programming standard,
as they may have been whipped up at short notice to replicate some experiments,
and are not intended for re-use.
Nevertheless, sometimes they are re-used by another configuration script,
leading to a major gotcha/pitfall: changes made to the imported HMM
(or
the model's module itself) also impact the original object (since they
are mutable and thereby referenced). This usually isn't an issue, since
one rarely imports two/more separate configurations. However, the test suite
imports all configurations, which might then unintentionally interact.
To avoid this, you should use the copy
method of the HMM
before making any changes to it.
__init__(Dyn, Obs, tseq, X0, liveplotters=None, sectors=None, name=None, **kwargs)
⚓︎
Initialize.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
Dyn
|
Operator or dict
|
Operator for the dynamics. |
required |
Obs
|
Operator or TimeDependentOperator or dict
|
Operator for the observations
Can also be time-dependent, ref |
required |
tseq
|
Chronology
|
Time sequence of the HMM process. |
required |
X0
|
RV
|
Random distribution of initial condition |
required |
liveplotters
|
list
|
A list of tuples. See example use in function |
None
|
sectors
|
dict
|
Labelled indices referring to parts of the state vector.
When defined, field-mean statistics are computed for each sector.
Example use can be found in |
None
|
name
|
str
|
Label for the |
None
|
simulate(desc='Truth & Obs')
⚓︎
Generate synthetic truth and observations.
Operator
⚓︎
Bases: NicePrint
Container for the dynamical and the observational maps.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
M
|
int
|
Length of output vectors. |
required |
model
|
function
|
The actual operator. |
None
|
noise
|
RV
|
The associated additive noise. The noise can also be a scalar or an
array, producing |
None
|
Note
Any remaining keyword arguments are written to the object as attributes.
TimeDependentOperator
⚓︎
Wrapper for Operator
that enables time dependence.
The time instance should be specified by ko
,
i.e. the index of an observation time.
Examples: docs/examples/time-dep-obs-operator.py
and dapper/mods/QG/sakov2008.py
.
__init__(**kwargs)
⚓︎
Can be initialized like Operator
, in which case the resulting
object will always return the same Operator
nomatter the input time.
If initialized with 1 argument: dict(time_dependent=func)
then func
must return an Operator
object.