MCMC toolbox » Examples » Algae

Algae example

The example uses functions algaesys, algaefun and algaess.

We study the following system

This is a simplified lake algae dynamics model. We consider phytoplankton A, zooplankton Z and nutrition P (eg. phosphorus) available for A in the water. The system is affected by the water outflow/inflow Q, incoming phosphorus load Pin and temperature T. It is described as a simple predator - pray dynamics between A and Z. The growth of A is limited by the availability of P and it depends on the water temperature T. The inflow/outflow Q affects both A and P, but not Z. We use the following equations:

dA/dt = (μ - ρa - Q/V - αZ) A
dZ/dt = αZA-ρz Z
dP/dt = -Q/V (P-Pin) + (ρa-μ)A+ρzZ

where the growth rate µ depends on both temperature T and phosphorus P

μ = μmaxθ(T-20)P/(k+P).

The data set is stored in algaedata.mat. First we load and plot the data.

clear model data params options
load algaedata.mat
figure(1); clf
for i =1:3
  subplot(2,3,i)
  plot(data.xdata(:,1),data.xdata(:,i+1),'-k');
  title(data.xlabels(i+1)); xlim([1,120])
end
subplot(2,1,2)
plot(data.ydata(:,1),data.ydata(:,2:end),'o-');
title('model state variable observations');
legend(data.ylabels(2:end),'Location','best');
xlabel('days');

The model sum of squares in file algaess.m is given in the model structure.

model.ssfun = @algaess;

All parameters are constrained to be positive. The initial concentrations are also unknown and are treated as extra parameters.

params = {
    {'mumax', 0.5,  0}
    {'rhoa',  0.03, 0}
    {'rhoz',  0.1,  0}
    {'k',     10,   0}
    {'alpha', 0.02, 0}
    {'th',    1.14, 0, Inf, 1.14, 0.2}  % N(0.14, 0.2^2)1{th>0} prior
% initial values for the model states
    {'A0', 0.77, 0, Inf, 0.77, 2 }
    {'Z0', 1.3,  0, Inf, 1.3,  2 }
    {'P0', 10,   0, Inf, 10,   2 }
    };

We assume having at least some prior information on the repeatability of the observation and assign rather non informational prior for the residual variances of the observed states. The default prior distribution is sigma2 ~ invchisq(S20,N0), the inverse chi squared distribution (see for example Gelman et al.). The 3 components (A, Z, P) all have separate variances.

model.S20 = [1 1 2];
model.N0  = [4 4 4];

First generate an initial chain.

options.nsimu = 1000;
[results, chain, s2chain]= mcmcrun(model,data,params,options);
Sampling these parameters:
name   start [min,max] N(mu,s^2)
mumax: 0.5 [0,Inf] N(0,Inf)
rhoa: 0.03 [0,Inf] N(0,Inf)
rhoz: 0.1 [0,Inf] N(0,Inf)
k: 10 [0,Inf] N(0,Inf)
alpha: 0.02 [0,Inf] N(0,Inf)
th: 1.14 [0,Inf] N(1.14,0.2^2)
A0: 0.77 [0,Inf] N(0.77,2^2)
Z0: 1.3 [0,Inf] N(1.3,2^2)
P0: 10 [0,Inf] N(10,2^2)

Then re-run starting from the results of the previous run, this will take couple of minutes.

options.nsimu = 5000;
[results, chain, s2chain] = mcmcrun(model,data,params,options, results);
Using values from the previous run
Sampling these parameters:
name   start [min,max] N(mu,s^2)
mumax: 0.398492 [0,Inf] N(0,Inf)
rhoa: 0.0348433 [0,Inf] N(0,Inf)
rhoz: 0.0982238 [0,Inf] N(0,Inf)
k: 9.4219 [0,Inf] N(0,Inf)
alpha: 0.0233986 [0,Inf] N(0,Inf)
th: 1.00471 [0,Inf] N(1.14,0.2^2)
A0: 1.16216 [0,Inf] N(0.77,2^2)
Z0: 2.07551 [0,Inf] N(1.3,2^2)
P0: 8.54463 [0,Inf] N(10,2^2)

Chain plots should reveal that the chain has converged and we can use the results for estimation and predictive inference.

figure(2); clf
mcmcplot(chain,[],results,'pairs');
figure(3); clf
mcmcplot(chain,[],results,'denspanel',2);

Function chainstats calculates mean ans std from the chain and estimates the Monte Carlo error of the estimates. Number tau is the integrated autocorrelation time and geweke is a simple test for a null hypothesis that the chain has converged.

chainstats(chain,results)
MCMC statistics, nsimu = 5000

                 mean         std      MC_err         tau      geweke
---------------------------------------------------------------------
     mumax     7.3133      8.9169      1.8501       612.9    0.034271
      rhoa   0.026332    0.014272    0.002472      416.33     0.27418
      rhoz   0.097931   0.0057379  0.00069317      81.933      0.9884
         k      346.6      434.88      90.632      615.33    0.030661
     alpha   0.023557   0.0013095  0.00015524      92.634      0.9452
        th     1.0123    0.013533   0.0016359      114.66     0.98836
        A0     1.0649     0.30144    0.024486      37.659      0.9064
        Z0     1.8118     0.45222    0.050899      66.175     0.82012
        P0      8.822     0.85789    0.065738      37.405     0.98279
---------------------------------------------------------------------

In order to use the mcmcpred function we need function modelfun with input arguments given as modelfun(xdata,theta). We construct this as an anonymous function.

modelfun = @(d,th) algaefun(d(:,1),th,th(7:9),d);

We sample 500 parameter realizations from chain and s2chain and calculate the predictive plots.

nsample = 500;
out = mcmcpred(results,chain,s2chain,data.xdata,modelfun,nsample);
figure(4); clf
mcmcpredplot(out);
% add the 'y' observations to the plot
hold on
for i=1:3
  subplot(3,1,i)
  hold on
  plot(data.ydata(:,1),data.ydata(:,i+1),'s');
  ylabel(''); title(data.ylabels(i+1));
  hold off
end
xlabel('days');