scipy.integrate.ode 中僵硬系统的停止条件

计算科学 Python scipy 刚性
2021-11-30 00:01:49

我正在使用 Python scipy.integrate.ode,我想在某个条件下停止我的集成。所以我使用积分器“dopri5”并使用方法“set_solout”为我的停止条件指定一个函数。

不幸的是,在某些情况下,程序说我的问题很棘手,然后退出。(消息是“用户警告:dopri5:问题可能很僵硬(中断)”)。所以我尝试了另一个积分器。该文档提到了其他 3 个可能适用于棘手问题的集成器(“vode”、“zvode”和“lsoda”)。(还有“dop853”,但退出方式与“dopri5”相同)。

这是我的问题:这些集成器都不支持“set_selout”方法。那么:是否有另一种方法可以在某个条件下阻止这些集成器中的任何一个?

编辑(几个小时后):我用很短的时间步重复调用“集成”方法(积分器设置为“lsoda”)解决了这个问题;并在每次通话后检查我的结束情况。丑陋,但可以完成工作。我仍然想知道是否有更好的方法来做到这一点。

3个回答

我不知道用 SciPy 处理这个问题的更好方法,因为我认为它没有事件处理。但是,如果您愿意冒险超越 SciPy,以下软件具有该功能,可以记录为事件处理或 rootfinding:

  • 日晷的 CVODE
  • MATLABode23ode15s
  • Julia 的 DifferentialEquations.jl 日晷包装器和 Rosenbrock 方法
  • Mathematica 的 NDSolve

如果你想坚持 Python 科学家族,你可以选择AssimuloAssimulo 是许多 ODE 集成器的包装器,提供通用接口。如果您碰巧在 Windows 上运行,您可以在Christoph Gohlke 的页面上找到轮子。

Assimulo 允许处理状态事件以允许 ODE 的 RHS 函数中的不连续性,但您也可以使用它们在满足特定条件时停止迭代。

该过程是定义一个函数“state_events”来分析事件是否发生,第二个函数“handle_event”相应地采取行动(改变状态方程,改变变量,停止迭代,......)。

Assimulo 包中的示例是一个撞到墙上的钟摆。当它撞到墙上时,状态会发生变化,即方向应该反转并且应该损失一些能量。

我修改了 Assimulo 附带的示例,使用一个简单的指数衰减问题,我要求在物种浓度低于阈值时停止积分。请参阅下面的代码。

#!/usr/bin/env python 
# -*- coding: utf-8 -*-
import numpy as N
import pylab as P
from assimulo.problem import Explicit_Problem
from assimulo.solvers.sundials import CVode
from assimulo.exception import TerminateSimulation


def run_example():

    def decay(t,y):

        yd_0 = -0.5*y[0]

        return N.array([yd_0])

    def state_events(t,y,sw):
        """
        This is our function that keep track of our events, when the sign
        of any of the events has changed, we have an event.
        """

        return N.array([y[0]-50.0])


    def handle_event(solver, event_info):
        """
        Event handling. This functions is called when Assimulo finds an event as
        specified by the event functions.
        """
        state_info = event_info[0] #We are only interested in state events info

        if state_info[0] != 0: #Check if the first event function have been triggered
            raise TerminateSimulation


    #Initial values
    y0 = [100.0] #Initial states
    t0 = 0.0             #Initial time

    #Create an Assimulo Problem
    mod = Explicit_Problem(decay, y0, t0)

    mod.state_events = state_events #Sets the state events to the problem
    mod.handle_event = handle_event #Sets the event handling to the problem
    mod.name = 'Simple decay'   #Sets the name of the problem

    #Create an Assimulo solver (CVode)
    sim = CVode(mod)

    #Specifies options 
    sim.discr = 'BDF'     #Sets the discretization method
    sim.iter = 'Newton' #Sets the iteration method
    sim.rtol = 1.e-8        #Sets the relative tolerance
    sim.atol = 1.e-6        #Sets the absolute tolerance

    #Simulation
    ncp = 200     #Number of communication points
    tfinal = 10.0 #Final time

    t,y = sim.simulate(tfinal, ncp) #Simulate

    #Print event information
    sim.print_event_data()

    #Plot
    P.plot(t,y)
    P.show()

if __name__=='__main__':
    run_example()

python中的事件检测:

解决方案可能是 https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html

来自文档:用于非刚性问题的“RK45”或“RK23”方法和用于刚性问题的“Radau”或“BDF”。