16.4 Coding the DAE system function
The first step in coding an DAE system in Stan is defining the DAE residual function. The system functions require a specific signature so that the solvers know how to use them properly.
The first argument to the residual function is time, passed as a real
;
the second argument to the residual function is the system state \(y\),
passed as a vector
, the third argument to the residual function is
the state derivative \(y'\), also passed as a vector
. The residual
function’s return value is a vector
of the same size as state and
stae derivatives. Additional arguments
can be included in the residual function to pass other information
into the solve (these will be passed through the function that starts the DAE
solution). These argument can be parameters (in our example, the
reaction rate coefficient \(\alpha\), \(\beta\), and \(\gamma\)), data, or any quantities that are needed to define the
DAE.
The above reaction be coded using the following function in Stan (see the user-defined functions chapter for more information on coding user-defined functions).
vector chem(real t, vector yy, vector yp,
real alpha, real beta, real gamma) {
vector[3] res;
1] = yp[1] + alpha * yy[1] - beta * yy[2] * yy[3];
res[2] = yp[2] - alpha * yy[1] + beta * yy[2] * yy[3] + gamma * yy[2] * yy[2];
res[3] = yy[1] + yy[2] + yy[3] - 1.0;
res[return res;
} }
The function takes in a time t
(a real
), the system state
yy
(a vector
), state derivative yp
(a vector
), as well as parameter
alpha
(a real
), beta
(a real
), and gamma
(a real
). The function returns a
vector
of the residuals at time t
. The DAE coded here does not
explicitly depend on t
, however one still needs to specify t
as
an argument.
Strict signature
The types in the DAE residual function are strict. The first argument is the time
passed as a real
, the second argument is the state passed as a vector
,
the third argument is the state derivative passed as a vector
,
and the return type is a vector
. A model that does not have this signature will
fail to compile. The fourth 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 DAE signatures:
vector my_dae1(real t, vector y, vector yp, real a0);
vector my_dae2(real t, vector y, vector yp, array[] int a0, vector a1);
vector my_dae3(real t, vector y, vector yp, matrix a0, array[] real a1, row_vector a2);
but these are not allowed:
vector my_dae1(real t, array[] real y, vector yp);
// Second argument is not a vector
array[] real my_dae2(real t, vector y, vector yp);
// Return type is not a vector
vector my_dae3(real t, vector y);
// First argument is not a real and missing the third argument