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?
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
.
来源:https://stackoverflow.com/questions/25581901/stop-integration-after-designated-length-of-time-in-matlab