DifferentialEquations.jl: Exception thrown in callback of solve command that is handled by a try-catch block inside another solve command causes the outer solve command to fail

Hi there :slight_smile:
Please post code enclosed in ``` to make it a lot more readable.

While I am not sure about your problem specifically, your MWE does have several issues I’d like to address:

Module loading

You should load modules at toplevel and not via @eval. Using @eval using ... basically makes performant code impossible and make everything much more inconvenient (e.g. you need to use invokelatest).

Undefined variables

Your MWE uses the variable x_first_callback but it is never defined. You probably meant test_callback. However…

Wrong construction of DiscreteCallback

you never arrive there because your code errors on constructing the DiscreteCallback. You wrote:

test_callback = DiscreteCallback(example_callback, sqrt(-1))

This fails immediately with DomainError because you compute sqrt(-1) before even constructing the callback! You probably forgot to make it an anonymous function like so:

test_callback = DiscreteCallback(example_callback, (integrator) -> sqrt(-1))

This perhaps also explains why the “outer” solver fails: You never catch your exception because it is thrown outside the try-catch that was intended to catch it.

Your improved MWE doesn’t have this problem because test_callback is constructed correctly.

It is unclear to me what the consequence of a failure of the inner solver for the outer solver should be so I can’t recommend a good way to solve your original problem. I suggest you open a new thread where you explain the structure of the problem you want to solve and then likely someone knowledgeable will pop in, explaining how to handle your case in the best way :slight_smile:

Here is a suggestion of how your MWE code could look like (where I also fixed some other issues your code had):

module julia_try_catch_ode

using DifferentialEquations

function run()
    dfdt_0 = [0.0]
    tbounds = (0.0, 5.0) # tuple is preferred
    dfdt_prob = ODEProblem(dfdt!, dfdt_0, tbounds)
    dfdt_sol = solve(dfdt_prob)
end

function dfdt!(df, f, p, t) # mutating function get a ! in Julia
    # df = [-1.0] # this doesn't overwrite df
    df[1] = -1.0
    internal_IC = [0.0]
    internal_bounds = (0.0, 5.0)
    test_callback = DiscreteCallback((_,_,_)->true, (_)->sqrt(-1))
    internal_prob = ODEProblem(dfdt_2, internal_IC, internal_bounds)
    try
        doomed_solve = solve(internal_prob, callback = test_callback)
    catch e
        # internal solve failed
        # what does that mean for the outer solve?
    end
    # return df # no need to return
end

function dfdt_2(df, f, p, t)
    # df = [-1.0] # this doesn't overwrite df
    df[1] = -1.0
end

run()
end
3 Likes