2

I wish to solve the Lorentz model in Python without the help of a package and my codes seems not to work to my expectation. I do not know why I am not getting the expected results and Lorentz attractor. The main problem I guess is related to how to store the various values for the solution of x,y and z respectively.Below are my codes for the Runge-Kutta 45 for the Lorentz model with 3D plot of solutions:

import numpy as np
import matplotlib.pyplot as plt
#from scipy.integrate import odeint

#a) Defining the Runge-Kutta45 method

def fx(x,y,z,t):
    dxdt=sigma*(y-z)
    return dxdt

def fy(x,y,z,t):
    dydt=x*(rho-z)-y
    return dydt

def fz(x,y,z,t):
    dzdt=x*y-beta*z
    return dzdt


def RungeKutta45(x,y,z,fx,fy,fz,t,h):
    k1x,k1y,k1z=h*fx(x,y,z,t),h*fy(x,y,z,t),h*fz(x,y,z,t)
    k2x,k2y,k2z=h*fx(x+k1x/2,y+k1y/2,z+k1z/2,t+h/2),h*fy(x+k1x/2,y+k1y/2,z+k1z/2,t+h/2),h*fz(x+k1x/2,y+k1y/2,z+k1z/2,t+h/2)
    k3x,k3y,k3z=h*fx(x+k2x/2,y+k2y/2,z+k2z/2,t+h/2),h*fy(x+k2x/2,y+k2y/2,z+k2z/2,t+h/2),h*fz(x+k2x/2,y+k2y/2,z+k2z/2,t+h/2)
    k4x,k4y,k4z=h*fx(x+k3x,y+k3y,z+k3z,t+h),h*fy(x+k3x,y+k3y,z+k3z,t+h),h*fz(x+k3x,y+k3y,z+k3z,t+h)
    return x+(k1x+2*k2x+2*k3x+k4x)/6,y+(k1y+2*k2y+2*k3y+k4y)/6,z+(k1z+2*k2z+2*k3z+k4z)/6



sigma=10.
beta=8./3.
rho=28.
tIn=0.
tFin=10.
h=0.05
totalSteps=int(np.floor((tFin-tIn)/h))

t=np.zeros(totalSteps)
x=np.zeros(totalSteps) 
y=np.zeros(totalSteps) 
z=np.zeros(totalSteps)

for i in range(1, totalSteps):
    x[i-1]=1. #Initial condition
    y[i-1]=1. #Initial condition
    z[i-1]=1. #Initial condition
    t[0]=0. #Starting value of t
    t[i]=t[i-1]+h
    x,y,z=RungeKutta45(x,y,z,fx,fy,fz,t[i-1],h)


#Plotting solution

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm

fig=plt.figure()
ax=fig.gca(projection='3d')
ax.plot(x,y,z,'r',label='Lorentz 3D Solution')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.legend()
Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51

1 Answers1

4

I changed the integration step (btw., classical 4th order Runge-Kutta, not any adaptive RK45) to use the python core concept of lists and list operations extensively to reduce the number of places where the computation is defined. There were no errors there to correct, but I think the algorithm itself is more concentrated.

You had an error in the system that changed it into a system that rapidly diverges. You had fx = sigma*(y-z) while the Lorenz system has fx = sigma*(y-x).

Next your main loop has some strange assignments. In every loop you first set the previous coordinates to the initial conditions and then replace the full arrays with the RK step applied to the full arrays. I replaced that completely, there are no small steps to a correct solution.

import numpy as np
import matplotlib.pyplot as plt
#from scipy.integrate import odeint


def fx(x,y,z,t): return sigma*(y-x)
def fy(x,y,z,t): return x*(rho-z)-y
def fz(x,y,z,t): return x*y-beta*z

#a) Defining the classical Runge-Kutta 4th order method

def RungeKutta4(x,y,z,fx,fy,fz,t,h):
    k1x,k1y,k1z = ( h*f(x,y,z,t) for f in (fx,fy,fz) )
    xs, ys,zs,ts = ( r+0.5*kr for r,kr in zip((x,y,z,t),(k1x,k1y,k1z,h)) )
    k2x,k2y,k2z = ( h*f(xs,ys,zs,ts) for f in (fx,fy,fz) )
    xs, ys,zs,ts = ( r+0.5*kr for r,kr in zip((x,y,z,t),(k2x,k2y,k2z,h)) )
    k3x,k3y,k3z = ( h*f(xs,ys,zs,ts) for f in (fx,fy,fz) )
    xs, ys,zs,ts = ( r+kr for r,kr in zip((x,y,z,t),(k3x,k3y,k3z,h)) )
    k4x,k4y,k4z  =( h*f(xs,ys,zs,ts) for f in (fx,fy,fz) )
    return (r+(k1r+2*k2r+2*k3r+k4r)/6 for r,k1r,k2r,k3r,k4r in 
            zip((x,y,z),(k1x,k1y,k1z),(k2x,k2y,k2z),(k3x,k3y,k3z),(k4x,k4y,k4z)))



sigma=10.
beta=8./3.
rho=28.
tIn=0.
tFin=10.
h=0.01
totalSteps=int(np.floor((tFin-tIn)/h))

t = totalSteps * [0.0]
x = totalSteps * [0.0]
y = totalSteps * [0.0]
z = totalSteps * [0.0]

x[0],y[0],z[0],t[0] = 1., 1., 1., 0.  #Initial condition
for i in range(1, totalSteps):
    x[i],y[i],z[i] = RungeKutta4(x[i-1],y[i-1],z[i-1], fx,fy,fz, t[i-1], h)

Using tFin = 40 and h=0.01 I get the image

solution of Lorenz system

looking like the typical image of the Lorenz attractor.

Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51
  • The codes seem to work without any error but it did not return the expected Lorentz curve after doing a 3d plot. I suspect it could be due to how you defined the variables; xs,ys and zs to update the x,y,z as proposed for Runge-Kutta 45 method. – Clement Twumasi Dec 25 '18 at 15:29
  • I'm not sure what problem you observe, I added a picture for some longer integration interval which looks like the usual Lorentz image. The `xs` are just `x+0.5*k1x` etc. using tuple/list-based vector arithmetic. – Lutz Lehmann Dec 25 '18 at 15:55
  • It is working perfectly now. I just had to increase the totalSteps to get the expected Lorenz curve. Impressive! – Clement Twumasi Dec 25 '18 at 16:03
  • 1
    Just one question... I see that you are including updated time ( ts = t + 0.5*h as well as ts = t + h)... I am wondering if this is necessary if the system is autonomous? If so, what is the reasoning? I can't quite see where it is getting used to get the next step. – rocksNwaves May 17 '19 at 12:36
  • 1
    @rocksNwaves : No, it is not really necessary for autonomous systems. It was done just to stay within the general interface used in the question. – Lutz Lehmann May 17 '19 at 12:39