Description
Hi,
I am looking to implement the required code to pass the rhs jacobian to sundials to avoid expensive finite-difference approximations. According to the example cvde_Roberts_dns.jl
, at line 26 (this link) this needs implementing a wrapper from Sundials._DlsMat
to Matrix
and the user jacobian wrapper.
My strategy for the latter is as follows:
# Type to store user rhs and jacobian, no data are provided,
# as these can be defined using efficient closures in v0.5.
type FunJac{F, J}
fun::F
jac::J
end
funjac(f, J) = FunJac(f, J)
function cvodefunjac(t::Float64,
x::N_Vector,
ẋ::N_Vector,
funjac::FunJac)
funjac.fun(t, convert(Vector, x), convert(Vector, ẋ))
return CV_SUCCESS
end
function cvodefunjac(N::Clong,
t::realtype,
x::N_Vector,
ẋ::N_Vector,
J::DlsMat,
userjac::FunJac,
tmp1::N_Vector,
tmp2::N_Vector,
tmp3::N_Vector)
funjac.jac(t, convert(Matrix, J), convert(Vector, x))
return CV_SUCCESS
end
i.e. the same FunJac
type is used to store the rhs and the jacobian. Appropriate julia callbacks are then defined for the rhs and jacobian using cfunction
and dispatch, along the lines of:
fun = cfunction(cvodefunjac,
Cint,
(realtype,
N_Vector,
N_Vector,
Ref{typeof(funjac)}))
jac = cfunction(cvodefunjac,
Cint,
(Clong,
realtype,
N_Vector,
N_Vector,
DlsMat,
Ref{typeof(funjac)},
N_Vector,
N_Vector,
N_Vector))
ynv = NVector(copy(x₀))
CVodeInit(mem, fun, 0.0, convert(N_Vector, ynv))
CVodeSetUserData(mem, funjac)
CVDlsSetDenseJacFn(mem, jac)
Now the missing piece is how to define the convert(::Type{Matrix}, J::DlsMat)
method called in the jacobian. Any pointers (no pun intended) are welcome. Is the code in cvode_Roberts_dns.jl
a valid approach? It looks beyond my CJulia-fu skills...
I am actually writing this as part of a personal package but could contribute it to Sundials if requested.