Fazang
now supports ODE sensitivity solution (based on CVODES
) with respect to given parameters
without explicitly asking for Jacobian. For that the user-defined ODE must include right-hand-side (RHS) definitions for var
type and real
types, due to the lack of meta-programming.
User-defined RHS would be like this.
module ode_mod
use fazang
use, intrinsic :: iso_c_binding
implicit none
real(rk), parameter :: omega = 0.5d0
real(rk), parameter :: d1 = 1.0d0
real(rk), parameter :: d2 = 1.0d0
contains
! right-hand-side for data input
subroutine eval_rhs(t, y, fy)
implicit none
real(c_double), intent(in) :: t, y(:)
real(c_double), intent(inout) :: fy(size(y))
fy(1) = y(2)
fy(2) = sin(omega * d1 * d2 * t)
end subroutine eval_rhs
! right-hand-side for var input with parameters
! y, p, and output fy must all be of var type
subroutine eval_rhs_pvar(t, y, fy, p)
implicit none
real(c_double), intent(in) :: t
type(var), intent(in) :: y(:), p(:)
type(var), intent(inout) :: fy(size(y))
fy(1) = y(2)
fy(2) = sin(p(1) * p(2) * p(3) * t)
end subroutine eval_rhs_pvar
end module ode_mod
Now we can solve the defined ODE
program cvodes_demo
use ode_mod
use fazang
implicit none
type(var) :: yt(2, 3)
type(cvodes_tol) :: tol
real(rk), parameter :: ts(3) = [1.2d0, 2.4d0, 4.8d0]
real(rk), parameter :: y00(2) = [0.2d0, 0.8d0]
type(var) :: param(3)
real(rk) :: y0(2), ga(2)
integer :: i, j
y0 = y00 ! init condition
param = var([omega, d1, d2]) ! parameters
tol = cvodes_tol(CV_BDF, 1.d-10, 1.d-10, 1000_8)
yt = cvodes_sol(0.d0, y0, ts, param, eval_rhs,&
& eval_rhs_pvar, tol)
! ...
end program cvodes_demo
Note that the call to cvodes_sol
includes parameter argument param
and two RHS functions, one for real
input and one for var
input.
The sensitivities are obtained the same way by calling grad
and adj
on the output and input, respectively.
call yt(1, 1) % grad()
write(*, *) "dy_1/ d_omega at time ts(1):", param(1)%adj()