13.3 Coding the ODE system function
The first step in coding an ODE system in Stan is defining the ODE system function. The system functions require a specific signature so that the solvers know how to use them properly.
The first argument to the system function is time, passed as a real
;
the second argument to the system function is the system state,
passed as a vector
, and the return value from the system function are the
current time derivatives of the state defined as a vector
. Additional arguments
can be included in the system function to pass other information
into the solve (these will be passed through the function that starts the ODE
integration). These argument can be parameters (in this case, the friction
coefficient), data, or any quantities that are needed to define the
differential equation.
The simple harmonic oscillator can be coded using the following function in Stan (see the user-defined functions chapter for more information on coding user-defined 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;
}
The function takes in a time t
(a real
), the system state
y
(a vector
), and the parameter theta
(a real
). The function returns a
vector
of time derivatives of the system state at time t
, state y
, and
parameter theta
. The simple harmonic oscillator coded here does not have
time-sensitive equations; that is, t
does not show up in the definition of
dydt
, however it is still required.
Strict signature
The types in the ODE system function are strict. The first argument is the time
passed as a real
, the second argument is the state passed as a vector
,
and the return type is a vector
. A model that does not have this signature will
fail to compile. The third argument onwards can be any type, granted all
the argument types match the types of the respective arguments in the solver
call.
All of these are possible ODE signatures:
vector myode1(real t, vector y, real a0);
vector myode2(real t, vector y, array[] int a0, vector a1);
vector myode3(real t, vector y, matrix a0, array[] real a1, row_vector a2);
but these are not allowed:
vector myode1(real t, array[] real y, real a0);
// Second argument is not a vector
array[] real myode2(real t, vector y, real a0);
// Return type is not a vector
vector myode3(vector y, real a0);
// First argument is not a real and second is not a vector