Skip to content

Commit 826d6dc

Browse files
author
Abhinab Bhattacharjee
committed
Intial EnKF and ETKF commit
1 parent bed0bbc commit 826d6dc

File tree

17 files changed

+427
-127
lines changed

17 files changed

+427
-127
lines changed

src/+datools/+error/Error.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
classdef Error < handle
2+
%ERROR base class for all kind of errors
3+
% Curently supports Gaussian, Laplace, Logistics, Tent and Triangle.
24

35
methods
46

src/+datools/+error/Gaussian.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
classdef Gaussian < datools.error.Error
2+
%GAUSSIAN Gaussian child class for adding gaussina noise with a user
3+
% defined deviation and bias
24

35
properties
4-
CovarianceSqrt
5-
Bias
6+
CovarianceSqrt % Covariance(sqrt) for the noise
7+
Bias % Bias
68
end
79

810
methods

src/+datools/+examples/l63_enkf.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
modelODE.TimeSpan = [0, Delta_t];
3131

3232
% Propogate
33-
[tt, yy] = ode45(natureODE.Rhs.F, [0, 10], nature0);
33+
[tt, yy] = ode45(natureODE.RHS.F, [0, 10], nature0);
3434
natureODE.Y0 = yy(end, :).';
3535

3636
% initialize model

src/+datools/+observation/Indexed.m renamed to src/+datools/+observation/+operator/Indexed.m

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
classdef Indexed < datools.observation.Observation
1+
classdef Indexed < datools.observation.operator.Observation
2+
%INDEXED Defines the indexed observation operator
23

34
properties
4-
Indices
5+
Indices % Indices of observed state
56
end
67

78
methods
@@ -14,7 +15,7 @@
1415

1516
s = p.Results;
1617

17-
[email protected](nvars, p.Unmatched);
18+
[email protected].operator.Observation(nvars, p.Unmatched);
1819

1920
obj.Indices = s.Indices;
2021

src/+datools/+observation/Linear.m renamed to src/+datools/+observation/+operator/Linear.m

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
classdef Linear < datools.observation.Observation
1+
classdef Linear < datools.observation.operator.Observation
2+
%LINEAR Defines the linear observation operator
3+
% H is already linearized
24

35
properties
4-
H
6+
H % Observation operator
57
end
68

79
methods
@@ -14,7 +16,7 @@
1416

1517
s = p.Results;
1618

17-
[email protected](nvars, p.Unmatched);
19+
[email protected].operator.Observation(nvars, p.Unmatched);
1820

1921
obj.H = s.H;
2022

@@ -30,4 +32,4 @@
3032

3133
end
3234

33-
end
35+
end

src/+datools/+observation/Nonlinear.m renamed to src/+datools/+observation/+operator/Nonlinear.m

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
classdef Nonlinear < datools.observation.Observation
1+
classdef Nonlinear < datools.observation.operator.Observation
2+
%NONLINEAR Defines the non linear observation operator
23

34
properties
45
F
5-
%J
6-
Indicies
6+
Jacobian % Jacobian of non-linear Observation operator
7+
Indicies % Indices of observed state
78
end
89

910
methods
@@ -12,16 +13,16 @@
1213
p = inputParser;
1314
p.KeepUnmatched = true;
1415
addParameter(p, 'F', @(~, x) x);
15-
%addParameter(p, 'J', @(~, x) speye(numel(x)));
16+
addParameter(p, 'Jacobian', @(~, x) speye(numel(x)));
1617
addParameter(p, 'Indicies', 1);
1718
parse(p, varargin{:});
1819

1920
s = p.Results;
2021

21-
[email protected](nvars, p.Unmatched);
22+
[email protected].operator.Observation(nvars, p.Unmatched);
2223

2324
obj.F = s.F;
24-
%obj.J = s.J;
25+
obj.Jacobian = s.Jacobian;
2526
obj.Indicies = s.Indicies;
2627

2728
end
@@ -32,8 +33,10 @@
3233
end
3334

3435
function H = linearization(obj, t, x)
35-
%H = obj.J(t, x);
36-
H = 1;
36+
H = obj.Jacobian(t, x);
37+
if size(H, 1) == size(H, 2)
38+
H = H(obj.Indices, :);
39+
end
3740
end
3841

3942
end

src/+datools/+observation/Observation.m renamed to src/+datools/+observation/+operator/Observation.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
classdef Observation < handle
2+
%OBSERVATION Base class for every observation operator
3+
% other details
24

35
properties
4-
NumVars
5-
ErrorModel
6+
NumVars % number of state variables
7+
ErrorModel % observation error model
68
end
79

810
methods
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
classdef StateObservation < handle
2+
%STATEOBSERVATION this is the class that handles the observed state
3+
% Observed state are noisy snapshots of reality (truth)
4+
5+
properties
6+
Y % Current Observation of States (maybe sparse)
7+
R % Observation Error Covariance
8+
Noise % Noise
9+
NumObs % Number of Observations(Make sure > 0)
10+
end
11+
12+
methods
13+
function obj = StateObservation(varargin)
14+
p = inputParser;
15+
p.KeepUnmatched = true;
16+
addParameter(p, 'Y', []);
17+
addParameter(p, 'Noise', datools.error.Error);
18+
validationFunction = @(x) (x>0);
19+
addParameter(p, 'NumObs', 1, validationFunction);
20+
21+
parse(p, varargin{:});
22+
23+
s = p.Results;
24+
25+
26+
obj.Y = s.Y;
27+
obj.Noise = s.Noise;
28+
obj.NumObs = s.NumObs;
29+
30+
unMatched = p.Unmatched;
31+
32+
p = inputParser;
33+
addParameter(p, 'R', speye(obj.NumObs));
34+
35+
parse(p, unMatched);
36+
s = p.Results;
37+
obj.R = s.R;
38+
end
39+
40+
function updateY(obj, y)
41+
obj.Y = y;
42+
end
43+
44+
function addNoise(obj, t, ~)
45+
obj.Y = obj.Noise.adderr(t, obj.Y);
46+
end
47+
end
48+
49+
end

src/+datools/+statistical/+ensemble/ETKF.m

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,35 @@
22

33
methods
44

5-
function analysis(obj, R, y)
5+
function analysis(obj)
66

77
inflation = obj.Inflation;
88

99
tc = obj.Model.TimeSpan(1);
1010

1111
xf = obj.Ensemble;
1212
ensN = obj.NumEnsemble;
13+
14+
R = obj.Observation.R;
1315

1416
xfm = mean(xf, 2);
1517
Af = xf - repmat(xfm, 1, ensN);
1618
Af = inflation * Af/sqrt(ensN - 1);
1719
xf = repmat(xfm, 1, ensN) + Af*sqrt(ensN - 1);
1820

19-
Hxf = obj.Observation.observeWithoutError(tc, xf);
21+
Hxf = obj.ObservationOperator.observeWithoutError(tc, xf);
2022
Hxfm = mean(Hxf, 2);
2123
HAf = Hxf - repmat(Hxfm, 1, ensN);
2224
HAf = HAf/sqrt(ensN - 1);
2325

24-
dS = decomposition((HAf * HAf.')+R, 'chol');
26+
dS = decomposition((HAf * HAf.')+ R, 'chol');
2527
dR = decomposition(R, 'chol');
2628

2729
temp = dS \ HAf;
2830
T = sqrtm(eye(ensN)-(HAf.' * temp));
2931

3032
Aa = Af * T;
31-
xam = xfm + ((Aa * (HAf * T).') * (dR \ (y - Hxfm)));
33+
xam = xfm + ((Aa * (HAf * T).') * (dR \ (obj.Observation.Y - Hxfm)));
3234
xa = sqrt(ensN-1) .* Aa + repmat(xam, 1, ensN);
3335

3436
obj.Ensemble = xa;

src/+datools/+statistical/+ensemble/EnF.m

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
1-
classdef EnF < handle
2-
% This is the base class for all statistical methods
3-
% Derive from this class and implement methods/functions as required
4-
% Deriving from handle base class allows an object of this class to be
5-
% passed by reference.
1+
classdef EnF < datools.DABase
2+
%ENF This is the base class for all statistical methods
3+
% Derive from this class and implement methods/functions as required
4+
% Deriving from handle base class allows an object of this class to be
5+
% passed by reference.
66

77
properties
8-
Model % type of ODE solver (ode45/Runge Kutta) and the model (eg: Lorenz63)
9-
ModelError % type err
10-
Observation % type of obervation
11-
Ensemble % current ensemble values for all the states
12-
Weights % Weight of each particle/ensemble
13-
Inflation % inflation constant
14-
Rejuvenation % rejuvenation constant
15-
Localization % A boolean if localization needs to be used
16-
Parallel % A boolean if parallel threads are to be implemented
17-
RankHistogram % State variables for which RH is needed
18-
RankValue % store the RH values for each state variables required
19-
ResamplingThreshold % threshold below which resampling needs to be done
8+
%Model % type of ODE solver and the model
9+
%ModelError % type err
10+
%Observation % type of obervation
11+
Ensemble % current ensemble values for all the states
12+
Anomalies % Anomalies
13+
Weights % Weight of each particle/ensemble
14+
Inflation % inflation constant
15+
Rejuvenation % rejuvenation constant
16+
Localization % A boolean if localization needs to be used
17+
Parallel % A boolean if parallel threads are used
18+
RankHistogram % State variables for which RH is needed
19+
RankValue % store the RH values for each state variables required
20+
ResamplingThreshold % threshold below which resampling needs to be done
2021
end
2122

2223
properties (Dependent)
23-
BestEstimate % Current estimate of the particles/ensembles
24-
NumEnsemble % Number of ensemble members
24+
BestEstimate % Current estimate of the particles/ensembles
25+
NumEnsemble % Number of ensemble members
2526
end
2627

2728
methods (Abstract)
2829
% A method that will be implemented by child classes to make
2930
% approximate inference on ensembles of states by combining
3031
% prior forecast/background data with noisy observations
31-
analysis(obj, R, y)
32+
analysis(obj)
3233
end
3334

3435

@@ -42,8 +43,9 @@
4243

4344
p = inputParser;
4445
p.KeepUnmatched = true;
45-
addRequired(p, 'Model', @(x) isa(x, 'datools.Model'));
46-
addParameter(p, 'ModelError', datools.error.Error);
46+
47+
%addRequired(p, 'Model', @(x) isa(x, 'datools.Model'));
48+
%addParameter(p, 'ModelError', datools.error.Error);
4749
addParameter(p, 'NumEnsemble', 1);
4850
addParameter(p, 'Inflation', 1);
4951
addParameter(p, 'Rejuvenation', []);
@@ -52,34 +54,29 @@
5254
addParameter(p, 'RIPIterations', 0);
5355
addParameter(p, 'RankHistogram', [])
5456
addParameter(p, 'ResamplingThreshold', 0.5);
57+
addParameter(p, 'EnsembleGenerator', @(x, y) randn(x, y));
58+
5559
parse(p, varargin{:});
5660

5761
s = p.Results;
62+
63+
[email protected](p.Unmatched);
5864

59-
obj.Model = s.Model;
60-
obj.ModelError = s.ModelError;
6165
obj.Inflation = s.Inflation;
6266
obj.Rejuvenation = s.Rejuvenation;
6367
obj.Localization = s.Localization;
6468
obj.Parallel = s.Parallel;
6569
obj.RankHistogram = s.RankHistogram;
6670
obj.ResamplingThreshold = s.ResamplingThreshold;
6771
ensN = s.NumEnsemble;
72+
6873
if ~isempty(obj.RankHistogram)
6974
RankValue = zeros(length(obj.RankHistogram), ensN+2);
7075
end
7176

72-
kept = p.Unmatched;
73-
74-
p = inputParser;
75-
addParameter(p, 'Observation', datools.observation.Observation(s.Model.NumVars));
76-
addParameter(p, 'EnsembleGenerator', @(x) randn(s.Model.NumVars, x));
77-
parse(p, kept);
78-
79-
s = p.Results;
80-
8177
obj.Ensemble = s.EnsembleGenerator(ensN);
82-
obj.Observation = s.Observation;
78+
obj.Anomalies = (1/sqrt(ensN)) * (obj.Ensemble - mean(obj.Ensemble, 2));
79+
%obj.Observation = s.Observation;
8380
obj.Weights = ones(ensN, 1) / ensN;
8481

8582
end
@@ -93,7 +90,7 @@ function forecast(obj)
9390
times = zeros(obj.NumEnsemble, 1);
9491

9592
if obj.Parallel
96-
rhs = obj.Model.ODEModel.RHS.F;
93+
rhs = obj.Model.ODEModel.F;
9794
tspan = obj.Model.TimeSpan;
9895
solver = obj.Model.Solver;
9996
ens = obj.Ensemble;
@@ -112,14 +109,14 @@ function forecast(obj)
112109
end
113110

114111
for ensi = 1:ensN
115-
obj.Ensemble(:, ensi) = obj.ModelError.adderr(obj.Model.TimeSpan(end), ens(:, ensi));
112+
obj.Ensemble(:, ensi) = obj.ModelError.adderr(obj.Model.ODEModel.TimeSpan(end), ens(:, ensi));
116113
end
117114

118115
else
119116
for ensi = 1:obj.NumEnsemble
120117
[time, yend] = obj.Model.solve([], obj.Ensemble(:, ensi));
121118

122-
obj.Ensemble(:, ensi) = obj.ModelError.adderr(obj.Model.TimeSpan(end), yend);
119+
obj.Ensemble(:, ensi) = obj.ModelError.adderr(obj.Model.ODEModel.TimeSpan(end), yend);
123120
times(ensi) = time;
124121
end
125122
end
@@ -162,7 +159,7 @@ function setMean(obj, xam)
162159
% of the object of this class or a derived class to XAM
163160

164161
X = obj.Ensemble;
165-
ensN = size(X, 2);
162+
ensN = size(X, 2); % try obj.NumEnsemble
166163
xm = mean(X, 2);
167164
A = (X - repmat(xm, 1, ensN));
168165
X = repmat(xam, 1, ensN) + A;
@@ -188,7 +185,7 @@ function scaleAnomalies(obj, scale)
188185
function rejuvenate(obj, tau, Xf)
189186
%REJUVENATE To reduce particle degeneracy
190187
%
191-
% REJUVENATE(OBJ, TAU, XF) adds a random noise in the form of
188+
% REJUVENATE(OBJ, TAU, XF) adds a noise in the form of
192189
% random combination of background anomalies of the ensembles
193190
% of states (using rejuvenation bandwidth TAU) to the
194191
% transformation matrix. This matrix is used to rejuvenate

0 commit comments

Comments
 (0)