FFT based method for advection type models (Burgers)
This script solves the Burgers equation using spectral methods. The waves will eventually steepen and form a shock which is a problem for spectral methods. This model has viscosity which can tame the shock formation however many times this is not enough. To fix this we can use spectral filters which help stop the build up of high wavenumbers (when it steepens to a shock). There are multiple different filters provided in the script. Currently it uses Boyd's 2/3 filter however you can easily modify the code to use a different one.
Contents
clear all; close
Parameters
Define physical parameters for the model.
nu = 1e-3;
Define a spatial grid.
xmin = -1; xmax = 1; N = 2^10; x = linspace(xmin,xmax,N+1); x = x(1:N); dx = x(2)-x(1); L = xmax - xmin;
Make initial condition.
u_amp = 1; sig = 0.15*xmax; u = u_amp*exp(-(x/sig).^2); u0 = u;
Time step and number of steps.
t = 0; % initial time t_f = 1; % final time t_plot = 0.1; % plot interval dt = 1e-3; % time step
Total steps and plot steps.
N_stps = round(t_f/dt); N_plot = round(t_plot/dt);
Wave numbers.
dk = 2*pi/L; ks = [0:N/2-1 0 -N/2+1:-1]*dk; ks2 = ks.*ks; kmax = max(abs(ks));
Filters
Define specific filters: Boyd 2/3 filter.
f_step = @(kc,k) 1.*(abs(k)<kc) + 0.*(abs(k)>=kc); f_23 = @(k) f_step(2/3, k);
Gaussian filter.
f_gauss = @(a,b,kc,k) 1.*(abs(k)<=kc) + min(1, exp(-a*(abs(k)-kc).^b./(1-kc).^b)).*(abs(k)>kc);
Hyperviscosity.
f_hyper = @(a,b,k) exp(-a*abs(k).^b);
Bump filters.
f_bump = @(a,b,kc,k) 1.*(abs(k)<=kc) + min(1, exp(a*(1-1./(1-((abs(k)-kc)./(1-kc)).^b)))).*(abs(k)>kc); f_bump2 = @(a,b,k1,k2,k) 1.*(abs(k)<=k1) ... + min(1, exp(a*(1-1./(1-((abs(k)-k1)./(k2-k1)).^b)))).*(abs(k)>k1 & abs(k)<k2) ... + 0.*(abs(k)>=k2);
Parameters.
filt_alpha = 0.2; filt_beta = 4; kcut = 0.5*kmax; u_filter = f_23(ks/kmax);
Ploting
Plot initial conditions.
figure(2) clf subplot(2,1,1) plot(x,u,'b-') grid on xlabel('x'); ylabel('u'); title(['time = ' num2str(t,2)]); axis([xmin xmax -max(abs(u0)) 1.4*max(abs(u0))]) subplot(2,1,2) uf = fft(u); spec1 = uf.*conj(uf); plot(fftshift(ks)/kmax,abs(fftshift(spec1)),'b.') xlabel('k'); ylabel('spectrum'); grid on axis([0 1 1e-10-eps 1e5]) set(gca,'yscale','log') drawnow
Plot the filter.
figure(1) clf plot(ks/max(ks),u_filter,'b.') title('filters') xlabel('k (normalized)')
Main Loop
LHS of implicit formulation.
lhopu = 1 + dt*ks2*nu;
Euler time stepping
for ii=1:N_stps
t = t+dt;
Compute the nonlinear terms (these are treated explicitly).
uux = u.*ifft(i*ks.*fft(u)); uxx = ifft(-ks2.*fft(u));
Now in the transformed domain treat the diffusion implicitly.
rhs = u - dt*uux + dt*nu*uxx; uincr = real(ifft(u_filter.*(fft(rhs)))); u = uincr(1:N); if sum(isnan(u)) > 0 disp(['simulation broke at t=',num2str(t)]) return end if mod(ii,N_plot) == 0
Plot
Update the plots.
figure(2) clf subplot(2,1,1) plot(x,u,'b-') grid on xlabel('x'); title(['time = ' num2str(t,3)]); axis([xmin xmax -max(max(u0)) 1.4*max(max(u0))]) subplot(2,1,2) uf = fft(u); spec1 = uf.*conj(uf); plot(fftshift(ks)/kmax,abs(fftshift(spec1)),'b.') xlabel('k'); ylabel('spectrum'); grid on axis([0 1 1e-10-eps 1e5]) set(gca,'yscale','log') drawnow
end
end