0

我在scipy.integrate.ode遇到了一个奇怪的问题。这是一个最小的工作示例:

import sys
import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from scipy.integrate import ode, complex_ode

def fun(t):
    return np.exp( -t**2 / 2. )

def ode_fun(t, y):
    a, b = y
    f = fun(t)
    c = np.conjugate(b)
    dt_a = -2j*f*c + 2j*f*b
    dt_b = 1j*f*a
    return [dt_a, dt_b]

t_range = np.linspace(-10., 10., 10000)

init_cond = [-1, 0]
trajectory = np.empty((len(t_range), len(init_cond)), dtype=np.complex128)

### setup ###
r = ode(ode_fun).set_integrator('zvode', method='adams', with_jacobian=False)
r.set_initial_value(init_cond, t_range[0])
dt = t_range[1] - t_range[0]

### integration ###
for i, t_i in enumerate(t_range):
    trajectory[i,:] = r.integrate(r.t+dt)

a_traj    = trajectory[:,0]
b_traj    = trajectory[:,1]
fun_traj  = fun(t_range)

### plot ###
plt.figure(figsize=(10,5))
plt.subplot(121, title='ODE solution')
plt.plot(t_range, np.real(a_traj))
plt.subplot(122, title='Input')
plt.plot(t_range, fun_traj)
plt.show()

此代码工作正常,输出图为(ODE 显式依赖于输入变量,右侧面板显示输入,左侧面板显示第一个变量的 ode 解决方案)。

在此处输入图像描述

所以原则上我的代码是有效的。奇怪的是,如果我只是简单地替换积分范围

t_range = np.linspace(-10., 10., 10000)

经过

t_range = np.linspace(-20., 20., 10000)

我得到输出

在此处输入图像描述

所以不知何故,集成商只是放弃了集成,并将我的解决方案保持不变。为什么会这样?我该如何解决?

我测试过的一些东西:这显然不是分辨率问题,集成步骤已经很小了。相反,似乎集成商在几步之后甚至不再费心调用 ode 函数了。我已经通过在 ode_fun() 中包含一个打印语句来测试它。

我目前的怀疑是,在最初的几个集成步骤中,我的函数没有发生显着变化后,集成商决定我的函数是恒定的。我可能需要在某处设置一些容忍度吗?

任何帮助表示赞赏!

4

1 回答 1

2

“我目前的怀疑是,在最初的几个集成步骤中,我的功能没有发生显着变化后,集成商认为我的功能是恒定的。” 你的怀疑是正确的。ODE 求解器通常具有一个内部步长,该步长根据求解器计算的误差估计进行自适应调整。这些步长与请求输出的时间无关;使用在内部步骤计算的点处的解插值计算请求时间的输出。

当您在 处启动求解器时t = -20,显然输入变化如此缓慢,以至于求解器的内部步长变得足够大,以至于当求解器接近 时t = 0,求解器会直接跳过输入脉冲。

max_step您可以使用方法选项限制内部步长set_integrator。如果我设置max_step为 2.0(例如),

r = ode(ode_fun).set_integrator('zvode', method='adams', with_jacobian=False,
                                max_step=2.0)

我得到了你期望的输出。

于 2021-03-13T10:34:19.900 回答