% [u,x,t,kk,amp] = int_fact_KdV(t_0,t_f,dt,NPrint,N) % % this solves the periodic KdV equation % % u_t + 6 u u_x + u_xxx = 0 % % with periodic boundary conditions using spectral derivatives % and an integrating factor for the time-stepping. % t_0 is the initial time, t_f is the % final time, dt is the time-step size, N is the number of mesh-points, % and M is the number of printouts. It also returns the power spectrum of the % solution, where kk is the collection of wave numbers and amp = log(f_k^2) % is the magnitude of the kth Fourier mode. % % N SHOULD BE A POWER OF 2! % (It will work no matter what, but will go much faster if N is a power % of 2.) % % The initial data is set within the code, search for "SET INITIAL % DATA". % % To turn off the nonlinear effects, look within the tstep subroutine function [u,x,t,kk,amp] = int_fact_KdV(t_0,t_f,dt,NPrint,N) % define the mesh in space dx = 2*pi/N; x = 0:dx:2*pi-dx; x = x'; % the wave-numbers... kk = (-N/2+1):1:(N/2-1); % total number of steps to be taken: Ntot = (t_f-t_0)/dt; % test to see if Ntot is an integer, to see if your choice of dt % is compatible with your choice of t_0 and t_f if abs(Ntot - round(Ntot)) > 100000*eps disp(' ') disp('dt is not consistent with your choice of t_0 and t_f. Choose another dt!') disp(' ') return end Ntot = round(Ntot); % number of steps to be taken before a (screen) printout NRun = Ntot/NPrint; % test to see if NRun is an integer to see if your choice of dt is % consistent with NPrint if abs(NRun - round(NRun)) > 1000*eps disp(' ') disp('NPrint is not consistent with dt. Choose another NPrint!') disp(' ') return end NRun = round(NRun); % define the vector t that is to be printed out... t = t_0:NRun*dt:t_f; % SET INITIAL DATA % sigma = 20; % sigma = 100; % u_now = sigma/2*sech(sqrt(sigma)/2*(x-pi/2)).^2; sigma1 = 75; sigma2 = 250; u_now = sigma2/2*sech(sqrt(sigma2)/2*(x-pi/2)).^2; % u_now = zeros(size(u_now)); % u_now = u_now + sigma1/2*sech(sqrt(sigma1)/2*(x-pi)).^2; % We're computing solutions of % % u_t = - u_xxx + Non where Non = - 6 u u_x % % In Fourier space, this is % % d/dt u_k = i*k^3 u_k + Non_k % % which has the solution % % u_k(t) = u_k(0) exp(ik^3 t) + int_0^t exp(ik^3 (t-s)) Non_k(s) ds % % Approximating Non_k(s) with Non_k(0), % % u_k(t) = u_k(0) exp(ik^3 t) + i/k^3 Non_k(0) (1-exp(ik^3 t)) % % and so in Fourier space, % % u_k_new = u_k_now exp(ik^3 dt) + i/k^3 Non_k_now (1-exp(ik^3 dt)) % % u_0_new = u_0_now. % % To get a method with higher accuracy, I would've chosen a better % approximation of the integral than the left-hand rule. % save first printout: u(:,1) = u_now; v = fft(u_now); amp(N/2:N-1,1) = log10( abs(v(1:N/2)) + 1.e-16); amp(1:N/2-1,1) = log10( abs(v(N/2+2:N)) + 1.e-16); for jj=1:NPrint % take NRun time-steps for j=1:NRun % compute solution with one step of size dt u_coarse = tstep(u_now,dt,N); % compute solution with two steps of size dt/2 u_fine = tstep(u_now,dt/2,N); u_fine = tstep(u_fine,dt/2,N); % use Richardson extrapolation to combine u_coarse and % u_fine to get a solution with local truncation % error of O(dt^3)... u_now = 2*u_fine - u_coarse; end % save printout u(:,jj+1) = u_now; v = fft(u_now); amp(N/2:N-1,jj+1) = log10( abs(v(1:N/2)) + 1.e-16); amp(1:N/2-1,jj+1) = log10( abs(v(N/2+2:N)) + 1.e-16); end x(N+1) = 2*pi; u(N+1,:) = u(1,:); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function u_now = tstep(u_now,dt,N); % We're computing solutions of % % u_t = - u_xxx + Non where Non = - 6 u u_x % % In Fourier space, this is % % d/dt u_k = i*k^3 u_k + Non_k % % which has the solution % % u_k(t) = u_k(0) exp(ik^3 t) + int_0^t exp(ik^3 (t-s)) Non_k(s) ds % % Approximating Non_k(s) with Non_k(0), % % u_k(t) = u_k(0) exp(ik^3 t) + i/k^3 Non_k(0) (1-exp(ik^3 t)) % % and so in Fourier space, % % u_k_new = u_k_now exp(ik^3 dt) + i/k^3 Non_k_now (1-exp(ik^3 dt)) % % u_0_new = u_0_now. % Non = - 6 u u_x = - 3 (u^2)_x % Non_k = - 3 i k (u^2)_k Non = -3*u_now.^2; % now differentiate Non. Non = fft(Non); Non(1) = 0; for k=1:(N/2-1) Non(1+k) = i*k*Non(1+k); Non(N-k+1) = -i*k*Non(N-k+1); end % at this point, I have Non_k_now computed. If I want to remove the % nonlinear effects, then I set Non to zero as below % Non = zeros(size(Non)); % start by computing Fourier transform of u_now... v = fft(u_now); for k=1:(N/2-1) v(1+k) = v(1+k)*exp(i*k^3*dt) + i/k^3*Non(1+k)*(1-exp(i*k^3*dt)); v(N-k+1) = v(N-k+1)*exp(i*(-k)^3*dt) + i/(-k)^3*Non(N-k+1)*(1-exp(i*(-k)^3*dt)); end % at this point, v is v_new_k % take the inverse fourier transform. u_now = ifft(v); % for good measure, impose reality. u_now = real(u_now);