Solving the Lorenz 96 model with Julia and Python

Introduction

I'm studying a lot because I want to use data assimilation for research. Lorenz96 model often used in data assimilation benchmarks https://journals.ametsoc.org/jas/article/55/3/399/24564/Optimal-Sites-for-Supplementary-Weather I wrote the code to solve the problem in Julia. I'm not sure if this is slow or fast, so I rewrote it in Python for the time being and compared it.

Lorenz 96 model

equation

\frac{dX_j}{dt} = (X_{j+1} - X_{j-2})X_{j-1} - X_j +F

However, $ j = 1 \ dots N $. This time N = 40.

If you initially set $ X_j = F $, you will get a stationary solution. This time, solve it as $ X_ {20} = 1.01F, ; F = 8 $. When F = 8, chaotic behavior can be seen.

This is solved with Runge-Kutta with 4 steps and 4th order accuracy.

Julia version

The version of Julia is 1.5.1. I ran it in Jupyter lab.

using LinearAlgebra

##Parameters
##Behavior changes depending on the size of F
F = 8
N = 40
dt = 0.01
tend = 146
nstep = Int32(tend/dt)

# dx/dt=f(x) 
#Lorentz 96 equation
function f(x)
    f = fill(0.0, N)
    for i=3:N-1
        f[i] = (x[i+1]-x[i-2])x[i-1] - x[i] + F
    end
    
    #Periodic boundary
    f[1] = (x[2]-x[N-1])x[N] - x[1] + F
    f[2] = (x[3]-x[N])x[1] - x[2] + F
    f[N] = (x[1]-x[N-2])x[N-1] - x[N] + F
    
    return f
end

#Solve L96 with RK4
function RK4(xold, dt)
    k1 = f(xold)
    k2 = f(xold + k1*dt/2.)
    k3 = f(xold + k2*dt/2.)
    k4 = f(xold + k3*dt)
    
    xnew = xold + dt/6.0*(k1 + 2.0k2 + 2.0k3 + k4)
end

#Calculate the true value in all steps
function progress(deltat)
    xn = zeros(Float64, N, nstep)
    t = zeros(Float64, nstep)
    
    #X = fill(F,N)+randn(N)
    X = fill(Float64(F), N)
    #The initial disturbance is j=0 of F value at 20 points.1%Gives the value of.
    X[20] = 1.001*F
    
    for j=1:nstep
        X = RK4(X, deltat)
        for i=1:N
            xn[i, j] = X[i]
        end
        t[j] = dt*j
    end
    
    return xn, t
end

# x_Calculation of true
@time xn, t = progress(dt)

Python version

Python is 3.7.3. Python calculates with numpy installed with pip. Numpy in Anaconda is faster, but it's a test for the time being, so I don't care.

import numpy as np
from copy import copy

##Parameters
##Behavior changes depending on the size of F
F = 8
#Number of analysis data points (dimension)
N = 40
dt = 0.01
#1 year calculation
tend=146
nstep = int(tend/dt)

def f(x):
    f = np.zeros((N))
    for i in range(2, N-1):
        f[i] = (x[i+1]-x[i-2])*x[i-1] - x[i] + F
    
    f[0] = (x[1]-x[N-2])*x[N-1] - x[0] + F
    f[1] = (x[2]-x[N-1])*x[0] - x[1] + F
    f[N-1] = (x[0]-x[N-3])*x[N-2] - x[N-1] + F
    
    return f

#Solve L96 with RK4
def Model(xold, dt):
    k1 = f(xold)
    k2 = f(xold + k1*dt/2.)
    k3 = f(xold + k2*dt/2.)
    k4 = f(xold + k3*dt)
    
    xnew = xold + dt/6.0*(k1 + 2.0*k2 + 2.0*k3 + k4)
    return xnew

#Calculate the true value in all steps
def progress(deltat):
    xn = np.zeros((N, nstep))
    t = np.zeros((nstep))
    
    X = float(F)*np.ones(N)
    #X = fill(Float64(F), N)
    #The initial disturbance is j=0 of F value at point 19 (considering 0 start).1%Gives the value of.
    X[19] = 1.001*F
    
    for i in range(N):
        xn[i, 0] = copy(X[i])
    
    for j in range(1, nstep):
        X = Model(X, deltat)
        xn[:, j] = X[:]
        #print(X[20], X[1], deltat)
        t[j] = dt*j

    return xn, t

#Run
start = time.time()
xn, t = progress(dt)
elapsed_time = time.time() - start
print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")

Calculation time

Julia 0.73 s Python 2.94 s

And Julia was faster. I did it on a MacBook Pro with a 2.3 GHz Quad-Core Intel Core i5.

I haven't really thought about optimizing Python, so I think it will be faster. I changed the order of the indexes of array, but it didn't get faster. I can do JIT compilation with Python, but I haven't done it, so I put it on hold this time.

For the time being, Julia's calculation speed did not seem to be slow. By the way, I also wrote the code for data assimilation by Extended Kalman Filter, but Julia was faster.

Bonus: Drawing

Code to plot the calculation result in Julia

Hoffmeler diagram

using PyPlot

fig = plt.figure(figsize=(6, 5.))
ax1 = fig.add_subplot(111)

ax1.set_title("true")
ax1.set_xlabel("X_i")
ax1.set_ylabel("time step")

image1 = ax1.contourf(xn'[1:5000,:], )
cb1 = fig.colorbar(image1, ax=ax1, label="X")

time change

using PyPlot

fig = plt.figure(figsize=(5, 8.))
ax1 = fig.add_subplot(211)
nhalf = Int(nstep/2)
nstart = nhalf
nend = nstep
ax1.plot(t[nstart:nend], xn[1, nstart:nend], label="x1")
ax1.plot(t[nstart:nend], xn[2, nstart:nend], label="x2")
ax1.plot(t[nstart:nend], xn[3, nstart:nend], label="x3")

Bonus: Data storage

Save as HDF5. Save data every 5 steps in the latter half of the calculation result.

using HDF5

h5open("L96_true_obs.h5", "w") do file
    write(file, "Xn_true", xn[:, nhalf:5:nstep])
    write(file, "t", t[nhalf:5:nstep])
end

Reed looks like this

file = h5open("L96_true_obs.h5", "r") 
Xn_true = read(file, "Xn_true")
t = read(file, "t")
close(file)

Recommended Posts

Solving the Lorenz 96 model with Julia and Python
Archive and compress the entire directory with python
Solving the Python knapsack problem with the greedy algorithm
[# 2] Make Minecraft with Python. ~ Model drawing and player implementation ~
Visualize the range of interpolation and extrapolation with python
Install the latest stable Python with pyenv (both 2 and 3)
Programming with Python and Tkinter
Encryption and decryption with Python
Python and hardware-Using RS232C with Python-
Solving Sudoku with Python (Incomplete)
Solving Sudoku with Python (Part 2)
Calibrate the model with PyCaret
Call the API with python3.
python with pyenv and venv
Works with Python and R
Solving with Ruby and Python AtCoder ARC 059 C Least Squares
Try hitting the Twitter API quickly and easily with Python
Solving with Ruby and Python AtCoder ABC178 D Dynamic programming
Solving with Ruby and Python AtCoder ABC151 D Breadth-first search
Solving with Ruby and Python AtCoder AISING2020 D Iterative Squares
Solving with Ruby, Perl, Java and Python AtCoder ATC 002 A
Solve the spiral book (algorithm and data structure) with python!
Solving with Ruby and Python AtCoder ABC011 C Dynamic programming
Solving with Ruby and Python AtCoder ABC153 E Dynamic programming
Solving with Ruby and Python AtCoder ARC067 C Prime Factorization
Solving with Ruby, Perl, Java and Python AtCoder ATC 002 B
Solving with Ruby and Python AtCoder ABC138 D Adjacency list
Play with the password mechanism of GitHub Webhook and Python
Communicate with FX-5204PS with Python and PyUSB
Shining life with Python and OpenCV
Extract the xz file with python
The story of Python and the story of NaN
Robot running with Arduino and python
Install Python 2.7.9 and Python 3.4.x with pip.
Neural network with OpenCV 3 and Python 3
AM modulation and demodulation with python
[Python] font family and font with matplotlib
Scraping with Node, Ruby and Python
Scraping with Python, Selenium and Chromedriver
Scraping with Python and Beautiful Soup
Get the weather with Python requests
Get the weather with Python requests 2
Find the Levenshtein Distance with python
JSON encoding and decoding with python
Hadoop introduction and MapReduce with Python
Hit the Etherpad-lite API with Python
Install the Python plugin with Netbeans 8.0.2
Reading and writing NetCDF with Python
I liked the tweet with python. ..
I played with PyQt5 and Python3
[Python] Mixed Gauss model with Pyro
Master the type with Python [Python 3.9 compatible]
Reading and writing CSV with Python
Multiple integrals with Python and Sympy
Validate the learning model with Pylearn2
Coexistence of Python2 and 3 with CircleCI (1.0)
Easy modeling with Blender and Python
Sugoroku game and addition game with python
FM modulation and demodulation with Python
I compared the speed of Hash with Topaz, Ruby and Python
[In-Database Python Analysis Tutorial with SQL Server 2017] Step 6: Using the model