Skip to content

Commit 5391e66

Browse files
committed
Add notebook with examples of KdV solutions.
1 parent 1923086 commit 5391e66

File tree

1 file changed

+270
-0
lines changed

1 file changed

+270
-0
lines changed

KdV Examples.ipynb

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "cfc06113",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"import numpy as np\n",
11+
"%matplotlib inline\n",
12+
"import matplotlib\n",
13+
"import matplotlib.pyplot as plt\n",
14+
"import matplotlib.animation\n",
15+
"from IPython.display import HTML\n",
16+
"font = {'size' : 15}\n",
17+
"matplotlib.rc('font', **font)"
18+
]
19+
},
20+
{
21+
"cell_type": "code",
22+
"execution_count": null,
23+
"id": "0209d0a0",
24+
"metadata": {},
25+
"outputs": [],
26+
"source": [
27+
"def rk3(u,xi,rhs):\n",
28+
" y2 = u + dt*rhs(u,xi)\n",
29+
" y3 = 0.75*u + 0.25*(y2 + dt*rhs(y2,xi))\n",
30+
" u_new = 1./3 * u + 2./3 * (y3 + dt*rhs(y3,xi))\n",
31+
" return u_new\n",
32+
"\n",
33+
"\n",
34+
"def rhs(u, xi, epsilon=1.0):\n",
35+
" uhat = np.fft.fft(u)\n",
36+
" return -u*np.real(np.fft.ifft(1j*xi*uhat)) - epsilon*np.real(np.fft.ifft(-1j*xi**3*uhat))\n",
37+
" \n",
38+
"def solve_KdV(u0,tmax=1.,m=256,epsilon=1.0, ylims=(-100,300)):\n",
39+
" \"\"\"Solve the KdV equation using Fourier spectral collocation in space\n",
40+
" and SSPRK3 in time, on the domain (-pi, pi). The input u0 should be a function.\n",
41+
" \"\"\"\n",
42+
" # Grid\n",
43+
" L = 2*np.pi\n",
44+
" x = np.arange(-m/2,m/2)*(L/m)\n",
45+
" xi = np.fft.fftfreq(m)*m*2*np.pi/L\n",
46+
"\n",
47+
" dt = 1.73/((m/2)**3)\n",
48+
" u = u0(x)\n",
49+
" uhat2 = np.abs(np.fft.fft(u))\n",
50+
"\n",
51+
" num_plots = 400\n",
52+
" nplt = np.floor((tmax/num_plots)/dt)\n",
53+
" nmax = int(round(tmax/dt))\n",
54+
"\n",
55+
" fig = plt.figure(figsize=(12,8))\n",
56+
" axes = fig.add_subplot(111)\n",
57+
" line, = axes.plot(x,u,lw=3)\n",
58+
" xi_max = np.max(np.abs(xi))\n",
59+
" axes.set_xlabel(r'$x$',fontsize=30)\n",
60+
" plt.close()\n",
61+
"\n",
62+
" frames = [u.copy()]\n",
63+
" tt = [0]\n",
64+
" uuhat = [uhat2]\n",
65+
"\n",
66+
" for n in range(1,nmax+1):\n",
67+
" u_new = rk3(u,xi,rhs)\n",
68+
"\n",
69+
" u = u_new.copy()\n",
70+
" t = n*dt\n",
71+
" # Plotting\n",
72+
" if np.mod(n,nplt) == 0:\n",
73+
" frames.append(u.copy())\n",
74+
" tt.append(t)\n",
75+
" \n",
76+
" def plot_frame(i):\n",
77+
" line.set_data(x,frames[i])\n",
78+
" axes.set_title('t= %.2e' % tt[i])\n",
79+
" axes.set_xlim((-np.pi,np.pi))\n",
80+
" axes.set_ylim(ylims)\n",
81+
"\n",
82+
" anim = matplotlib.animation.FuncAnimation(fig, plot_frame,\n",
83+
" frames=len(frames), interval=100)\n",
84+
"\n",
85+
" return HTML(anim.to_jshtml())"
86+
]
87+
},
88+
{
89+
"cell_type": "markdown",
90+
"id": "3f0cfe80",
91+
"metadata": {},
92+
"source": [
93+
"## Initial sinusoid\n",
94+
"\n",
95+
"Here we set up something similar to the FPUT experiment, with a single low-frequency mode as initial condition on a periodic domain. Notice how, at some later times, the solution comes close to the initial condition."
96+
]
97+
},
98+
{
99+
"cell_type": "code",
100+
"execution_count": null,
101+
"id": "7bd939ca",
102+
"metadata": {},
103+
"outputs": [],
104+
"source": [
105+
"def u0(x):\n",
106+
" return 100*np.sin(x)\n",
107+
"solve_KdV(u0)"
108+
]
109+
},
110+
{
111+
"cell_type": "markdown",
112+
"id": "784f0474",
113+
"metadata": {},
114+
"source": [
115+
"## Formation of a soliton train from an initial positive pulse."
116+
]
117+
},
118+
{
119+
"cell_type": "code",
120+
"execution_count": null,
121+
"id": "c38c986f",
122+
"metadata": {},
123+
"outputs": [],
124+
"source": [
125+
"def u0(x):\n",
126+
" return 2000*np.exp(-10*(x+2)**2)\n",
127+
"solve_KdV(u0, tmax=0.005, ylims=(-100,3000))"
128+
]
129+
},
130+
{
131+
"cell_type": "markdown",
132+
"id": "f191670a",
133+
"metadata": {},
134+
"source": [
135+
"# Interaction of two solitons"
136+
]
137+
},
138+
{
139+
"cell_type": "code",
140+
"execution_count": null,
141+
"id": "76b69166",
142+
"metadata": {},
143+
"outputs": [],
144+
"source": [
145+
"A = 25; B = 16;\n",
146+
"def u0(x):\n",
147+
" return 3*A**2/np.cosh(0.5*(A*(x+2.)))**2 + 3*B**2/np.cosh(0.5*(B*(x+1)))**2\n",
148+
"solve_KdV(u0,tmax = 0.006, ylims=(-10,3000))"
149+
]
150+
},
151+
{
152+
"cell_type": "markdown",
153+
"id": "fa18aa7b",
154+
"metadata": {},
155+
"source": [
156+
"The next simulation shows a comparison between the propagation of a single soliton versus the interaction of two solitons."
157+
]
158+
},
159+
{
160+
"cell_type": "code",
161+
"execution_count": null,
162+
"id": "b24c8e5d",
163+
"metadata": {},
164+
"outputs": [],
165+
"source": [
166+
"# Grid\n",
167+
"m = 256\n",
168+
"L = 2*np.pi\n",
169+
"x = np.arange(-m/2,m/2)*(L/m)\n",
170+
"xi = np.fft.fftfreq(m)*m*2*np.pi/L\n",
171+
"\n",
172+
"dt = 1.73/((m/2)**3)\n",
173+
"\n",
174+
"A = 25; B = 16;\n",
175+
"u = 3*A**2/np.cosh(0.5*(A*(x+2.)))**2 + 3*B**2/np.cosh(0.5*(B*(x+1)))**2\n",
176+
"v = 3*A**2/np.cosh(0.5*(A*(x+2.)))**2\n",
177+
"\n",
178+
"tmax = 0.006\n",
179+
"\n",
180+
"uhat2 = np.abs(np.fft.fft(u))\n",
181+
"\n",
182+
"num_plots = 400\n",
183+
"nplt = np.floor((tmax/num_plots)/dt)\n",
184+
"nmax = int(round(tmax/dt))\n",
185+
"\n",
186+
"fig = plt.figure(figsize=(12,8))\n",
187+
"axes = fig.add_subplot(111)\n",
188+
"line, = axes.plot(x,u,lw=3)\n",
189+
"line2, = axes.plot(x,v,lw=3)\n",
190+
"xi_max = np.max(np.abs(xi))\n",
191+
"axes.set_xlabel(r'$x$',fontsize=30)\n",
192+
"plt.close()\n",
193+
"\n",
194+
"frames = [u.copy()]\n",
195+
"vframes = [v.copy()]\n",
196+
"tt = [0]\n",
197+
"uuhat = [uhat2]\n",
198+
"\n",
199+
"for n in range(1,nmax+1):\n",
200+
" u_new = rk3(u,xi,rhs)\n",
201+
" v_new = rk3(v,xi,rhs)\n",
202+
"\n",
203+
" u = u_new.copy()\n",
204+
" v = v_new.copy()\n",
205+
" t = n*dt\n",
206+
" # Plotting\n",
207+
" if np.mod(n,nplt) == 0:\n",
208+
" frames.append(u.copy())\n",
209+
" vframes.append(v.copy())\n",
210+
" tt.append(t)\n",
211+
" uhat2 = np.abs(np.fft.fft(u))\n",
212+
" uuhat.append(uhat2)\n",
213+
" \n",
214+
"def plot_frame(i):\n",
215+
" line.set_data(x,frames[i])\n",
216+
" line2.set_data(x,vframes[i])\n",
217+
" power_spectrum = np.abs(uuhat[i])**2\n",
218+
" axes.set_title('t= %.2e' % tt[i])\n",
219+
" axes.set_xlim((-np.pi,np.pi))\n",
220+
" axes.set_ylim((-10,3000))\n",
221+
" \n",
222+
"anim = matplotlib.animation.FuncAnimation(fig, plot_frame,\n",
223+
" frames=len(frames), interval=100)\n",
224+
"\n",
225+
"HTML(anim.to_jshtml())"
226+
]
227+
},
228+
{
229+
"cell_type": "markdown",
230+
"id": "70b44acc",
231+
"metadata": {},
232+
"source": [
233+
"## Formation of a dispersive shockwave"
234+
]
235+
},
236+
{
237+
"cell_type": "code",
238+
"execution_count": null,
239+
"id": "758b2d7e",
240+
"metadata": {},
241+
"outputs": [],
242+
"source": [
243+
"def u0(x):\n",
244+
" return -500*np.exp(-10*(x-2)**2)\n",
245+
"solve_KdV(u0, tmax=0.005, epsilon=0.1, ylims=(-600,300))"
246+
]
247+
}
248+
],
249+
"metadata": {
250+
"kernelspec": {
251+
"display_name": "Python 3 (ipykernel)",
252+
"language": "python",
253+
"name": "python3"
254+
},
255+
"language_info": {
256+
"codemirror_mode": {
257+
"name": "ipython",
258+
"version": 3
259+
},
260+
"file_extension": ".py",
261+
"mimetype": "text/x-python",
262+
"name": "python",
263+
"nbconvert_exporter": "python",
264+
"pygments_lexer": "ipython3",
265+
"version": "3.10.4"
266+
}
267+
},
268+
"nbformat": 4,
269+
"nbformat_minor": 5
270+
}

0 commit comments

Comments
 (0)