Skip to content

Commit ef7fe3d

Browse files
authored
Merge pull request #222 from stan-dev/bmw/case-studies-updates
Update ODE conversion case study
2 parents 50b5378 + dc418b8 commit ef7fe3d

File tree

2 files changed

+33
-693
lines changed

2 files changed

+33
-693
lines changed

knitr/convert-odes/convert_odes.Rmd

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,18 @@ system function -- in the new interface none of this packing and unpacking
3636
is necessary.
3737

3838
The new interface also uses `vector` variables for the state rather than
39-
`real[]` variables.
39+
`array[] real` variables.
4040

4141
As an example, in the old solver interface the system function for the ODE
4242
$y' = -\alpha y$ would be written:
4343

44-
```{stan, output.var = "", eval = FALSE}
44+
```stan
4545
functions {
46-
real[] rhs(real t, real[] y, real[] theta, real[] x_r, int[] x_i) {
46+
array[] real rhs(real t, array[] real y, array[] real theta,
47+
array[] real x_r, array[] int x_i) {
4748
real alpha = theta[1];
4849
49-
real yp[1] = { -alpha * y[1] };
50+
array[1] real yp = {-alpha * y[1]};
5051
5152
return yp;
5253
}
@@ -100,7 +101,7 @@ The new `ode_bdf` solver interface is (the interfaces for `ode_adams` and
100101
`ode_rk45` are the same):
101102

102103
```{stan, output.var = "", eval = FALSE}
103-
vector[] ode_bdf(F f, vector y0, real t0, real[] times, ...)
104+
vector[] ode_bdf(F f, vector y0, real t0, array[] real times, ...)
104105
```
105106

106107
The arguments are:
@@ -144,7 +145,7 @@ The `ode_bdf_tol` interface is (the interfaces for `ode_rk45_tol`
144145
and `ode_adams_tol` are the same):
145146

146147
```{stan, output.var = "", eval = FALSE}
147-
vector[] ode_bdf_tol(F f, vector y0, real t0, real[] times,
148+
array[] vector ode_bdf_tol(F f, vector y0, real t0, array[] real times,
148149
real rel_tol, real abs_tol, int max_num_steps, ...)
149150
```
150151

@@ -193,7 +194,7 @@ The two models here come from the Stan
193194
### ODE System Function
194195

195196
In the old SIR system function, `beta`, `kappa`, `gamma`, `xi`, and `delta`,
196-
are packed into the `real[] theta` argument. `kappa` isn't actually a model
197+
are packed into the `array[] real theta` argument. `kappa` isn't actually a model
197198
parameter so it is not clear why it is packed in with the other parameters,
198199
but it is. Promoting `kappa` to a parameter causes there to be more states
199200
in the extended ODE sensitivity system (used to get gradients of the ODE
@@ -208,14 +209,11 @@ functions {
208209
// theta[3] = gamma, recovery rate
209210
// theta[4] = xi, bacteria production rate
210211
// theta[5] = delta, bacteria removal rate
211-
real[] simple_SIR(real t,
212-
real[] y,
213-
real[] theta,
214-
real[] x_r,
215-
int[] x_i) {
216-
real dydt[4];
217-
218-
dydt[1] = - theta[1] * y[4] / (y[4] + theta[2]) * y[1];
212+
array[] real simple_SIR(real t, array[] real y, array[] real theta,
213+
array[] real x_r, array[] int x_i) {
214+
array[4] real dydt;
215+
216+
dydt[1] = -theta[1] * y[4] / (y[4] + theta[2]) * y[1];
219217
dydt[2] = theta[1] * y[4] / (y[4] + theta[2]) * y[1] - theta[3] * y[2];
220218
dydt[3] = theta[3] * y[2];
221219
dydt[4] = theta[4] * y[2] - theta[5] * y[4];
@@ -230,7 +228,7 @@ rewritten to explicitly name all the parameters. No separation of data
230228
and parameters is necessary either -- the solver will not add more
231229
equations for arguments that are defined in the `data` and
232230
`transformed data` blocks. The state variables in the new model are also
233-
represented by `vector` variables instead of `real[]` variables.
231+
represented by `vector` variables instead of `array[]` variables.
234232
The new ODE system function is:
235233

236234
```{stan, output.var = "", eval = FALSE}
@@ -256,14 +254,14 @@ functions {
256254

257255
### Calling the ODE Solver
258256

259-
In the old ODE interface, the parameters are all packed into a `real[]` array
257+
In the old ODE interface, the parameters are all packed into a `array[] real`
260258
before calling the ODE solver:
261259

262260
```{stan, output.var = "", eval = FALSE}
263261
transformed parameters {
264-
real<lower=0> y[N_t, 4];
262+
array[N_t, 4] real<lower=0> y;
265263
{
266-
real theta[5] = {beta, kappa, gamma, xi, delta};
264+
array[5] real theta = {beta, kappa, gamma, xi, delta};
267265
y = integrate_ode_rk45(simple_SIR, y0, t0, t, theta, x_r, x_i);
268266
}
269267
}
@@ -272,11 +270,11 @@ transformed parameters {
272270
In the new ODE interface each of the arguments is appended on to the ODE
273271
solver function call. The RK45 ODE solver with default tolerances is called
274272
`ode_rk45`. Because the states are handled as `vector` variables, the solver
275-
output is an array of vectors (`vector[]`).
273+
output is an array of vectors (`array[] vector`).
276274

277275
```{stan, output.var = "", eval = FALSE}
278276
transformed parameters {
279-
vector<lower=0>[4] y[N_t] = ode_rk45(simple_SIR, y0, t0, t,
277+
array[N_t] vector<lower=0>[4] y = ode_rk45(simple_SIR, y0, t0, t,
280278
beta, kappa, gamma, xi, delta);
281279
}
282280
```
@@ -285,7 +283,7 @@ The `ode_rk45_tol` function can be used to specify tolerances manually:
285283

286284
```{stan, output.var = "", eval = FALSE}
287285
transformed parameters {
288-
vector<lower=0>[4] y[N_t] = ode_rk45_tol(simple_SIR, y0, t0, t,
286+
array[N_t] vector<lower=0>[4] = ode_rk45_tol(simple_SIR, y0, t0, t,
289287
1e-6, 1e-6, 1000,
290288
beta, kappa, gamma, xi, delta);
291289
}
@@ -308,12 +306,10 @@ In the old system function, parameters are manually unpacked from `theta` and
308306

309307
```{stan, output.var = "", eval = FALSE}
310308
functions {
311-
real[] one_comp_mm_elim_abs(real t,
312-
real[] y,
313-
real[] theta,
314-
real[] x_r,
315-
int[] x_i) {
316-
real dydt[1];
309+
array[] real one_comp_mm_elim_abs(real t, array[] real y,
310+
array[] real theta, array[] real x_r,
311+
array[] int x_i) {
312+
array[1] real dydt;
317313
real k_a = theta[1]; // Dosing rate in 1/day
318314
real K_m = theta[2]; // Michaelis-Menten constant in mg/L
319315
real V_m = theta[3]; // Maximum elimination rate in 1/day
@@ -322,8 +318,9 @@ functions {
322318
real dose = 0;
323319
real elim = (V_m / V) * y[1] / (K_m + y[1]);
324320
325-
if (t > 0)
326-
dose = exp(- k_a * t) * D * k_a / V;
321+
if (t > 0) {
322+
dose = exp(-k_a * t) * D * k_a / V;
323+
}
327324
328325
dydt[1] = dose - elim;
329326
@@ -365,14 +362,14 @@ the `x_i` argument is required even though it isn't used:
365362

366363
```{stan, output.var = "", eval = FALSE}
367364
transformed data {
368-
real x_r[2] = {D, V};
369-
int x_i[0];
365+
array[2] real x_r = {D, V};
366+
array[2] int x_i;
370367
}
371368
...
372369
transformed parameters {
373-
real C[N_t, 1];
370+
array[N_t, 1] real C;
374371
{
375-
real theta[3] = {k_a, K_m, V_m};
372+
array[3] real theta = {k_a, K_m, V_m};
376373
C = integrate_ode_bdf(one_comp_mm_elim_abs, C0, t0, times, theta, x_r, x_i);
377374
}
378375
}
@@ -383,7 +380,7 @@ In the new interface the arguments are simply passed at the end of the
383380

384381
```{stan, output.var = "", eval = FALSE}
385382
transformed parameters {
386-
vector[1] mu_C[N_t] = ode_bdf(one_comp_mm_elim_abs, C0, t0, times,
383+
array[N_t] vector[1] mu_C = ode_bdf(one_comp_mm_elim_abs, C0, t0, times,
387384
k_a, K_m, V_m, D, V);
388385
}
389386
```
@@ -392,7 +389,7 @@ The `ode_bdf_tol` function can be used to specify tolerances manually:
392389

393390
```{stan, output.var = "", eval = FALSE}
394391
transformed parameters {
395-
vector[1] mu_C[N_t] = ode_bdf_tol(one_comp_mm_elim_abs, C0, t0, times,
392+
array[N_t] vector[1] mu_C = ode_bdf_tol(one_comp_mm_elim_abs, C0, t0, times,
396393
1e-8, 1e-8, 1000,
397394
k_a, K_m, V_m, D, V);
398395
}

0 commit comments

Comments
 (0)