具有复杂初始值的scipy odeint

时间:2013-11-11 15:40:04

标签: python scipy complex-numbers odeint

我需要解决具有复杂初始值的复杂域定义的ODE系统。 scipy.integrate.odeint不适用于复杂系统。 我强调在实部和虚部切割我的系统并分别求解,但我的ODE系统的rhs涉及因变量本身和它们的复共轭之间的产物。 哇,我这样做吗?这是我的代码,我尝试在Re和Im部分中破坏RHS,但我不认为解决方案是否相同,因为复杂数字之间的内部产品我不会打破它。 在我的脚本中,u1是一个(非常)长的复杂函数,比如u1(Lm)= f_real(Lm)+ 1j * f_imag(Lm)。

from numpy import *
from scipy import integrate

def cj(z): return z.conjugate()


def dydt(y, t=0):
    # Notation
    # Dependent Variables
    theta1 = y[0]
    theta3 = y[1]
    Lm = y[2]
    u11 = u1(Lm)
    u13 = u1(3*Lm)
    zeta1 = -2*E*u11*theta1
    zeta3 = -2*E*3*u13*theta3
    # Coefficients
    A0 = theta1*cj(zeta1) + 3*theta3*cj(zeta3)
    A2 = -zeta1*theta1 + 3*cj(zeta1)*theta3 + zeta3*cj(theta1)
    A4 = -theta1*zeta3 - 3*zeta1*theta3
    A6 = -3*theta3*zeta3
    A = - (A2/2 + A4/4 + A6/6)
    # RHS vector components
    dy1dt = Lm**2 * (theta1*(A - cj(A)) - cj(theta1)*A2/2
                     - 3/2*theta3*cj(A2) 
                     - 3/4*cj(theta3)*A4
                     - zeta1)
    dy2dt = Lm**2 * (3*theta3*(A - cj(A)) - theta1*A2/2
                     - cj(theta1)*A4/4
                     - 1/2*cj(theta3)*A6
                     - 3*zeta3)
    dy3dt = Lm**3 * (A0 + cj(A0))
    return array([dy1dt, dy2dt, dy3dt])


t = linspace(0, 10000, 100) # Integration time-step
ry0 = array([0.001, 0, 0.1]) # Re(initial condition)
iy0 = array([0.0, 0.0, 0.0]) # Im(initial condition)
y0 = ry0 + 1j*iy0 # Complex Initial Condition

def rdydt(y, t=0): # Re(RHS)
    return dydt(y, t).real
def idydt(y, t=0): # Im(RHS)
    return dydt(y, t).imag

ry, rinfodict = integrate.odeint(rdydt, y0, t, full_output=True)
iy, iinfodict = integrate.odeint(idydt, y0, t, full_output=True)

我得到的错误就是这个     TypeError:数组无法安全地转换为所需类型     odepack.error:函数调用的结果不是正确的数组     浮动。

2 个答案:

答案 0 :(得分:8)

正如您所发现的,odeint不处理复值微分方程,但有scipy.integrate.complex_odecomplex_ode是一个便利函数,负责将n复方程的系统转换为2*n实方程组。 (注意用于定义odeintode方程的函数的签名中的差异。odeint期望f(t, y, *args)ode(和{{1}期待complex_ode。)

可以为f(y, t, *args)创建类似的便利功能。在以下代码中,odeint是一个函数,用于处理复杂系统到实际系统的转换,并使用odeintz解决它。该代码包括解决复杂系统的示例。它还显示了如何将该系统“手动”转换为真实系统并使用odeint解决。但是对于一个大型系统来说,这是一个单调且容易出错的过程;使用复杂的求解器肯定是一种更为理智的方法。

odeint

这是剧本生成的情节:

Solution to the complex system


更新

此代码已经显着扩展为一个名为import numpy as np from scipy.integrate import odeint def odeintz(func, z0, t, **kwargs): """An odeint-like function for complex valued differential equations.""" # Disallow Jacobian-related arguments. _unsupported_odeint_args = ['Dfun', 'col_deriv', 'ml', 'mu'] bad_args = [arg for arg in kwargs if arg in _unsupported_odeint_args] if len(bad_args) > 0: raise ValueError("The odeint argument %r is not supported by " "odeintz." % (bad_args[0],)) # Make sure z0 is a numpy array of type np.complex128. z0 = np.array(z0, dtype=np.complex128, ndmin=1) def realfunc(x, t, *args): z = x.view(np.complex128) dzdt = func(z, t, *args) # func might return a python list, so convert its return # value to an array with type np.complex128, and then return # a np.float64 view of that array. return np.asarray(dzdt, dtype=np.complex128).view(np.float64) result = odeint(realfunc, z0.view(np.float64), t, **kwargs) if kwargs.get('full_output', False): z = result[0].view(np.complex128) infodict = result[1] return z, infodict else: z = result.view(np.complex128) return z if __name__ == "__main__": # Generate a solution to: # dz1/dt = -z1 * (K - z2) # dz2/dt = L - z2 # K and L are fixed parameters. z1(t) and z2(t) are complex- # valued functions of t. # Define the right-hand-side of the differential equation. def zfunc(z, t, K, L): z1, z2 = z return [-z1 * (K - z2), L - z2] # Set up the inputs and call odeintz to solve the system. z0 = np.array([1+2j, 3+4j]) t = np.linspace(0, 4, 101) K = 3 L = 1 z, infodict = odeintz(zfunc, z0, t, args=(K,L), full_output=True) # For comparison, here is how the complex system can be converted # to a real system. The real and imaginary parts are used to # write a system of four coupled equations. The formulas for # the complex right-hand-sides are # -z1 * (K - z2) = -(x1 + i*y1) * (K - (x2 + i*y2)) # = (-x1 - i*y1) * (K - x2 + i(-y2)) # = -x1 * (K - x2) - y1*y2 + i*(-y1*(K - x2) + x1*y2) # and # L - z2 = L - (x2 + i*y2) # = (L - x2) + i*(-y2) def func(r, t, K, L): x1, y1, x2, y2 = r dx1dt = -x1 * (K - x2) - y1*y2 dy1dt = -y1 * (K - x2) + x1*y2 dx2dt = L - x2 dy2dt = -y2 return [dx1dt, dy1dt, dx2dt, dy2dt] # Use regular odeint to solve the real system. r, infodict = odeint(func, z0.view(np.float64), t, args=(K,L), full_output=True) # Compare the two solutions. They should be the same. (As usual for # floating point calculations, there could be a small difference.) delta_max = np.abs(z.view(np.float64) - r).max() print "Maximum difference between the complex and real versions is", delta_max # Plot the real and imaginary parts of the complex solution. import matplotlib.pyplot as plt plt.clf() plt.plot(t, z[:,0].real, label='z1.real') plt.plot(t, z[:,0].imag, label='z1.imag') plt.plot(t, z[:,1].real, label='z2.real') plt.plot(t, z[:,1].imag, label='z2.imag') plt.xlabel('t') plt.grid(True) plt.legend(loc='best') plt.show() 的函数,用于处理复杂变量和矩阵方程。新函数可以在github上找到:https://github.com/WarrenWeckesser/odeintw

答案 1 :(得分:3)

我想我自己找到了解决方案。我发布它,因为任何人都会觉得它很有用。 似乎odeint无法处理复数。不管怎样,scipy.integrate.ode都可以 通过使用'zvode'集成方法。