Controller
Controller

Reputation: 529

Stop integration after designated length of time in Matlab

I want to stop solving a differential equation in Matlab if it takes more than a designated amount of time. I tried the following,but it doesn't work...

    options = odeset('AbsTol',1e-8,'RelTol',1e-5);
    RUNTIME=5;
    timerID = tic;
    while (toc(timerID) < RUNTIME)
        [t_pae,x_th_pae] = ode15s(@prosomoiwsh,[0 t_end],[80*pi/180;0;130*pi/180;0;th_initial(1);th_initial(2);th_initial(3);th_initial(4)],options);
    end

How can I solve this?

UPDATE : I tried what horchler suggested and now my code looks like this :

    interupt_time = 20;
    outputFun= @(t,y,flag)interuptFun(t,y,flag,interupt_time);
    options = odeset('AbsTol',1e-5,'RelTol',1e-5,'OutputFcn',outputFun);

    try
        [t_pae,x_b_th_pae] = ode15s(@prosomoiwsh,[0 t_end],[0;0;0;th_initial(1);th_initial(2);th_initial(3);th_initial(4);th_initial(5);th_initial(6);th_initial(7);th_initial(8);th_initial(9);th_initial(10);th_initial(11);th_initial(12)],options);
        u_pae=compute_input(epsilon,ke,kv,dD,IwF,IwG,IwD,IbF,IbG,IbD,p,m,t_pae,x_b_th_pae);  
    catch ME
        if strcmp(ME.identifier,'interuptFun:Interupt')
            disp(ME.message);
            input('got caught')
        else
            rethrow(ME); % It's possible the error was due to something else
        end
    end

   function dx_b_th = prosomoiwsh(t,x_b_th)
   ...
   end

The outputFun is exactly the same as the one horchler suggested. But now it times out every single time,while previously this only happened occasionally. What am I doing wrong?

Upvotes: 1

Views: 1811

Answers (1)

horchler
horchler

Reputation: 18484

First, you can't do anything like what you're trying. All that will happen is that ode15s will run for as long as it needs and return it's result as usual. You need a way of interrupting the ODE solver in the middle of its execution when a certain designated amount of time has been exceeded. Unfortunately, you didn't provide runnable code, so I'll have to provide general suggestions that you can adapt to your problem.

One way to do this is via an Output function. This is a function that gets called after every (successful) integration step of a Matlab solver. There are are several examples of Output functions that you can examine the code of to see what you can do: odeplot, odeprint, odephas2, and odephas3. Just type edit odeplot in your command window to see the code.

Below is an example of how you might use this capability using the built-in example function vdp1000 that's referred to in the help for ode15s. You need to create a persistent variable to save the initial time, initialize it, and then check the elapsed time relative to a parameter that you pass in. Then you throw an error to abort ode15s if the elapsed time exceeds the designated value. A try-catch statement can be used to catch the error.

function ode_interupt_demo

tspan = [0 3000]; y0 = [2;0];
interupt_time = 0.05;
outputFun= @(t,y,flag)interuptFun(t,y,flag,interupt_time);
opts = odeset('AbsTol',1e-8,'RelTol',1e-5,'OutputFcn',outputFun);

try
    [t,y] = ode15s(@vdp1000,tspan,y0,opts);
catch ME
    if strcmp(ME.identifier,'interuptFun:Interupt')
        disp(ME.message);
        % Do other things
    else
        rethrow(ME); % It's possible the error was due to something else
    end
end


function status = interuptFun(t,y,flag,interupt_time)   %#ok<INUSL>
persistent INIT_TIME;
status = 0;
switch(flag)
    case 'init'
        INIT_TIME = tic;
    case 'done'
        clear INIT_TIME;
    otherwise
        elapsed_time = toc(INIT_TIME);
        if elapsed_time > interupt_time
            clear INIT_TIME;
            str = sprintf('%.6f',elapsed_time);
            error('interuptFun:Interupt',...
                 ['Interupted integration. Elapsed time is ' str ' seconds.']);
        end
end

One disadvantage of this approach is that you will not get a return value from ode15s. This may or may not be desirable in your application. There are likely ways around this, but they'll require more code. One easy thing that you can do is have the error message return the last time and state of the system (when it was interrupted) using the t and y values passed into the output function. It's also possible that Event functions could be used to terminate integration based on elapsed time – those might allow you to still return output from ode15s.

Upvotes: 4

Related Questions