Python 加速odeint计算

Python 加速odeint计算,python,scipy,ode,odeint,Python,Scipy,Ode,Odeint,我正在使用scipy的odeint运行一个相当大的ODE系统。为了保持系统的连贯性、易读性和简洁性,我将其中的大部分分成了几个类,以便相互调用。从可读性的角度来看,它似乎工作得很好,但是由于重复调用python对象,它显著降低了实际ODE解算器的速度。我四处寻找优化代码的方法,以保持一定程度的可读性,同时提高计算效率(在将代码转换为支持numpy的lambda函数之前,使用Numba或Sympy),但到目前为止,我还不是很成功。我想知道在这种情况下,什么策略会有所帮助。我在下面提供了代码的简单版

我正在使用scipy的odeint运行一个相当大的ODE系统。为了保持系统的连贯性、易读性和简洁性,我将其中的大部分分成了几个类,以便相互调用。从可读性的角度来看,它似乎工作得很好,但是由于重复调用python对象,它显著降低了实际ODE解算器的速度。我四处寻找优化代码的方法,以保持一定程度的可读性,同时提高计算效率(在将代码转换为支持numpy的lambda函数之前,使用Numba或Sympy),但到目前为止,我还不是很成功。我想知道在这种情况下,什么策略会有所帮助。我在下面提供了代码的简单版本。先谢谢你

class NaL():
    g = 0
    def I(self, v, E): return self.g * (v - E) #Leak current

class Neuron():
    C_m = 1.0 #membrane capacitance
    V = 0  # Voltage
    m, h = 0, 0  #activating variables
    def I_Na(self): #Sodium Currents
        return self.NaT.I(self.V, self.m, self.h)+ self.NaL.I(self.V)  
    def __init__(self):
        self.NaT = NaT()
        self.NaL = NaL()
        self.NaT.g = 3000
        self.NaL.g = 20

I1 = Neuron()

def Run(X,t):
    I1.V, I1.m, I1.h = X 
    dydt = [(0 - I1.I_Na()) / I1.C_m, #dV/dt for neuron
            I1.NaT.dmdt(I1.V, I1.m), #dm/dt for sodium channel
            I1.NaT.dhdt(I1.V, I1.h) #dh/dt for sodium channel
           ]
    return dydt
X = odeint(Run, [-70, 0.0050, 0.9961], t)

集成的瓶颈几乎肯定是求值派生的
运行
,因为在集成的每个步骤中都必须多次调用它。现在,由于所有的类成员和函数调用,有相当大的Python开销

解决这个问题的一个方法是真正使用你的模块,在这里,你不用定义积分器要使用的函数,而是用符号(SymPy)定义微分方程。然后将它们转换为C代码,并将其编译为Python函数,然后用于集成。这样,在实际集成之前,类和类函数只会被调用几次,集成的效率与定义没有类和类似类的导数时一样高。(此外,通过编译,您可能会获得相当大的速度提升,特别是如果您有许多神经元的话。)

目前,将示例转换为JIT代码非常简单:

from jitcode import jitcode, provide_basic_symbols

t, y = provide_basic_symbols()

class NaL():
    […]

class Neuron():
    […]

I1 = Neuron()

I1.V, I1.m, I1.h = y(0), y(1), y(2)

Run = [
    (0 - I1.I_Na()) / I1.C_m,
    I1.NaT.dmdt(I1.V, I1.m),
    I1.NaT.dhdt(I1.V, I1.h)
]

t = range(100)

ODE = jitcode(Run)
ODE.set_initial_value([-70,0.0050,0.9961], t[0])
X = np.vstack(ODE.integrate for time in t[1:])

由于与示例代码不起作用相同的原因,此代码现在不起作用。请注意,类中所有涉及动态变量的算术都变成了符号。对于加法和乘法,这是开箱即用的,但是如果您有类似于
math.sin
sympy.sin
的东西,如果不重复,则必须将其替换为相关的:示例代码中的类
NaT
未定义,传递给
NaL.I
的参数数量错误。未定义函数
dmdt
dhdt
。请提供一个工作示例。