I am having trouble with taking a sparse, analytical Jacobian generated in ModelingToolkit and passing it to my Sundials IDA solver. Here is an MWE adapted from a previous question.
Running this segment of code with a pre-defined analytical Jacobian works (for some reason, running this code only works about every other time).
using Sundials
using ODEInterfaceDiffEq
using ODEInterface
p=[-2,1.2,-1.0]
function f!(res,du,u,p,t)
res[1] = du[1] - p[1] * u[1] + p[2] * u[1]*u[2]
res[2] = du[2] -p[3] * u[2] - u[1]*u[2]
res[3]= u[2] + u[1] - u[3]
end
function g!(J,du,u,p,gamma,t)
J[1,1] = gamma - p[1] + p[2] * u[2]
J[1,2] = p[2]* u[1]
J[1,3] = 0
J[2,1] = - 1 * u[2]
J[2,2] = gamma - p[3] - u[1]
J[2,3] = 0
J[3,1] = 1
J[3,2] = 1
J[3,3] = -1
nothing
end
fg1 = DAEFunction(f!;jac=g!)
dIC=[0.8,2]
IC =[1.0,1.0,2.0]
tspan=(0.0,10.0)
diff_vars = [true,true, false]
prob = DAEProblem(fg1,dIC,IC,tspan,p,differential_vars=diff_vars)
sol = solve(prob,IDA())
using Plots
plot(sol, layout=(3,1), label=["DAE X1" "DAE X2" "DAE X3"], lw=3)
However, when I try to generate the same Jacobian as a sparse Jacobian using ModelingToolkit, I get errors
# generating the sparse jacobian using ModelingtoolKit
using ModelingToolkit, SparseArrays
@variables u[1:3] du[1:3] γ
res = similar(u)
t = 0.0
f!(res, du, u, p, t)
# need to combine d(res)/du + γ.*d(res)/d(du)
J_u = ModelingToolkit.jacobian(res, u)
J_du = γ.*ModelingToolkit.jacobian(res, du)
J = similar(J_u)
for i in 1:length(J_u)
J[i] = simplify(J_u[i] + J_du[i])
end
J_func! = eval(build_function(sparse(J), u, γ)[2])
function gnew!(J,du,u,p,gamma,t)
J_func!(J, u, gamma)
nothing
end
jac_prototype = sparse([1.0 1 0; 1 1 0; 1 1 1])
# solving the DAE
fg2 = DAEFunction(f!;jac=gnew!)
probMTK = DAEProblem(fg2,dIC,IC,tspan,p,differential_vars=diff_vars,jac_prototype = jac_prototype)
solMTK = solve(probMTK,IDA())
with the error type Array has no field nzval
. If I use solMTK = solve(probMTK,IDA(;linear_solver=:KLU))
, I get the error MethodError: no method matching nonzeros(::Nothing)
. What am I doing wrong?
As a side note: I would strongly prefer using Sundials to solve my real system.