nonlinear Schroedinger equation resolution with split step method - python

I'm trying to resolve a nonlinear PDE Schrödinger equation with the split-step Fourier pseudo-spectral method. The fonction "solver" is supposed to solve the time and space dependant equation with the split-step method but it gives values oscillating between 0.49 and 0.51 instead of the good answer which is between 0 and 1.657 (see here).
What should I change to get the good result?
import numpy as np
from matplotlib import pyplot as plt
i = np.complex(0,1)
K = 1
dt = 0.01 #temps
t = np.arange(0,20,dt)
N = 1024#espace
x = np.linspace(-20,20,N) #domaine truncated
L = 40
dx = L/N
k =np.linspace(-N/2,N/2-1,N)
def solver(x,t):
F = []
psi = 0.5 +0.01*np.cos(2*np.pi*x/40)
for l in range(len(t)):
g = np.exp(-i*K*(np.abs(psi))*dt)*psi
fg = np.fft.fftshift((np.fft.fft(g)))
fpsi = np.exp(-i/2*(2*np.pi*k/L)**2*dt)*fg
psi = np.fft.ifft(fpsi)
F.append(psi)
return F
M = np.abs(solver(x,t))
print(M)
#plt.plot(x,M)
#plt.show()
fig = plt.figure(figsize=(10,10))
ax1 = fig.add_subplot()
m1 = ax1.matshow(M)
plt.title("")
fig.colorbar(m1)
ax1.set_xlabel('espace')
ax1.set_ylabel('temps')
enter image description here

Related

Python - changing color of 3d plot regarding the heat equation

I need to solve the heat equation using finite difference method in Python. However my main problem is not the solving equation but rather plotting the result. See below for my code.
import numpy as np
import matplotlib.pyplot as plt
max_iter_time = 100
interval_length = 1
D = 20
dt = .001
delta_x = .01
u = np.empty((max_iter_time,round(interval_length/delta_x)))
interval = np.linspace(0,1,round(interval_length/delta_x))
interior = np.sin(interval*2*np.pi)
u_start = 0
u = np.array([interior]*max_iter_time)
u[:,0]=u_start
for i in range(0, max_iter_time-1,1):
u[:,round(interval_length/delta_x)-1]=u[:,round(interval_length/delta_x)-2]
def fdm1d(u):
for t in range(0, max_iter_time-1, 1):
for i in range(0, max_iter_time-1, 1):
u[t + 1, i] = u[t][i] + D*dt * (u[t][i+1] + u[t][i-1] + u[t][i] - 2*u[t][i])
return u
u2 = []
u1 = fdm1d(u)
print(u1.shape)
ax = plt.axes(projection='3d')
for t in range(0, max_iter_time-1, 1):
for i in range(0, max_iter_time-1, 1):
u2.append([t,i,u1[t][i]])
xpoints = []
ypoints = []
zpoints =[]
for i in range(len(u2)-1):
xpoints.append(u2[i][0])
ypoints.append(u2[i][1])
zpoints.append(u2[i][2])
ax.scatter(xpoints,ypoints,zpoints,cmap='inferno')
plt.show()
My question is about the plot itself - when I compile the code the plot that shows looks like this:
plot
In the code I have specified the color of this but nothing has changed. Could someone adivse on this? What do I do wrong here? Is there any better way to plot this?

Simulating two coupled dynamical systems in Python

The goal is to plot two identical dynamical systems that are coupled.
We have:
X = [x0,x1,x2]
U = [u0,u1,u2]
And
Xdot = f(X) + alpha*(U-X)
Udot = f(U) + alpha*(X-U)
So I wish to plot the solution to this grand system on one set of axes (i.e in xyz for example) and eventually change the coupling strength to investigate the behaviour.
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from mpl_toolkits.mplot3d import Axes3D
def couple(s,t,a=0.2,beta=0.2,gamma=5.7,alpha=0.03):
[x,u] = s
[u0,u1,u2] = u
[x0,x1,x2] = x
xdot = np.zeros(3)
xdot[0] = -x1-x2
xdot[1] = x0+a*x1
xdot[2] = beta + x2*(x0-gamma)
udot = np.zeros(3)
udot[0] = -u1-u2
udot[1] = u0+a*u1
udot[2] = beta + u2*(u0-gamma)
sdot = np.zeros(2)
sdot[0] = xdot + alpha*(u-x)
sdot[1] = udot + alpha*(x-u)
return sdot
s_init = [0.1,0.1]
t_init=0; t_final = 300; t_step = 0.01
tpoints = np.arange(t_init,t_final,t_step)
a=0.2; beta=0.2; gamma=5.7; alpha=0.03
y = odeint(couple, s_init, tpoints,args=(a,beta,gamma,alpha), hmax = 0.01)
I imagine that something is wrong with s_init since it should be TWO initial condition vectors but when I try that I get that "odeint: y0 should be one-dimensional." On the other hand when I try s_init to be a 6-vector I get "too many values to unpack (expected two)." With the current setup, I am getting the error
File "C:/Users/Python Scripts/dynsys2019work.py", line 88, in couple
[u0,u1,u2] = u
TypeError: cannot unpack non-iterable numpy.float64 object
Cheers
*Edit: Please note this is basically my first time attempting this kind of thing and will be happy to receive further documentation and references.
The ode definition takes in and returns a 1D vector in scipy odeint, and I think some of your confusion is that you actually have 1 system of ODEs with 6 variables. You have just mentally apportioned it into 2 separate ODEs that are coupled.
You can do it like this:
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import numpy as np
def couple(s,t,a=0.2,beta=0.2,gamma=5.7,alpha=0.03):
x0, x1, x2, u0, u1, u2 = s
xdot = np.zeros(3)
xdot[0] = -x1-x2
xdot[1] = x0+a*x1
xdot[2] = beta + x2*(x0-gamma)
udot = np.zeros(3)
udot[0] = -u1-u2
udot[1] = u0+a*u1
udot[2] = beta + u2*(u0-gamma)
return np.ravel([xdot, udot])
s_init = [0.1,0.1, 0.1, 0.1, 0.1, 0.1]
t_init=0; t_final = 300; t_step = 0.01
tpoints = np.arange(t_init,t_final,t_step)
a=0.2; beta=0.2; gamma=5.7; alpha=0.03
y = odeint(couple, s_init, tpoints,args=(a,beta,gamma,alpha), hmax = 0.01)
plt.plot(tpoints,y[:,0])

Inaccurate phase portrait result with matplotlib

I am trying to plot the phase potrait for the equation as defined in my sh2 function in the code below. I know the expected phase plot should be [[expected phase plot][1]][1] [1]: https://i.stack.imgur.com/y1T9Y.png.
However this is my result: [[result][1]: https://i.stack.imgur.com/EuSOm.png.
I am using integrate.odeint can anyone suggest what I could change in the could below or if there would be best to use another algorithm that would give me a closer result to th expected.
Please find my code :
import matplotlib.pyplot as plt
import numpy as np
from numpy import sin
import scipy.integrate as integrate
from math import *
g = 9.81
l = 1.6
l_big = 2.0
l_small = 1.6
m = 0.01
alpha = l_big-l_small
k = 10*(10**40)
def sh2(r1,t):
theta1,omega1 = r1
sh2_theta1 = omega1
sh2_omega1 = -g*(l + ((1/2)*alpha*(1-np.tanh(theta1*omega1*k))))*sin(theta1)
return np.array([sh2_theta1, sh2_omega1],float)
init_state = np.radians([30.0,0])
dt = 1/10.0
time = np.arange(0,10.0,dt)
timexo = np.arange(0,10.0,dt)
state2 = integrate.odeint(sh2,init_state,time)
print(len(state2),len(timexo))
state2_plot = np.transpose(state2[0:2500])
plt.plot(timexo[0:2500],state2_plot[1], '--m', label = r'$\theta = \frac{\pi}{6}$')
plt.xlabel('Time t (s) ')
plt.ylabel('Angular Velocity' ' ' r'$\dot{\theta}$')
plt.show()
#code for phase plot
# initial values
x_0 = 0.0 # intial angular position
v_0 = 1.0 # initial angular momentum
t_0 = 0 # initial time
# initial y-vector from initial position and momentum
y0 = np.array([x_0,v_0])
# max value of time and points in time to integrate to
t_max = 10
N_spacing_in_t = 10000
# create vector of time points you want to evaluate
t = np.linspace(t_0,t_max,N_spacing_in_t)
# create vector of positions for those times
y_result = integrate.odeint(sh2, init_state, t)
# get angle and angular momentum
angle = y_result[:,0]
angular_velocity = y_result[:,1]
# plot result
fig = plt.figure()
plt.plot(angle, angular_velocity,'--k',lw=1)
plt.xlabel('Angle' ' ' r'$\theta$')
plt.ylabel(r'Angular Velocity' r' $\dot{\theta}$')
plt.gcf().savefig('pumping.png',dpi=300)
plt.show()
Thank you for tour time

How do I generate a vector field plot for logistic equation K = 1 using matplotlib?

I'm going through Strogatz's Nonlinear Dynamics and Chaos and I've hit a snag in chapter 2 Exercise 2.8.1. (Educator flag: I've graduated so this isn't for a class, I'm just trying to get back into the numerical solving of differential equations) It's a pretty simple differential equation and I can plot individual solution curves given different initial conditions but I'm trying to use quiver or streamplot to superimpose individual solutions on top of the vector field.
My problem is in understanding how to translate the vector field plots for similar problems in the dy/dx form found here over to the dx/dt form that's primarily tackled in Strogatz's book.
Given that the x vector that's defined in the logistic function is only one dimensional I'm having a hard time reasoning out how express the u and v flows in quiver or streamplot since the problem only seems to have a u flow. It's probably super easy and is being over-thought but any guidance or assistance would be much appreciated!
So far I have the following:
# 2.8.1
# Plot the vector field and some trajectories for xdot = x(1-x) given
# some different initial conditions for the logistic equation with carrying
# capacity K = 1
# dx/dt = x(1-x)
# Imports:
from __future__ import division
from scipy import *
import numpy as np
import pylab
import matplotlib as mp
from matplotlib import pyplot as plt
import sys
import math as mt
def logistic(x,t):
return np.array([x[0]*(1-x[0])])
def RK4(t0 = 0, x0 = np.array([1]), t1 = 5 , dt = 0.01, ng = None):
tsp = np.arange(t0, t1, dt)
Nsize = np.size(tsp)
X = np.empty((Nsize, np.size(x0)))
X[0] = x0
for i in range(1, Nsize):
k1 = ng(X[i-1],tsp[i-1])
k2 = ng(X[i-1] + dt/2*k1, tsp[i-1] + dt/2)
k3 = ng(X[i-1] + dt/2*k2, tsp[i-1] + dt/2)
k4 = ng(X[i-1] + dt*k3, tsp[i-1] + dt)
X[i] = X[i-1] + dt/6*(k1 + 2*k2 + 2*k3 + k4)
return X
def tplot():
t0 = 0
t1 = 10
dt = 0.02
tsp = np.arange(t0,t1,dt)
X = RK4(x0 = np.array([2]), t1 = 10,dt = 0.02, ng = logistic)
Y = RK4(x0 = np.array([0.01]), t1 = 10,dt = 0.02, ng = logistic)
Z = RK4(x0 = np.array([0.5]), t1 = 10,dt = 0.02, ng = logistic)
P = RK4(x0 = np.array([3]), t1 = 10,dt = 0.02, ng = logistic)
Q = RK4(x0 = np.array([0.1]), t1 = 10,dt = 0.02, ng = logistic)
R = RK4(x0 = np.array([1.5]), t1 = 10,dt = 0.02, ng = logistic)
O = RK4(x0 = np.array([1]), t1 = 10,dt = 0.02, ng = logistic)
pylab.figure()
pylab.plot(tsp,X)
pylab.plot(tsp,Y)
pylab.plot(tsp,Z)
pylab.plot(tsp,P)
pylab.plot(tsp,Q)
pylab.plot(tsp,R)
pylab.plot(tsp,O)
pylab.title('Logistic Equation - K=1')
pylab.xlabel('Time')
pylab.ylabel('Xdot')
pylab.show()
print tplot()
image here
To graph a slope from a derivative (like, dx/dt), you can first find dx/dt, and then use a fixed dt to calculate dx. Then, at each (t, x) of interest, plot the little line segment from (t,x) to (t+dt, x+dx).
Here's an example for your equation dx/dt = x(1-x). (The Strogatz picture doesn't have arrowheads so I removed them too.)
import numpy as np
import matplotlib.pyplot as plt
times = np.linspace(0, 10, 20)
x = np.linspace(0 ,2, 20)
T, X = np.meshgrid(times, x) # make a grid that roughly matches the Strogatz grid
dxdt = X*(1-X) # the equation of interest
dt = .5*np.ones(X.shape) # a constant value (.5 is just so segments don't run into each other -- given spacing of times array
dx = dxdt * dt # given dt, now calc dx for the line segment
plt.quiver(T, X, dt, dx, headwidth=0., angles='xy', scale=15.)
plt.show()
wonkybadonk: For the difference in slope of the plotted trajectories and the plotted vector field seem to be due to the fact that your vector field are not steep enough. Make sure that
dx = dxdt*dt; (point by point multiplication, not a dot product)
and that you added "angles='xy'" as a quiver argument. (see tom10 post).

1D Finite Difference Wave Equation Modeling

I am attempting to model a 1D wave created by a Gaussian point source using the finite difference approximation method. Below is my code.
import matplotlib.pyplot as plt
import numpy as np
########Pre-Defining Values########
# spacial extent
lox = -1000
upx = 1000
# space sampling interval (km)
dx = 2.0
dx2inv = 1/(dx*dx)
# temporal extent
lot = 0
upt = 60
# time sampling interval (s)
dt = 0.5
dt2 = dt*dt
x = np.arange(lox,upx,dx)
t = np.arange(lot,upt,dt)
# pressure source location
psx = 0
# velocity (km/s)
v = 2.0
v2 = v*v
# density change location
pcl = 500
# density
p1 = 1
p1inv = 1/p1
p2 = 0.2
p2inv = 1/p2
pinv = np.zeros_like(x)
p = np.zeros_like(x)
for i in range(0,(int)((upx+pcl)/dx),1):
pinv[i] = p1inv
p[i] = p1
for i in range((int)((upx+pcl)/dx),len(pinv),1):
pinv[i] = p2inv
p[i] = p2
# waveform
f = np.zeros((len(t),len(x)))
# source
amp = 20
mu = 0
sig = 10/dx
s = np.zeros_like(f)
s[0] = 1/(sig*np.sqrt(2*np.pi)) * np.exp(-(x-mu)*(x-mu)/2/sig/sig)
maxinv = 1/np.amax(s[0])
for i in range(1,len(s[0])):
s[0][i] *= amp*maxinv
########Calculating Waveform########
h = np.zeros_like(f)
n1 = len(f)
n2 = len(f[0])
def fdx(i1):
for i2 in range(1,n2-1):
gi = f[i1][i2 ]
gi -= f[i1][i2-1]
gi *= pinv[i2]
h[i1][i2-1] -= gi
h[i1][i2 ] = gi
#f[0] = s[0]
fdx(0)
for i2 in range(0,n2):
f[1][i2] = 2*f[0][i2] + (s[0][i2] - h[0][i2] * dx2inv) * p[i2] * v2 * dt2
for i1 in range(1,n1-1):
fdx(i1)
for i2 in range(0,n2):
f[i1+1][i2] = 2*f[i1][i2] - f[i1-1][i2] + (s[i1][i2] - h[i1][i2] * dx2inv) * p[i2] * v2 * dt2
########Plotting########
plt.plot(x,f[50])
maxf = 1.5*amp
minf = -1.5*amp
plt.axis([lox,upx,minf,maxf])
plt.xlabel('x')
plt.ylabel('f(x,t)')
# vertical colored bars representing density
plt.axvspan(lox, pcl, facecolor='g', alpha=0.1)
plt.axvspan(pcl, upx, facecolor='g', alpha=0.2)
# text with density values
plt.text(pcl-0.2*upx,0.8*maxf,r'$\rho = $%s'%(p1),fontsize=15)
plt.text(pcl+0.05*upx,0.8*maxf,r'$\rho = $%s'%(p2),fontsize=15)
plt.show()
Unfortunately this code does not produce the correct result (two Gaussian pulses traveling left and right away from x=0). It instead produces one Gaussian pulse that grows with time. Does anyone know what error I am making?
Thank you very much.
It has been some time since you posted this, but if it is of any help, here is a code to generate Gaussian pulses. I am not good at programming so i am sorry if this code is obfuscating. I have used 1D FDTD wave propagation equation for an EM wave (unitless) :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#defining dimensions
xdim=720
time_tot = 500
xsource = xdim/2
#stability factor
S=1
#Speed of light
c=1
epsilon0=1
mu0=1
delta =1
deltat = S*delta/c
Ez = np.zeros(xdim)
Hy = np.zeros(xdim)
epsilon = epsilon0*np.ones(xdim)
mu = mu0*np.ones(xdim)
fig , axis = plt.subplots(1,1)
axis.set_xlim(len(Ez))
axis.set_ylim(-3,3)
axis.set_title("E Field")
line, = axis.plot([],[])
def init():
line.set_data([],[])
return line,
def animate(n, *args, **kwargs):
Hy[0:xdim-1] = Hy[0:xdim-1]+(delta/(delta*mu[0:xdim-1]))*(Ez[1:xdim]-Ez[0:xdim-1])
Ez[1:xdim]= Ez[1:xdim]+(delta/(delta*epsilon[1:xdim]))*(Hy[1:xdim]-Hy[0:xdim-1])
Ez[xsource] = Ez[xsource] + 30.0*(1/np.sqrt(2*np.pi))*np.exp(-(n-80.0)**2/(100))
ylims = axis.get_ylim()
if (abs(np.amax(Ez))>ylims[1]):
axis.set_ylim(-(np.amax(Ez)+2),np.amax(Ez)+2)
line.set_data(np.arange(len(Ez)),Ez)
return line,
ani = animation.FuncAnimation(fig, animate, init_func=init, frames=(time_tot), interval=10, blit=False, repeat =False)
fig.show()
I hope it helps. :)

Categories

Resources