如何为非线性ODE系统生成庞加莱截面的方法?

时间:2018-12-15 12:02:45

标签: numpy scipy ode numerical-integration

我一直在尝试研究如何为非线性ODE系统计算庞加莱截面,并使用精确系统上的论文作为参考,并且一直在与numpy进行角力以尝试使其运行更好。它旨在在有界域内运行。

当前,我有以下代码

import numpy as np
from scipy.integrate import odeint
X = 0
Y = 1
Z = 2

def generate_poincare_map(function, initial, plane, iterations, delta):
    intersections = []
    p_i = odeint(function, initial.flatten(), [0, delta])[-1]
    for i in range(1, iterations):
        p_f = odeint(function, p_i, [i * delta, (i+1) * delta])[-1]
        if (p_f[Z] > plane) and (p_i[Z] < plane):
            intersections.append(p_i[:2])
        if (p_f[Z] > plane) and (p_i[Z] < plane):
            intersections.append(p_i[:2])
        p_i = p_f
    return np.stack(intersections)

由于仅在连续的时间步之间进行积分,因此非常浪费,并且似乎会产生错误的结果。原始参考文献包括以下内容: Reference solution

而我的倾向于导致类似 enter image description here

您是否对如何使其更正确甚至更快一点有任何建议?

1 个答案:

答案 0 :(得分:1)

获取ABC流的Pointcaré地图

def ABC_ode(u,t):
    A, B, C = 0.75, 1, 1 # matlab parameters
    x, y, z = u
    return np.array([
        A*np.sin(z)+C*np.cos(y), 
        B*np.sin(x)+A*np.cos(z), 
        C*np.sin(y)+B*np.cos(x)
    ])

def mysolver(u0, tspan): return odeint(ABC_ode, u0, tspan, atol=1e-10, rtol=1e-11)

您首先必须了解动力学系统实际上是关于单位圆上的点(cos(x),sin(x))等的。因此,相差2*pi倍数的值表示同一点。在该部分的计算中,必须通过在3个圆的笛卡尔积上进行计算来反映这一点。让我们继续使用第二个变体,并选择[-pi,pi]作为基本周期,以使零位置位于中心。请记住,pi跳得更大是由于角度减小,而不是该间隔的实际交叉。

def find_crosssections(x0,y0):
    u0 = [x0,y0,0]
    px = []
    py = []

    u = mysolver(u0, np.arange(0, 4000, 0.5)); u0 = u[-1]
    u = np.mod(u+pi,2*pi)-pi
    x,y,z = u.T

    for k in range(len(z)-1): 
        if z[k]<=0 and z[k+1]>=0 and z[k+1]-z[k]<pi:
            # find a more exact intersection location by linear interpolation
            s = -z[k]/(z[k+1]-z[k])  # 0 = z[k] + s*(z[k+1]-z[k])
            rx, ry = (1-s)*x[k]+s*x[k+1], (1-s)*y[k]+s*y[k+1]
            px.append(rx); 
            py.append(ry);
    return px,py

要获得庞加莱横截面的全貌并避免重复工作,请使用正方形网格,并标记其中一个交叉点是否已掉入其中。仅从自由正方形的中心开始新的迭代。

N=20
grid = np.zeros([N,N], dtype=int)
for i in range(N):
    for j in range(N):
        if grid[i,j]>0: continue;
        x0, y0 = (2*i+1)*pi/N-pi, (2*j+1)*pi/N-pi 
        px, py = find_crosssections(x0,y0)
        for rx,ry in zip(px,py):
            m, n = int((rx+pi)*N/(2*pi)), int((ry+pi)*N/(2*pi))
            grid[m,n]=1

    plt.plot(px, py, '.', ms=2)

enter image description here

您现在可以使用网格的密度和积分间隔的长度来进行绘制,以使图更加完整,但是这里已经包含了所有特征。但我建议您使用编译后的语言对此进行重新编程,因为计算会花费一些时间。