--- title: 8-1. Fourier approximations - KdV equation tags: Spectral method --- **Reference** 1. Spectral methods by *J. Shen*, *T. Tang* and *L.-L. Wang* --- ## Korteweg–de Vries (KdV) Equation Consider the KdV equation in the whole space: $$ u_t + uu_{y}+u_{yyy} = 0, \quad y\in(-\infty, \infty), \quad t\ge 0, $$ with initial condition $$ u(y,0) = u_0(y), \quad y\in(-\infty, \infty), $$ which has the exact solution $$ u(y,t) = 12 \kappa^2 sech^2(\kappa(y-y_0)-4\kappa^3 t), $$ where $y_0$ is the center of the initial profile $u(y,0)$, and $\kappa$ is a constant related to the traveling phase speed. Since $u(y,t)$ decays exponentially to zero as $|y|\to\infty$, we can truncate the infinite interval to a finite one $[-\pi L, \pi L]$ with $L > 0$, and approximate the boundary conditions by the periodic boundary conditions on $[-\pi L, \pi L]$. It is expected that the initial-boundary valued problem with periodic boundary conditions can provide a good approximation to the original initial-valued problem as long as the soliton does not reach the boundaries. For convenience, we map the interval $[-\pi L, \pi L]$ to $[0, 2\pi]$ through the coordinate transform: $$ x = \frac{y}{L}+\pi, \quad y = L(x-\pi), \quad x\in[0, 2\pi], \quad y\in[-\pi L, \pi L], $$ and denote $$ v(x,t) = u(y,t), \quad v_0(x) = u_0(y). $$ The transformed KdV equation reads $$ v_t + \frac{1}{L}vv_{x}+\frac{1}{L^3}v_{xxx} = 0, \quad x\in [0, 2\pi], \quad t\ge 0, $$ $$ v(x,0) = v_0(x). $$ Writing $v(x,t) = \sum_k \hat{v}_k(t) e^{ikx}$, taking the inner product of the equation with $e^{ikx}$ and using the fact that $vv_{x} = \frac{1}{2}(v^2)_x$, we obtain $$ \frac{d\hat{v}_k}{dt} - \frac{ik^3}{L^3}\hat{v}_k + \frac{ik}{2L}\widehat{(v^2)}_k = 0, \quad k=0,\pm 1, \cdots, $$ with the initial condition $$ \hat{v}_k(0) = \frac{1}{2\pi}\int^{2\pi}_0 v_0(x)e^{ikx}dx. $$ As suggestd by Trefethen we solve the system using method of integrating factor. The equations are multiplied by the integrating factor $e^{-ik^3 t/L^3}$ to $$ \frac{d}{dt}\left[e^{-ik^3t/L^3}\hat{v}_k\right] = -\frac{ik}{2L}e^{-ik^3t/L^3}\widehat{(v^2)}_k, \quad k=0,\pm 1, \cdots. $$ This system can then be solved by standard ODE solver such as Runge-Kutta method, as shown in the following example. ```Matlab % p27.m - Solve KdV eq. u_t + uu_x + u_xxx = 0 on [-pi,pi] by % FFT with integrating factor v = exp(-ik^3t)*u-hat. % Set up grid and two-soliton initial data: N = 256; dt = .4/N^2; x = (2*pi/N)*(-N/2:N/2-1)'; A = 25; B = 16; clf, drawnow, set(gcf,'renderer','zbuffer') u = 3*A^2*sech(.5*(A*(x+2))).^2 + 3*B^2*sech(.5*(B*(x+1))).^2; v = fft(u); k = [0:N/2-1 0 -N/2+1:-1]'; ik3 = 1i*k.^3; % Solve PDE and plot results: tmax = 0.006; nplt = floor((tmax/25)/dt); nmax = round(tmax/dt); udata = u; tdata = 0; h = waitbar(0,'please wait...'); for n = 1:nmax t = n*dt; g = -.5i*dt*k; E = exp(dt*ik3/2); E2 = E.^2; a = g.*fft(real( ifft( v ) ).^2); b = g.*fft(real( ifft(E.*(v+a/2)) ).^2); % 4th-order c = g.*fft(real( ifft(E.*v + b/2) ).^2); % Runge-Kutta d = g.*fft(real( ifft(E2.*v+E.*c) ).^2); v = E2.*v + (E2.*a + 2*E.*(b+c) + d)/6; if mod(n,nplt) == 0 u = real(ifft(v)); waitbar(n/nmax) udata = [udata u]; tdata = [tdata t]; end end waterfall(x,tdata,udata'), colormap(1e-6*[1 1 1]); view(-20,25) xlabel x, ylabel t, axis([-pi pi 0 tmax 0 2000]), grid off set(gca,'ztick',[0 2000]), close(h), pbaspect([1 1 .13]) ``` One can also re-write the equations by make the following substitution $$ g_k=e^{-ik^3t/L^3}, \quad \tilde{u}_k = g_k\hat{v}_k, $$ the system is then written as $$ \frac{d}{dt}\tilde{u}_k = -\frac{ik}{2L}g_k*fft\left(\left[ifft(g^{-1}*\tilde{u})\right]^2\right), \quad k=0,\pm 1, \cdots. $$ The ODE solvers can be directly applied. ### Julia code(昆毅): ```julia using LinearAlgebra using Plots using FFTW # p27.m - Solve KdV eq. u_t + uu_x + u_xxx = 0 on [-pi,pi] by # FFT with integrating factor v = exp(-ik^3t)*u-hat. # Set up grid and two-soliton initial data: N = 256; dt = .4/N^2; x = (2*pi/N)*(-N/2:N/2-1)'; A = 25; B = 16; u=zeros(length(x)) for i = 1:length(x) u[i] = 3*A^2*sech(.5*(A*(x[i]+2))).^2 + 3*B^2*sech(.5*(B*(x[i]+1))).^2 end v = fft(u); k = [0:N/2-1;0;-N/2+1:-1]; ik3 = 1im*k.^3; # Solve PDE and plot results: tmax = 0.006; nplt = floor((tmax/25)/dt); nmax = round(tmax/dt); udata = u; tdata = 0; for n = 1:nmax t = n*dt; g = -.5im*dt*k; E = exp.(dt*ik3/2); E2 = E.^2; a = g.*fft(real( ifft( v ) ).^2); b = g.*fft(real( ifft(E.*(v+a/2)) ).^2); # 4th-order c = g.*fft(real( ifft(E.*v + b/2) ).^2); # Runge-Kutta d = g.*fft(real( ifft(E2.*v+E.*c) ).^2); v = E2.*v + (E2.*a + 2*E.*(b+c) + d)/6; if mod(n,nplt) == 0 u = real(ifft(v)); udata = [udata u]; tdata = [tdata t]; end end p = plot(x',udata[:,1]) anim = Animation() for i = range(2, stop=26, length=250) T=round(tdata[Int(floor(i))],digits=6) plot(x', udata[:,Int(floor(i))],label="t=$T",ylim=(0,2000)) frame(anim) end gif(anim, "KdV Equation.gif") ``` @Woodystick (1). 研究看看 label 時間那邊能不能顯示到小數點後幾位就好, 比如說6或7位, 顯示這麼長實在很醜. (2). 然後也要固定 y 軸範圍, 不然跳來跳去的. (3). 還有 x-t-u 三維的圖也研究看看怎麼做. ![](https://i.imgur.com/XMtTDX1.png) ![](https://i.imgur.com/KxS6rIx.gif) ### Python code (沛聖) The following code solves the boundary value problem $$ \frac{d}{dt} e^{-ik^3t} v_k(t) = -\frac{ik}{2} e^{-ik^3t} (\widehat{u^2})_k,\quad k=0,\pm 1,\dots,\pm (N/2-1),N/2, $$ where $v_k(t) = \widehat{u}(k)$, using Runge-Kutta 4th Order Method #### Code ```python import numpy as np from numpy.fft import fft,ifft from numpy.linalg import norm import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import axes3d # Initialize variables N = 256 dt = .4/N**2 x = 2*np.pi/N * np.arange(-N/2,N/2) k = np.concatenate( (np.arange(N/2) , np.array([0]) , np.arange(-N/2+1,0)) ) ik3 = 1j*k**3 # Initialize initial condition A = 25 B = 16 u = 3*(A**2)/np.cosh(0.5*(A*(x+2)))**2 + 3*(B**2)/np.cosh(0.5*(B*(x+1)))**2 v = fft(u) # Initialize parameter for for-loop tmax = 0.006 nplt = np.floor(tmax/25/dt) nmax = round(tmax/dt) # Create container to store u and t udata = np.array(u) tdata = np.array([0]) # Iterate over [0,tmax] for n in range(1,nmax+1): t = n*dt g = -.5j*dt*k E = np.exp(dt*ik3/2) E2 = E**2 a = g*fft( (ifft(v).real)**2 ) b = g*fft( (ifft(E*(v+a/2)).real)**2 ) c = g*fft( (ifft(E*v + b/2).real)**2 ) d = g*fft( (ifft(E2*v + E*c).real)**2 ) v = E2*v + (E2*a + 2*E*(b+c) +d)/6 if n%nplt == 0: u = ifft(v).real udata = np.vstack( (udata,u) ) tdata = np.hstack( (tdata,t) ) # Create the waterfall plot x_grid , t_grid = np.meshgrid(x,tdata) fig = plt.figure() ax = fig.add_subplot(111,projection='3d') ax.plot_wireframe(x_grid,t_grid,udata) ax.set_xlabel('x') ax.set_ylabel('t') plt.show() ``` #### Results ![](https://i.imgur.com/YafcYCb.png) ![](https://i.imgur.com/MtWCBxt.gif) ### C++ code (沂君) ```(C++) //compile with g++ EX8_1_graph.cpp -L.\. -lfftw3 -o E81G #include <iostream> #include <cmath> #include <fstream> #include <complex> #include <vector> #include "fftw3.h" #define REAL 0 #define IMAG 1 #define PI 3.141592653589793 using namespace std; void copy( fftw_complex c2[], fftw_complex c1[], int N); //copy c1 into c2 void norm_real( fftw_complex c[], int N); //normalize and set imaginary part to 0 fftw_complex* mult( fftw_complex c1[], fftw_complex c2[], int N); //multiply fftw_complex* multc( fftw_complex c[], int num, int N); //multiply a constant fftw_complex* add( fftw_complex c1[], fftw_complex c2[], int N); //add fftw_complex* div( fftw_complex c[], int num, int N); //divide by a constant void u_to_file( fftw_complex v[], double t, double x[], int N, ofstream &outfile); //output real u at t int main(){ ofstream outfile("./EX8_output.txt"); outfile.precision(15); outfile << "# X T U" << endl; //% Set up grid and two-soliton initial data: int N = 256, A=25, B=16; double dt = 0.4/powl(N,2); double x[N], k[N]; fftw_complex u[N], v[N], ik3[N]; fftw_complex *in, *out; vector<int> tdata; in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); for(int i=0; i<N; i++) { x[i] = (-N/2+i)*2*PI/N; u[i][REAL] = 3*powl(A,2)*powl(1/coshl(0.5*(A*(x[i]+2))),2) + 3*powl(B,2)*powl(1/coshl(0.5*(B*(x[i]+1))),2); u[i][IMAG] = 0; } u_to_file(u, 0, x, N,outfile); outfile << endl << endl; fftw_plan plan1 = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_MEASURE); fftw_plan plan2 = fftw_plan_dft_1d(N, in, out, FFTW_BACKWARD, FFTW_MEASURE); copy(in, u, N); fftw_execute(plan1); copy(v, out, N); for(int i=0; i<N; i++) { if(i == (N/2)) k[i] = 0; else if(i < (N/2)) k[i] = i; else if(i > (N/2)) k[i] = -N + i; ik3[i][REAL] = 0; ik3[i][IMAG] = powl(k[i],3); } //% Solve PDE and plot results: double tmax = 0.006, nmax = round(tmax/dt), t; int nplt = floor((tmax/25)/dt); fftw_complex g[N], E[N], E2[N]; fftw_complex *a, *b, *c, *d; for(int n=1; n<=nmax; n++) { t = n*dt; for(int i=0; i<N; i++) { g[i][REAL] = 0; g[i][IMAG] = -0.5*dt*k[i]; complex<double> c1(dt*ik3[i][REAL]*0.5,dt*ik3[i][IMAG]*0.5); E[i][REAL] = real(exp(c1)); E[i][IMAG] = imag(exp(c1)); complex<double> c2(E[i][REAL],E[i][IMAG]); E2[i][REAL] = real(pow(c2,2)); E2[i][IMAG] = imag(pow(c2,2)); } //a copy(in, v, N); fftw_execute(plan2); norm_real(out, N); copy(in, mult(out, out, N), N); fftw_execute(plan1); a = mult(g, out, N); //b copy(in, mult(E, add(v, div(a, 2, N), N), N), N); fftw_execute(plan2); norm_real(out, N); copy(in, mult(out, out, N), N); fftw_execute(plan1); b = mult(g, out, N); //c copy(in, add(mult(E, v, N), div(b, 2, N), N), N); fftw_execute(plan2); norm_real(out, N); copy(in, mult(out, out, N), N); fftw_execute(plan1); c = mult(g, out, N); //d copy(in, add(mult(E2, v, N), mult(E, c, N), N), N); fftw_execute(plan2); norm_real(out, N); copy(in, mult(out, out, N), N); fftw_execute(plan1); d = mult(g, out, N); //v copy(v,add(mult(E2, v, N) ,div(add(add(mult(E2, a, N), multc(mult(E, add(b, c, N), N), 2, N) , N), d, N), 6, N) ,N) ,N); if(n%nplt == 0) { copy(in, v, N); fftw_execute(plan2); norm_real(out, N); copy(u, out, N); tdata.push_back(t); u_to_file(u, t, x, N,outfile); outfile << endl << endl; } } //Plot results: FILE* gp = _popen("gnuplot","w"); if (gp == NULL) { cout<<("Cannot open gnuplot!\n")<<endl;; return 0; } fprintf(gp,"set xlabel 'X'\nset ylabel 'T'\nset zlabel 'U'\nset zrange [0:2000]\nset view 30,351\n"); fprintf(gp,"set term png\nset output 'EX8_1_g.png'\n"); fprintf(gp,"splot 'EX8_output.txt' using 1:2:3 with lines title 'u'\n"); fprintf(gp,"set term gif size 800,400 \nset term gif animate delay 20 \nset output 'EX8_1.gif'\n"); fprintf(gp,"set ylabel 'U'\n"); for(int i=0; i<=nmax/39; i++) { fprintf(gp,"plot 'EX8_output.txt' using 1:3 index %i with lines lw 1.5 title 't=%f'\n",i+1,39*(i+1)*dt); } fprintf(gp,"set output\n"); _pclose(gp); fftw_destroy_plan(plan1); fftw_destroy_plan(plan2); fftw_free(in); fftw_free(out); return 0; } void copy( fftw_complex c2[], fftw_complex c1[], int N) { for(int i=0; i<N; i++) { c2[i][REAL] = c1[i][REAL]; c2[i][IMAG] = c1[i][IMAG]; } } void norm_real( fftw_complex c[], int N) { for(int i=0; i<N; i++) { c[i][REAL] = c[i][REAL]/N; c[i][IMAG] = 0; } } fftw_complex* mult( fftw_complex c1[], fftw_complex c2[], int N) { fftw_complex *c3; c3 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); for(int i=0; i<N; i++) { complex<double> c_1(c1[i][REAL],c1[i][IMAG]); complex<double> c_2(c2[i][REAL],c2[i][IMAG]); c3[i][REAL] = real(c_1*c_2); c3[i][IMAG] = imag(c_1*c_2); } return c3; } fftw_complex* multc( fftw_complex c[], int num, int N) { fftw_complex *c3; c3 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); for(int i=0; i<N; i++) { c3[i][REAL] = c[i][REAL]*num; c3[i][IMAG] = c[i][IMAG]*num; } return c3; } fftw_complex* add( fftw_complex c1[], fftw_complex c2[], int N) { fftw_complex *c3; c3 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); for(int i=0; i<N; i++) { c3[i][REAL] = c1[i][REAL] + c2[i][REAL]; c3[i][IMAG] = c1[i][IMAG] + c2[i][IMAG]; } return c3; } fftw_complex* div( fftw_complex c[], int num, int N) { fftw_complex *c3; c3 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); for(int i=0; i<N; i++) { c3[i][REAL] = c[i][REAL]/num; c3[i][IMAG] = c[i][IMAG]/num; } return c3; } void u_to_file( fftw_complex v[], double t, double x[], int N, ofstream &outfile) { for(int i=0; i<N-1; i++) { outfile << x[i] << " " << t << " " << v[i][REAL] << endl; } } ``` #### Results: ![](https://i.imgur.com/rOzatj1.png) ![](https://i.imgur.com/MgCklJw.gif)