当 运行 一起时,ODE 求解 运行 缓慢
ODE Solvers Running Slowly When Ran Together
我有一个 class 的一些 ODE 求解器的自定义实现。我遇到了一个问题,如果我使时间步 dt
小于 .2
,程序就会停止。但是,如果我注释掉其中一个 Runge-Kutta 解算器,它会执行得非常快,而且我可以切换注释掉的解算器,这样我就可以从两个解算器中获得解。我想知道如何解决这个问题。我一直在尝试找到一种解决方案可能会干扰另一个的方法,但我不明白这是怎么发生的。
实施:
global dt;
dt = .5; % going below ~.25 makes the program take a very long time to exit
g = 1;
c_d = 2;
m = 3;
tf = 15;
dudt = @(t, u) g - (c_d/m) * u.^2
[t_euler, u_euler] = euler(dudt, [0, tf], 0);
[t_rk4, u_rk4] = rk4(dudt, [0, tf], 0); % either of this one or rk2
% can be commented out to make the program
% run quickly, but rk2 and rk4 cannot be
% run at the same time
[t_rk2, u_rk2] = rk2(dudt, [0, tf], 0);
%% rk4.m %%
function [t, u] = rk4(odefun, tspan, u0)
t0 = tspan(1);
t = [ t0 ];
t_new = t0;
global dt;
tf = tspan(2);
u_new = u0;
u = [ u0 ];
while (t_new < tf)
if (t_new + dt > tf)
dt = tf - t_new;
end
k1 = dt * odefun(t_new, u_new);
k2 = dt * odefun(t_new + dt/2, u_new + k1/2);
k3 = dt * odefun(t_new + dt/2, u_new + k2/2);
k4 = dt * odefun(t_new + dt, u_new + k3);
u_new = u_new + 1/6 * (k1 + 2*k2 + 2*k3 + k4);
% rk2.m is the same as rk4.m, except u_new = u_new + k2
% euler.m is also the same, except u_new = u_new + k1
u = [ u, u_new ];
t_new = t_new + dt;
t = [ t, t_new ];
end
end
当计算最后一步的区间长度正好满足 tf
时,你减少了全局变量 dt
,而在另一种方法中 dt
现在更小的值是用过的。有了你的数据,你的新 dt
可能会小到 1e-16
甚至 0
.
您想将全局 dt
视为常量,也许使用局部变量 h
而不是 dt
。或者传递 dt
作为函数的参数。
我有一个 class 的一些 ODE 求解器的自定义实现。我遇到了一个问题,如果我使时间步 dt
小于 .2
,程序就会停止。但是,如果我注释掉其中一个 Runge-Kutta 解算器,它会执行得非常快,而且我可以切换注释掉的解算器,这样我就可以从两个解算器中获得解。我想知道如何解决这个问题。我一直在尝试找到一种解决方案可能会干扰另一个的方法,但我不明白这是怎么发生的。
实施:
global dt;
dt = .5; % going below ~.25 makes the program take a very long time to exit
g = 1;
c_d = 2;
m = 3;
tf = 15;
dudt = @(t, u) g - (c_d/m) * u.^2
[t_euler, u_euler] = euler(dudt, [0, tf], 0);
[t_rk4, u_rk4] = rk4(dudt, [0, tf], 0); % either of this one or rk2
% can be commented out to make the program
% run quickly, but rk2 and rk4 cannot be
% run at the same time
[t_rk2, u_rk2] = rk2(dudt, [0, tf], 0);
%% rk4.m %%
function [t, u] = rk4(odefun, tspan, u0)
t0 = tspan(1);
t = [ t0 ];
t_new = t0;
global dt;
tf = tspan(2);
u_new = u0;
u = [ u0 ];
while (t_new < tf)
if (t_new + dt > tf)
dt = tf - t_new;
end
k1 = dt * odefun(t_new, u_new);
k2 = dt * odefun(t_new + dt/2, u_new + k1/2);
k3 = dt * odefun(t_new + dt/2, u_new + k2/2);
k4 = dt * odefun(t_new + dt, u_new + k3);
u_new = u_new + 1/6 * (k1 + 2*k2 + 2*k3 + k4);
% rk2.m is the same as rk4.m, except u_new = u_new + k2
% euler.m is also the same, except u_new = u_new + k1
u = [ u, u_new ];
t_new = t_new + dt;
t = [ t, t_new ];
end
end
当计算最后一步的区间长度正好满足 tf
时,你减少了全局变量 dt
,而在另一种方法中 dt
现在更小的值是用过的。有了你的数据,你的新 dt
可能会小到 1e-16
甚至 0
.
您想将全局 dt
视为常量,也许使用局部变量 h
而不是 dt
。或者传递 dt
作为函数的参数。