EPPES parameter estimation example using Lorenz 95

This example demonstrates EPPES method using so called stochastic Lorenz 95 system [Wilks, 2005]. It is a Lorenz 95 system with added fast state variables whose effect is parameterized in the simpler forecast model. Here we estimate these parameters using EPPES. See the EPPES article [Laine, 2011] for details. This code is a slightly simplified version of the example in Section 4 of the paper.

Laine, et al.: Ensemble prediction and parameter estimation system: the method, Q. J. R. Meteorol. Soc., 2011, doi:10.1002/qj.922.

First, we load the truth system used as observations. The true states are generated with the full system using short integration time step and including the fast state variables, also. For estimation of the closure parameters of the simpler forecast model some independent random noise (with std sigma_a) is later added to these error free states.

T10 = load('T10.mat')

truth = T10.truth; % true states
aint  = T10.aint;  % analysis intervall
dt    = T10.dt;    % integration time step
T10 = 

    truth: [301x360 double]
     aint: 0.4
       dt: 0.0025

The forecast model function is obtained by evaluating the numerical solution of the L95 ode system at given time points and initial values at the start. The modified Lorenz 95 ode system is defined in file the l95ode.m.

l95fun = @(time,s0,params) deval(ode45(@l95ode,time,s0(:),[],params),time);

The standard deviations for analysis and initial perturbations.

sigma_a  = 0.05;
sigma_ip = 0.1;

Forecast model settings.

params.F       = 10;
params.sigma_e = 0;
params.phi     = 0.0;
params.gupars  = [0.0 0.2]; % initial parameter values
params.gufun   = @(x,p) polyval(p,x);
params.eta     = zeros(50,1);
fc_range       = 3;  % how long ahead do we forecast

nens = 50;  % ensemble size
npar = length(params.gupars); % number of parameters

Initial values for hyperprior parameters.

mu  = params.gupars(:); % initial prior mean
tau = 100*diag([1;1].^2); % accuracy of mu
sig = 0.1*diag([1;1].^2); % initial prior covariance
n0  = 1;                  % accuracy of sig
nmax = 10;                % maximum n0

Define number of EPPES iterations, and allocate memory for saving the intermediate results,

niter      = size(truth,1)-fc_range-1;
niter      = 30; % use a smaller number of iterations for faster illustration
parsall    = zeros(niter,nens,npar);
weightsall = zeros(niter,nens);
muall      = zeros(niter,npar);
sigall     = zeros(niter,npar,npar);

disp('running eppes, this will take some time ...')
running eppes, this will take some time ...

The simulation loop.

figure(1);clf
for iiter=1:niter

  time = (iiter-1)*aint:dt:(iiter+fc_range-1)*aint;
  a = truth(iiter,1:40);
  a = a + sigma_a*randn(size(a));  % analysis = truth + noise

  pars_prop = mvnorr(nens,mu,sig);  % proposed parameters from N(mu,sig)

  % launch the ensemble
  for j=1:nens
    s0 = a + sigma_ip*randn(size(a));       % initial value
    params.gupars = pars_prop(j,:);         % forecast model parameters
    sens(:,:,j) = l95fun(time,s0,params)';  % run the forecast model
    smod = sens(aint/dt:aint/dt:end,:,:);   % model response at data points
  end

  % sum of squares for ensemble members is calculated in function ens_ss_l95.m
  ss = ens_ss_l95(smod,truth(iiter+1:iiter+fc_range,1:40));
  % calculating weights and resampling
  w = exp(-0.5*(ss(:)));
  w = w/sum(w);
  pars_new = resample(pars_prop,w);

  % update the parameters
  [mu,tau,nn,sig] = eppesupd(pars_new,mu,tau,n0,sig);
  n0 = min(nn,nmax); % parameter n0 is at most nmax

  % save the proposed points and their resample weights
  parsall(iiter,:,:)  = pars_prop;
  weightsall(iiter,:) = w';
  muall(iiter,:)      = mu';
  sigall(iiter,:,:)   = sig;

  % some plotting on the fly
  figure(1);
  subplot(3,1,1);
  colormap(flipud(gray));
  plotc(repmat(time,nens,1),squeeze(sens(:,1,:))',-ss); hold on;
  plot(time(1)+aint:aint:time(end),truth(iiter+1:iiter+fc_range,1),'ro',...
       'markersize',10,'markerfacecolor','red');
  hold off;
  xlabel('time'); ylabel('state X_1');
  title(sprintf('iter: %d/%d',iiter,niter));

  subplot(3,1,2);
  plotc(pars_prop(:,1),pars_prop(:,2),w,'o','markeredgecolor',[0.85 0.85 0.85]);
  hold on
  ellipse(mu,4.6*sig,'g-','LineWidth',2);
  plot(mu(1),mu(2),'.k'); hold off
  xlabel('parameter \theta_1'); ylabel('parameter \theta_2');

  subplot(3,1,3);
  stem(w);
  xlabel('ensemble members'); ylabel('parameter weight')
  drawnow;

end

The figure shows iteratively the state evolution of each ensemble member for the first state variable X1, together with the observations. The forecast model lines are colored according to the forecast skill weight (upper panel). Two dimensional plot of the proposed parameters with their weights are shown with 95% probability ellipsoid of the proposal/prior covariance sig (center panel). The calculated relative weight for each members are shown (lower panel).

disp('... done')
... done

Plot the proposed points and their weights. For both of the parameters theta1 and theta2 the evolution of the EPPES method is shown. Iteration number is on the x axis and parameter value at y axis. Colouring shows the importance weights, red line is the evolution of the mean mu and green lines show plus minus 2 times the standard deviation from covariance matrix sig.

figure(2); clf
subplot(2,1,1)
eppeschainplot(parsall(:,:,1),weightsall, muall(:,1), sqrt(sigall(:,1,1)))
ylabel('\theta_1')
title('EPPES iterations in L95 example')
subplot(2,1,2)
eppeschainplot(parsall(:,:,2),weightsall, muall(:,2), sqrt(sigall(:,2,2)))
ylabel('\theta_2')
xlabel('iteration number')