Python 中的自适应 ODE 算法

计算科学 算法 Python
2021-12-05 08:58:48

我想使用integrate.ode module. 在我的情况下有点不同的是,我只想整合到某个位置,由粒子的最大允许 x 坐标确定:x_max

我遇到的主要问题是粒子可能首先移动得非常慢,然后再加快速度。因此,我不想在该区域的小时间步长上浪费精力。该算法应该能够进行调整,以便在粒子速度变高时使用更小的时间步长。

最后,如果我在“相空间”中绘制粒子轨迹,我应该有一条平滑的线。

为此,我在下面有一些粗略的伪代码:

backend = "dopri5"
x_max = 1
solver = ode(f)
solver.set_integrator(backend)  
solver.set_initial_value(y0, t0)
t, y = [t0], [y0]
k = 1.2
while solver.successful() and solver.y[0] < x_max
   solver.integrate(solver.t+dt)
   t.append(solver.t)
   y.append(solver.y)
   v_current = numpy.linalg.norm(y[-1])
   v_previous = numpy.linalg.norm(y[-2])
   if numpy.abs( v_current-v_previous ) > k * v_previous:
       dt = 0.8*dt
       del y[-1]
   else:
       dt = dt*1.2

问题是这个算法可能不是那么健壮,因为选择值k, 1.2, 0.8有些随意,可能会导致算法出现一些稳定性问题。

编辑:我还希望能够在轨迹上绘制时间间隔相等的点,以指示粒子的速度如何变化。

任何人都可以提出更好的方法吗?

2个回答

是的,SUNDIALS 中的事件检测功能应该适合您。我不知道它是否在 SUNDIALS 的非官方 Python 接口中实现;您应该大致按此顺序查看 Assimulo、scikits-odes、CasADi 和 PySUNDIALS。

至于等间隔的时间,您应该能够指定要将系统集成到集成器中的时间;积分器应存储其时间步长的内部状态,并插入其当前解决方案数组,以便在您查询时为您提供解决方案。

SUNDIALS 可以,恕我直言,但作为遗留组件的外部库,它不具备以 python 为中心的环境所具备的前端接口功能。我构建了PyDSTool系统来完成这种工作。除了求解器之外,它还有一套用于动力系统和建模的高级结构。这包括一种复杂而稳健的方法来指定与状态或时间相关的停止点(称为“事件”)。事件在内部、自动和任意精度下求解。然后,您可以根据您想要用于绘图的任何网格非常自然地对解决方案进行采样。例如,请参阅此示例,以及其他教程和提供的演示,以了解如何使用它进行采样和绘图。

PS PyDSTool 可以自动生成 C 代码以生成运行速度比任何使用回调到 python 定义的函数的集成器更快的求解器,这几乎是任何其他解决方案。