步入scipy积分器而不超过最终点

时间:2016-06-28 10:58:39

标签: python scipy

scipy积分器在积分时采用两个参数:(1)step告诉积分器只采取一个步骤,(2)relax告诉积分器可以步进超过最后时间点。

我想采取措施(以便我可以收集整个解决方案),但也没有超过最后一次(因为我在我的真正问题中存在不连续性)。但是,step True似乎忽略relaxFalse。放弃最后一次将需要一步。

这是一个说明问题的简单示例:

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,但我觉得无法知道它是否会在最后时间之前完成。

2 个答案:

答案 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设置为大约等于到最终时间的完整距离,以给它一个提示,但这只会炸毁积分器。