scipy.odeint 了解内部时间步长

scipy.odeint understanding internal timesteps

我正在 scipy 中使用 odeint 来集成一个功能。该函数实际上是一个向量(它是下面 L_total 函数 的返回值)。我遇到的问题是,对于这个向量的某些条目,集成非常容易,这意味着它不需要很多内部子步骤,但是对于其他一些值,集成应该更详细。我假设 odeint 需要一个子步骤,即应用于向量的每个条目的子步骤。如果这个假设是正确的,是否有一种方法可以根据函数向量中的条目以有效的方式在 scipy 中分配最大数量的内部子步骤?我知道通过使用 IF 语句我可以更改允许的最大步数,但我担心这会花费更多的计算时间,而这正是我想要减少的。我的代码如下所示:

def L_total(self, r, d, u):
    tem = self.T(u)
    condlist = [numpy.log10(tem) <= 2, numpy.log10(tem) >= 2]
    choicelist = [self.L1(r, d, tem), self.L2(r, tem)]
    return numpy.select(condlist, choicelist) #This is the returned value for the scipy integration, i.e. the vector I want to integrate

def integrate_function(self, i_0, time_final, r, d):
    def f(i, t):
        return - self.L_total(r, d, i)
    time = numpy.linspace(0., time_final, 2)
    result = odeint(f, i_0, time)
    return result[-1]

最后一个函数可以正常工作一段时间,直到变量 tem 的值增加,然后我收到一条消息说 'Excess work done on this call',建议增加允许的时间步数:

 lsoda--  at current t (=r1), mxstep (=i1) steps   ^@^@
   taken on this call before reaching tout     ^@^@
  in above message,  i1 =       500
  in above message,  r1 =  0.3319309749049D+03

此调用完成的工作过多(可能是错误的 Dfun 类型)

增加参数 mxstep 的数量听起来像是解决方案,除了只要 log(tem)< 2 积分很容易并且内部时间步长的数量可以很小,我不想浪费时间在这个简单的集成上,这个想法是只增加矢量的某些值的 mxstep 值。一种方法是:

def integrate_function(self, i_0, time_final, r, d, tem):
    def f(i, t):
        return - self.L_total(r, d, i)
    time = numpy.linspace(0., time_final, 2)
    if numpy.log10(tem)<=2:
        result = odeint(f, i_0, time, mxstep=10) 
    else:
        result = odeint(f, i_0, time, mxstep=1000)
    return result[-1]

但是向量函数的长度非常大,因此它会消耗大量计算时间,因为我必须在另一个循环内执行此循环。我需要的是效率,因为我的代码已经花费了很多时间。

odeint 自动选择的子时间步对于系统中的所有方程都是相同的。这是因为通常情况下,在求解 ODE 系统时,不能单独处理组件:所有组件都必须在同一时间点已知,以便在该时间找到导数。

对于非耦合系统,方程彼此无关,上述对时间步长可能造成了不必要的约束。在这种情况下,在循环中求解单个方程实际上可能比将它们作为一个系统来求解更快。