# Making Enzyme.jl work with the integrator interface of OrdinaryDiffEq.jl

**URL:** <https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186>\
**Category:** New to Julia\
**Tags:** ordinarydiffeq, enzyme\
**Created:** [February 22, 2025, 3:33pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186 "2025-02-22T15:33:40Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rittick\_Roy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rittick_roy/32/211584_2.png) [@Rittick\_Roy](https://discourse.julialang.org/u/Rittick_Roy)\
**Post date:** [February 22, 2025, 3:33pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/1 "2025-02-22T15:33:40Z")

</div>

I’m new to using autodiff in Julia and have some issues making Enzyme.jl work with OrdinaryDiffEq.jl. I want to take the a reverse mode derivative of my differential equation solution with respect to the input parameter p. This is a simple example, but in my actual model I need the integrator interface of OrdinaryDiffEq as well, so I am looking for a solution to make Enzyme work in reverse mode with the integrator interface. Here is my implementation:

```julia
using OrdinaryDiffEq
using Enzyme
using SciMLSensitivity

function fun(u, p, t)
    return -p[1] * t
end

function test_fun(p; kwargs...)
    u0 = 2.0
    tspan = (1.0, 2.0)
    prob = ODEProblem{false}(fun, u0, tspan, p)
    integrator = OrdinaryDiffEq.init(prob, OrdinaryDiffEq.RK4(), save_everystep = false; kwargs...)
    sol = solve!(integrator).u[2]
    return sol

end

p = [1.0]
dp = [0.0]
y = [0.0]
dy = [1.0]
Enzyme.autodiff(Reverse, test_fun, Duplicated(p, dp), Duplicated(y, dy))

```

I have tried multiple iterations for this, but nothing seems to work. Any inputs would be helpful!

---

<div class="post-metadata">

**Author:** ![kylebeggs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kylebeggs/32/43348_2.png) [@kylebeggs](https://discourse.julialang.org/u/kylebeggs)\
**Post date:** [February 22, 2025, 4:27pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/2 "2025-02-22T16:27:40Z")

</div>

You can definitely do this with Enzyme, but I suggest using DIfferentiationInterface.jl with the Enzyme backend. I find that APi to be more intuitive and you also get access to use other backends for free.

---

<div class="post-metadata">

**Author:** ![yolhan\_mannes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yolhan_mannes/32/220485_2.png) [@yolhan\_mannes](https://discourse.julialang.org/u/yolhan_mannes)\
**Post date:** [February 22, 2025, 4:44pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/3 "2025-02-22T16:44:12Z")

</div>

Works fine on 1.10, seems to be a 1.11 issue which are typical in Enzyme, as you, did not find a workaround

---

<div class="post-metadata">

**Author:** ![Rittick\_Roy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rittick_roy/32/211584_2.png) [@Rittick\_Roy](https://discourse.julialang.org/u/Rittick_Roy)\
**Post date:** [February 22, 2025, 4:59pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/4 "2025-02-22T16:59:17Z")

</div>

@kylebeggs Thanks for the tip, that’ll be useful

@yolhan_mannes Can you let me know the exact version of Julia you used to execute it, the version of Enzyme, OrdinaryDiffEq and SciMLSensitivity?

---

<div class="post-metadata">

**Author:** ![yolhan\_mannes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yolhan_mannes/32/220485_2.png) [@yolhan\_mannes](https://discourse.julialang.org/u/yolhan_mannes)\
**Post date:** [February 22, 2025, 5:00pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/5 "2025-02-22T17:00:46Z")

</div>

Julia Version 1.10.8  
[7da242da] Enzyme v0.13.30  
[1dea7af3] OrdinaryDiffEq v6.91.0  
[1ed8b502] SciMLSensitivity v7.74.0

I also changed your code a little while trying to make it work on 1.11 (did not make it : issue [SciMLSensitivity + Enzyme + 1.11 issue · Issue #2318 · EnzymeAD/Enzyme.jl · GitHub](https://github.com/EnzymeAD/Enzyme.jl/issues/2318)),

```julia
using OrdinaryDiffEq
using Enzyme
using SciMLSensitivity

function fun(du,u, p, t)
    du .= -p[1] * t
    nothing
end

function test_fun(p,prob)
    prob = remake(prob, p=p)
    sol = solve(prob,RK4(),save_everystep=false)
    res = sol.u[2]
    return res[1]
end

p = [1.0]
dp = [0.0]
u0 = [2.0]
prob = ODEProblem{true}(fun, u0, (1.0, 2.0), p)
dprob = Enzyme.make_zero(prob)

Enzyme.autodiff(Enzyme.Reverse, test_fun, Duplicated(p, dp),DuplicatedNoNeed(prob,dprob))
@info dp

```

The only thing that you can’t go around is making u0 a vector I think, because SciMLSensitivity needs to go through your du (must be a Ref), also always diff a remake not the original ODEProblem creation, it may work but its really not beautiful this way. You could go back to an explicit def for “fun” but since I made u0 a vector its better to avoid it

---

<div class="post-metadata">

**Author:** ![Rittick\_Roy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rittick_roy/32/211584_2.png) [@Rittick\_Roy](https://discourse.julialang.org/u/Rittick_Roy)\
**Post date:** [February 22, 2025, 5:17pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/6 "2025-02-22T17:17:45Z")

</div>

@yolhan_mannes Thank you so much! It was indeed a version issue, seems to be working with just 1.10

---

<div class="post-metadata">

**Author:** ![Rittick\_Roy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rittick_roy/32/211584_2.png) [@Rittick\_Roy](https://discourse.julialang.org/u/Rittick_Roy)\
**Post date:** [February 22, 2025, 5:52pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/7 "2025-02-22T17:52:12Z")

</div>

@yolhan_mannes Adding to this, do you have an idea how to make it work with the integrator interface? Because it seems to work with the direct solve, but not when I try to use the integrator interface

---

<div class="post-metadata">

**Author:** ![yolhan\_mannes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yolhan_mannes/32/220485_2.png) [@yolhan\_mannes](https://discourse.julialang.org/u/yolhan_mannes)\
**Post date:** [February 22, 2025, 6:16pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/8 "2025-02-22T18:16:43Z")

</div>

What about it using a callback to interface with it ? Also, do you have an exemple of kw pass to the init and not pass to solve ?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [February 23, 2025, 12:04pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/9 "2025-02-23T12:04:06Z")

</div>

With enzyme that is not fully supported yet. I hope to change that in the next few months but it will take a bit, and there are certain trade offs with that

---

<div class="post-metadata">

**Author:** ![Rittick\_Roy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rittick_roy/32/211584_2.png) [@Rittick\_Roy](https://discourse.julialang.org/u/Rittick_Roy)\
**Post date:** [February 24, 2025, 5:45pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/10 "2025-02-24T17:45:21Z")

</div>

@yolhan_mannes I’m not exactly sure what you meant, but I need to solve the differential equation one step at a time, perform some calculation, and then move to the next step. I could do save\_everystep = true, and then store the solution, and perform the calculation later, but this is slower and hence I use the step! function from the integrator interface.

@ChrisRackauckas Hi Chris! Thanks for the update. Is the integrator interface supported with other packages such as Zygote, or ReverseDiff?

---

<div class="post-metadata">

**Author:** ![jClugstor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jclugstor/32/32689_2.png) [@jClugstor](https://discourse.julialang.org/u/jClugstor)\
**Post date:** [February 24, 2025, 6:25pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/11 "2025-02-24T18:25:50Z")

</div>

You might be able to use a discrete callback for that:

> **[Event Handling and Callback Functions · DifferentialEquations.jl](https://docs.sciml.ai/DiffEqDocs/stable/features/callback_functions/)**
>
> Documentation for DifferentialEquations.jl.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [February 25, 2025, 1:30pm UTC](https://discourse.julialang.org/t/making-enzyme-jl-work-with-the-integrator-interface-of-ordinarydiffeq-jl/126186/12 "2025-02-25T13:30:33Z")

</div>

> [@Rittick\_Roy](#):
>
> @ChrisRackauckas Hi Chris! Thanks for the update. Is the integrator interface supported with other packages such as Zygote, or ReverseDiff?

Zygote no, ReverseDiff only in slow scalar mode. So Enzyme is really needed for performance here. It’s fundamental to the AD libraries.

> [@Rittick\_Roy](#):
>
> I’m not exactly sure what you meant, but I need to solve the differential equation one step at a time, perform some calculation, and then move to the next step. I could do save\_everystep = true, and then store the solution, and perform the calculation later, but this is slower and hence I use the step! function from the integrator interface.

That can be done with a discrete callback.
