3
votes

When the solution of ODE45 diverges (doesn't matter why and how), the following warning will be displayed, and the solver can not continue:

Warning: Failure at t=8.190397e+01. Unable to meet integration tolerances without reducing the step size below the smallest value allowed (2.273737e-13) at time t.

I am running ode45 on a matrix (lots of inputs), so I want to find out automatically for which inputs the above condition(failure) happens. I mean, Is there any other sign of this condition returned by ode45 that can be written in an array automatically? Something that can be used in a if statment as:

if {some variable is returned/is equal to ...} then {the solver has failed}

to identify those faulty inputs automatically without looking for the displayed warning.

2
A simple example that demonstrates the issue: [t,y]=ode45(@(t,y)[y(1)^2;y(2)],[0 1],[1;1]);. The two equations are independent. The first has a growth rate that causes the step size to become very small. In turn this causes ode45 to eventually abort. I guess the question is how one could write their ODE function to determine that this is going to happen, but avoid it by zeroing out an equation before the step size get too small? Obviously there would be no solution to the zeroed out equation, but ode45 could continue on its merry way and obtain full solutions for the remaining elements.horchler
@horchler I added more explanation. Now, I must check each individual input and see if ode45 fails or not (by looking for the displayed warning). I want another sign that can be dealt with automatically; say, by writing an if statement and checking for the failure at each run.Mostafa

2 Answers

4
votes

You can turn that warning into an error, and errors can be caught by try/catch blocks.

An example:

% Change this particular warning into an error
warnId = 'MATLAB:ode45:IntegrationTolNotMet';
warnstate = warning('error', warnId);    

% That can be caught with try/catch
try     
    % Quick-failing integration, suggested by horchler
    [t,y] = ode45(@(t,y)[y(1)^2;y(2)],[0 1],[1;1]);

catch ME
    % Check if we indeed failed on meeting the tolerances
    if strcmp(ME.identifier, warnId)

        % DO YOUR STUFF HERE

    else
        % Something else has gone wrong: just re-throw the error
        throw(ME);
    end

end

% Don't forget to reset the warning status
warning(warnstate);

You can get the warnId of any warning by virtue of the lastwarn command. For errors, see lasterr.

0
votes

Another method would be to just check for how much time ode45 was able to run. for example if you run

[x,t] = ode45(@some_ode,[t0,tf],x0);

then after this line is executed, simply check the value of t(end). If t(end)==tf, then ode45 did its job, otherwise there was a failure