scipy.solve_ivp:在第二次发生事件时终止轨迹

问题描述

我想解决返回初始状态所需的时间。作为一个玩具示例,让我们看一个简单的谐波振荡器d / dt(x,y)=(y,-x),初始条件为(x,y)=(1,0)。

我希望代码返回T = 6.28 ...(=2π),因为这是返回y为正的初始条件所花费的时间。当达到这一点时,它应该停止集成。

import numpy as np
from scipy.integrate import solve_ivp

def f(t,x):
    return [x[1],-x[0]]

def event(t,x):
    return x[0]

event.direction = 1
event.terminal = True # Try false,this gives the result but integrates beyond the event I need.

initial_condition = [0,1]

sol = solve_ivp(f,[0,10],initial_condition,method='RK45',dense_output=True,\
                events = event,rtol=1e-6,atol=3e-6)

print(sol.t_events)

麻烦是将event.terminal = True设置为立即启动积分,因为事件在t = 0时得到满足。是否有办法让积分仅在两次事件都得到满足后才停止?

解决方法

与您的解决方法类似,我将 1e-100 添加到事件而不是初始状态。这样做的好处是根本不影响轨迹,甚至理论上也不影响。

当然,这确实意味着您未来的事件会提前一小部分发生,但如果这对您很重要,则取决于您的情况。

对于您编写的示例代码,这将使您的事件如下:

def event(t,x):
    return x[0] + 1e-100

我尝试过的一件事不起作用是在集成过程中修改终止参数。我想如果我从 event.terminal = False 开始,然后在事件定义集 event.terminal = True 中,那么它将在第一个事件期间继续(在 t=0 时),并在第二个事件处终止。但是,如果在集成过程中更改了更改的参数,它似乎会忽略。

(这个问题与 Solve_ivp integration gets stuck if initial condition triggers event with terminal = True 相关,但我没有标记任何东西的声誉。)

,

为以后参考,这里是我一直在使用的解决方法:

将初始条件设置为事件发生前的一小部分,例如zoo::na.locf(),而不是library(data.table) dtA <- data.table(Time = seq(as.ITime("00:15:00"),by = 900L,length.out = 96L),Values1 = seq(1L,by = 2L,Values2 = seq(2L,Values3 = seq(1.5,by = 1.0,Category = rep("A",96L)) dtB <- data.table(Time = seq(as.ITime("00:15:00"),Values1 = seq(to = 192L,Values2 = seq(to = 191L,Values3 = seq(to = 97.5,Category = rep("B",96L)) dt <- rbind(dtA,dtB) 。即使对于更高自由度的混沌系统,它似乎也不会影响轨迹,但是它不会在t = 0时触发事件。

另一个可行的解决方法是,在一段时间内不进行任何事件集成,然后将结果用作进一步集成的初始条件,这次是在事件已就绪的情况下进行。我怀疑这个答案对任何人都有用,但我只是为了完整性而发布了它。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...