scipy积分器在积分时采用两个参数:(1)step
告诉积分器只采取一个步骤,(2)relax
告诉积分器可以步进超过最后时间点。
我想采取措施(以便我可以收集整个解决方案),但也没有超过最后一次(因为我在我的真正问题中存在不连续性)。但是,step
True
似乎忽略relax
为False
。放弃最后一次将需要一步。
这是一个说明问题的简单示例:
from scipy.integrate import ode
obj = ode(lambda t, y: -y) # Simple exponential decay
obj.set_initial_value(4.0)
final_time = 2.0
ts_new = []
ys_new = []
# Take one step at a time until the final time is reached
while obj.t < final_time:
y_new = obj.integrate(final_time, step=True, relax=False)
ts_new.append(obj.t)
ys_new.append(y_new)
print(ts_new[-1]) # 2.073628416585726
我原本期望最后一步是部分步骤(是什么叫它?)并完全停在final_time
上,例如obj.integrate(final_time, step=False, relax=False)
给出的值。除了重新运行整个ODE之外,有没有办法获得最后一点?我可以在最后一步之前将step
设置为False
,但我觉得无法知道它是否会在最后时间之前完成。
答案 0 :(得分:0)
一个糟糕的解决方案是在每一步将max_step
设置为final_time - obj.t
。这很诱人,因为它确实有效,但表现很糟糕。
from scipy.integrate import ode
obj = ode(lambda t, y: -y) # Simple exponential decay
obj.set_initial_value(4.0)
final_time = 2.0
ts_new = []
ys_new = []
# Take one step at a time until the final time is reached
while obj.t < final_time:
obj.set_integrator('vode', max_step=final_time-obj.t)
y_new = obj.integrate(final_time, step=True, relax=False)
ts_new.append(obj.t)
ys_new.append(y_new)
print(ts_new[-1]) # 2.0
请注意,它会在正确的时间停止。但是,似乎对set_integrator
的调用会重建积分器,从而导致巨大的减速。在问题中集成系统需要27个步骤,但是在这个答案中集成系统需要36215个步骤。通过直接改变obj._integrator.max_step
来避免重建积分器是不可能的,因为这似乎是Fortran参数的副本,并且对集成没有影响。
答案 1 :(得分:0)
一个可以通过的解决方案是抛弃在最后时间逐步完成的点,并创建一个从倒数第二个时间开始的新集成器,并将step=False
集成到最后一个时间。我还没有计时,但我怀疑这也有点贵。
from scipy.integrate import ode
obj = ode(lambda t, y: -y) # Simple exponential decay
obj.set_initial_value(4.0)
final_time = 2.0
ts_new = []
ys_new = []
# Take one step at a time until the final time is reached
while obj.t < final_time:
y_new = obj.integrate(final_time, step=True, relax=False)
if obj.t <= final_time:
ts_new.append(obj.t)
ys_new.append(y_new)
else:
t_last = ts_new[-1]
obj = ode(lambda t, y: -y)
obj.set_initial_value(ys_new[-1], t_last)
y_new = obj.integrate(final_time, step=False, relax=False)
ts_new.append(obj.t)
ys_new.append(y_new)
print(ts_new[-1]) # 2.0
请注意,它会给出正确的最终时间。这不能防止因跨越不连续而导致的集成过程中的错误,因此必须在生产软件中捕获这些错误以触发奖励步骤。
随着奖金集成商的加速,毫无疑问会有一些额外的步骤,但step=False
会悄悄地抛弃这些步骤。我试图将min_step
设置为大约等于到最终时间的完整距离,以给它一个提示,但这只会炸毁积分器。