Hi all,
I want to infer parameters of a system of ODEs. Before working with real data, I want to generate data for many synthetic experiments.
In order to familiarize myself with stan, I’m trying different interfaces and as a first step, I want to solve the ODE from the user guide.
This is the sho.stan file I’m using:
functions {
  vector sho(real t,        // time
             vector y,      // state
             real theta) {  // friction parameter
    vector[2] dydt;
    dydt[1] = y[2];
    dydt[2] = -y[1] - theta * y[2];
    return dydt;
  }
}
transformed data {
  int<lower=1> T = 40;
  vector[2] y0 = [1.0, 0.0]';
  real t0 = 0.0;
  array[T] real ts;
  for (t in 1:T) {
    ts[t] = t;
  }
  real theta = 0.35;
}
model {
}
generated quantities {
  array[T] vector[2] y_sim = ode_rk45(sho, y0, t0, ts, theta);
  // add measurement error
  for (t in 1:T) {
    y_sim[t, 1] += normal_rng(0, 0.1);
    y_sim[t, 2] += normal_rng(0, 0.1);
  }
}
I get expected results, when interfacing that code with cmdstanpy:
from pathlib import Path
from cmdstanpy import CmdStanModel
import matplotlib.pyplot as pt
stan_file = Path('stan/sho.stan')
model = CmdStanModel(stan_file=stan_file)
sim_data = model.sample(data={}, fixed_param=True)
y_sim = sim_data.stan_variable(var='y_sim')
y_sim_mean = np.mean(y_sims, axis=0)
pt.plot(y_sim_mean[:,0], y_sims_mean[:,1])
pt.plot(y_sim[0, :,0], y_sims[0, :,1])
pt.show()
However, I want to get the data from Python. If I set up a dictionary with
data = {
    'T': 40,
    'y0': [1.0, 0.0],
    't0': 0.0,
    'ts': list(range(1, 41)),
    'theta': 0.35,
}
And exchange the tranformed data in the stan code with a data block
data {
  int<lower=1> T;
  vector[2] y0;
  real t0;
  array[T] real ts;
  real theta;
}
I get following error Exception: variable does not exist; processing stage=data initialization; variable name=T; base type=int.
If I try the same with pystan, it works:
from pathlib import Path
import stan
import matplotlib.pyplot as pt
stan_code = Path('stan/sho.stan').read_text()
data = {
    'T': 40,
    'y0': [1.0, 0.0],
    't0': 0.0,
    'ts': list(range(1, 41)),
    'theta': 0.35,
}
posterior = stan.build(stan_code, data=data, random_seed=1)
fit = posterior.fixed_param()
y_sim = fit['y_sim']
y_sim_mean = np.mean(y_sim, axis=2)
pt.plot(y_sim_mean[:,0], y_sim_mean[:,1])
pt.plot(y_sim[:, 0, 0], y_sim[:, 1, 0])
pt.show()
Could someone give me a hint to how I get this working with cmdstanpy? Thank you so much in advance!
Operating System: Linux
Interface Version: pystan 3.4.0, cmdstanpy 1.0.1
Compiler/Toolkit: stan 2.29