Skip to content

pass user jacobian to cvode #79

Closed
Closed
@gasagna

Description

@gasagna

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions