|
| 1 | +classdef ThreeDVar < handle |
| 2 | + % |
| 3 | + |
| 4 | + properties |
| 5 | + Model % type of ODE solver (ode45/Runge Kutta) and the model (eg: Lorenz63) |
| 6 | + ModelError % type err |
| 7 | + Observation % type of obervation |
| 8 | + State % current state values for all the states |
| 9 | + B % background covariance |
| 10 | + OptAlg % lbfgs or newton |
| 11 | + end |
| 12 | + |
| 13 | + properties (Dependent) |
| 14 | + BestEstimate % Current estimate of the particles/ensembles |
| 15 | + end |
| 16 | + |
| 17 | + properties (Access=protected) |
| 18 | + BDecomposition |
| 19 | + end |
| 20 | + |
| 21 | + methods |
| 22 | + function obj = ThreeDVar(varargin) |
| 23 | + %ENF The constructor initializes the properties/attributes |
| 24 | + % |
| 25 | + % OBJ = ENF(VARARGIN) accepts variable length argument list |
| 26 | + % VARARGIN and updates the properties/attributes of the object |
| 27 | + % (OBJ) of this class or a derived class |
| 28 | + |
| 29 | + optAlgValFcn = @(x) (strcmp(x, 'lbfgs') || strcmp(x, 'newton')); |
| 30 | + |
| 31 | + p = inputParser; |
| 32 | + p.KeepUnmatched = true; |
| 33 | + addRequired(p, 'Model', @(x) isa(x, 'datools.Model')); |
| 34 | + addParameter(p, 'ModelError', datools.error.Error); |
| 35 | + addParameter(p, 'InitialState', []); |
| 36 | + addParameter(p, 'BackgroundCovariance', []); |
| 37 | + addParameter(p, 'OptimizationType', 'lbfgs', optAlgValFcn); |
| 38 | + parse(p, varargin{:}); |
| 39 | + |
| 40 | + s = p.Results; |
| 41 | + |
| 42 | + obj.Model = s.Model; |
| 43 | + obj.ModelError = s.ModelError; |
| 44 | + obj.State = s.InitialState; |
| 45 | + obj.B = s.BackgroundCovariance; |
| 46 | + obj.BDecomposition = decomposition(obj.B, 'chol'); |
| 47 | + obj.OptAlg = s.OptimizationType; |
| 48 | + |
| 49 | + kept = p.Unmatched; |
| 50 | + |
| 51 | + p = inputParser; |
| 52 | + addParameter(p, 'Observation', datools.observation.Observation(s.Model.NumVars)); |
| 53 | + parse(p, kept); |
| 54 | + |
| 55 | + s = p.Results; |
| 56 | + |
| 57 | + obj.Observation = s.Observation; |
| 58 | + end |
| 59 | + |
| 60 | + function forecast(obj) |
| 61 | + %FORECAST Method to propagate the model forward in time |
| 62 | + % |
| 63 | + % FORECAST(OBJ) propoagates the model one step in time |
| 64 | + % using a user defined time integration method |
| 65 | + |
| 66 | + [~ , yend] = obj.Model.solve([], obj.State); |
| 67 | + |
| 68 | + obj.State = obj.ModelError.adderr(obj.Model.TimeSpan(end), yend); |
| 69 | + |
| 70 | + |
| 71 | + end |
| 72 | + |
| 73 | + function analysis(obj, R, y) |
| 74 | + |
| 75 | + % A constrained problem like double pendulum will need a |
| 76 | + % constraint coming in from the object. |
| 77 | + |
| 78 | + dB = obj.BDecomposition; |
| 79 | + |
| 80 | + if strcmp(class(R), "decomposition") |
| 81 | + dR = R; |
| 82 | + else |
| 83 | + dR = decomposition(R, 'chol'); |
| 84 | + end |
| 85 | + |
| 86 | + xb = obj.State; |
| 87 | + obs = obj.Observation; |
| 88 | + |
| 89 | + t = obj.Model.TimeSpan(end); |
| 90 | + |
| 91 | + H = @(x) obs.observeWithoutError(t, x); |
| 92 | + Hadjoint = @(x) obs.linearization(t, x)'; |
| 93 | + |
| 94 | + J = @(x) cost(x, xb, dB, y, dR, H, Hadjoint); |
| 95 | + |
| 96 | + if strcmp(obj.OptAlg, 'lbfgs') |
| 97 | + opts = optimoptions('fmincon','Display','none', ... |
| 98 | + 'SpecifyObjectiveGradient',true, ... |
| 99 | + 'HessianApproximation', {'lbfgs', 50}); |
| 100 | + else |
| 101 | + |
| 102 | + hessv = @(Hax, v) dB\v + Hax*(dR\(Hax'*v)); |
| 103 | + opts = optimoptions('fmincon','Display','none', ... |
| 104 | + 'Algorithm','trust-region-reflective', ... |
| 105 | + 'SpecifyObjectiveGradient',true, ... |
| 106 | + 'HessianMultiplyFcn', hessv, ... |
| 107 | + 'SubproblemAlgorithm', 'cg'); |
| 108 | + |
| 109 | + end |
| 110 | + |
| 111 | + xa = fmincon(J, xb, [], [], [], [], [], [], [], opts); |
| 112 | + |
| 113 | + obj.State = xa; |
| 114 | + |
| 115 | + function [c, g, hessinfo] = cost(x, xb, dB, y, dR, H, Hadjoint) |
| 116 | + |
| 117 | + dx = x - xb; |
| 118 | + dy = H(x) - y; |
| 119 | + Hax = Hadjoint(x); |
| 120 | + |
| 121 | + Bix = dB\dx; |
| 122 | + Riy = dR\dy; |
| 123 | + |
| 124 | + c = 0.5*((dx'*Bix) + (dy'*Riy)); |
| 125 | + g = Bix + Hax*Riy; |
| 126 | + hessinfo = Hax; |
| 127 | + |
| 128 | + end |
| 129 | + |
| 130 | + |
| 131 | + end |
| 132 | + |
| 133 | + function x = get.BestEstimate(obj) |
| 134 | + %GET.BESTESTIMATE Method to estimate of ensemble values |
| 135 | + % |
| 136 | + % X = GET.BESTESTIMATE(OBJ) uses an in-built getter method, |
| 137 | + % derived from handle class, to return the best estimate of |
| 138 | + % the information from the current ensembles of states and |
| 139 | + % its corresponding weights |
| 140 | + |
| 141 | + x = obj.State; |
| 142 | + |
| 143 | + end |
| 144 | + |
| 145 | + end |
| 146 | + |
| 147 | +end |
0 commit comments