python - 具有复杂初始值的 scipy odeint

标签 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)

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

最佳答案

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

可以为 odeint 创建一个类似的便利函数。在下面的代码中,odeintz 是一个函数,它处理复杂系统到真实系统的转换,并用 odeint 求解。该代码包括解决复杂系统的示例。它还展示了如何将该系统“手动”转换为真实系统并使用 odeint 求解。但对于大型系统来说,这是一个乏味且容易出错的过程;使用复数求解器当然是一种更明智的方法。

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()

这是脚本生成的情节:

Solution to the complex system


更新

此代码已显着扩展为名为 odeintw 的函数,可处理复杂的变量和矩阵方程。可以在 github 上找到新功能:https://github.com/WarrenWeckesser/odeintw

关于python - 具有复杂初始值的 scipy odeint,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19910189/

相关文章:

python - 如何在没有 Python 调用开销的情况下直接从 Cython 调用 numpy/scipy C 函数?

python - 在什么情况下 Python 复数求幂会抛出 OverflowError?

python - Cython 中的复数

python - 为什么我无法直接在 OpenAI Gym 环境中设置属性

python - 操作错误 : unable to open database file: sqlalchemy

python - 值错误 : object too deep for desired array

python - 自定义距离的距离矩阵

python - 当您事先不知道等级时在最后一个轴上建立索引

python - 类型错误 : Object of type 'datetime' is not JSON serializable (with serialize function)

matlab - 毫不含糊地发现真正的异常