% [u,x,t,kk,amp] = burgers(t_0,t_f,M,N)
%
% solves the periodic Burgers equation without viscosity:
%                u_t + u u_x = u_t + (u^2/2)_x = 0 
% with initial data u_0 = cos(x) with periodic boundary conditions using 
% spectral derivatives in
% space and explicit time-stepping.  t_0 is the initial time, t_f is the
% final time, N is the number of mesh-points, and M is the number of
% time steps.  err is the error. 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.)
%
% Note: for burgers equation with initial data cos(x), we know that the 
% solution blows up at time: t = 1

function [u,x,t,kk,amp] = burgers(t_0,t_f,M,N)

% define the mesh in space
dx = 2*pi/N;
x = 0:dx:2*pi-dx;
x = x';
kk = 0:1:(N/2-1);

% define the mesh in time
dt = (t_f-t_0)/M;
t = t_0:dt:t_f;

for j=1:N
  u(j,1) = cos(x(j));
end 
v = fft(u(:,1));
for k=0:(N/2-1)
  if k == 0 
    amp(k+1,1) = log10(sqrt(v(1+k)^2)/N + 10e-16);
  else
    amp(k+1,1) = log10(sqrt(real(v(1+k)*v(N-k+1)))/N + 1e-16);    
  end
end

% first I take an explicit Euler Step:
% u_t + (u^2/2)_x = 0.  Hence u_t = - (u^2/2)_x.  On the level of
% fourier coefficients: d/dt u(k) = - i k temp(k) where temp = u_old^2/2
%
% Method: Take the fourier transform of temp and of u_old.  At each
% mode, multiply by temp's fft by -dt*i*k where k is the mode-number.  
% write u_new = u_old - dt*i*k*temp.  Take the inverse fft.
%
% I HAVE TO BE CAREFUL NOT TO USE "i" AS A LOOP INDEX ANYWHERE SINCE
% MATLAB WILL THEN FORGET THAT "i" IS THE SQUARE ROOT OF -1!
temp = u(:,1).^2/2;
temp = fft(temp);
v = fft(u(:,1));
for k = 1:(N/2-1)
% k is the wave-number.  Note that the zero mode v(1) is untouched since
% it is the mean.
  v(1+k) = v(1+k) - dt*i*k*temp(1+k);
  v(N-k+1) = v(N-k+1) - dt*i*(-k)*temp(N-k+1);
end
for k=0:(N/2-1)
  if k == 0 
    amp(k+1,j+1) = log10(v(1+k)/N + 10e-16);
  else
    amp(k+1,j+1) = log10(sqrt(real(v(1+k)*v(N-k+1)))/N + 10e-16);    
  end
end
% take the inverse transform.  I've cut off the imaginary parts since
% they're going to be at the level of round-off anyway.  (the true
% solution started out real-valued and will remain real.  If I wanted to
% be super-cautious, I'd keep the imaginary parts of the computed
% solution around to make sure they aren't growing on me.)
u(:,2) = real(ifft(v)); 


% now I switch to leap-frog time-stepping, which is linearly stable
% for hyperbolic equations 
for j=2:M
  temp = u(:,j).^2/2;
  temp = fft(temp);
  v = fft(u(:,j-1));
  for k = 1:(N/2-1)
% k is the wave-number.  Note that the zero mode v(1) is untouched since
% it is the mean.
    v(1+k) = v(1+k) - 2*dt*i*k*temp(1+k);
    v(N-k+1) = v(N-k+1) - 2*dt*i*(-k)*temp(N-k+1);
  end
  for k=0:(N/2-1)
    if k == 0 
      amp(k+1,j+1) = log10(v(1+k)/N + 10e-16);
    else
      amp(k+1,j+1) = log10(sqrt(real(v(1+k)*v(N-k+1)))/N + 10e-16);    
    end
  end
  u(:,j+1) = real(ifft(v)); 
end

