====== IAM 950 HW1 ======
**Problem 1.** Write numerical simulation for the heat eqn $u_t = \nu u_{xx}$ on a periodic domain
$[-L_x/2, L_x/2]$ using Fourier spatial discretization and Crank-Nicolson temporal discretization.
Verify that your code works correctly by simulating the Gaussian-decay solution
u(x,t) = (4 \pi \nu t)^{-1/2} e^{-x^2/4\nu t}
from t = 1 to 100 for parameters $\nu = 2$, Lx=100, dt=1/16, Nx=128 (number of x gridpoints).
Initialize your numerical code with u(x,1) and then compare the results of the
numerical time integration with u(x,t) evaluated from the above formula. I suggest plotting
both quantities versus x at regular intervals in time during the simulation, using "pause" (matlab)
to stop the simulation temporarily.
Make a plot of the numerical solution and the Gaussian solution versus x at t=100 to turn in.
Are the two entirely consistent? If not, why not?
**Problem 2.** Copy and revise your heat equation code so that it simulated the 1d Swift-Hohenberg equation,
$u_t = (r-1) u - 2 u_{xx} - u_{xxxx} - u^3$ on a periodic domain $[0,L_x]$ using Fourier spatial
discretization and Crank-Nicolson/Adams-Bashforth semi-implicit temporal discretization. Use the
initial condition $u(x,0) = \cos(ax) + 0.1 \cos(2ax)$ where $a=2\pi/L_x$, parameter values
r = 0.2, Lx = 100, Nx = 256 (number of x gridpoints), dt = 1/16, and integrate from t=0 to 100.
Make a colorplot of $u(x,t)$ in the $x,t$ plane (using every x gridpoint but plotting t at a larger
interval than dt, perhaps at intervals of 1/2 or 1. It should look something like this
{{:gibson:teaching:spring-2014:iam950:sh.png?direct&400|Simulations of Swift-Hohenberg eqn}}
When you are satisfied with the correctness of your simulation, make a plot of $u(x,100)$ versus x for
the above parameters and initial conditions to turn in.
Now play around with the forcing parameter in the range 0 < r < 1 and the initial condition,
by changing the wavelengths and magnitudes of the the cosines, and possibly the total integration
time, if you don't see patterns develop by t=100. Answer the following questions
- Does the wavelength of the final pattern depend on r or the initial condition?
- Does the wavelength of the final pattern match you expectation from linear analysis?
- Can you relate the amplitude of the final pattern or the time scale of its growth from the initial condition to the Swift-Hohenberg equation?
**Problem 3.** Copy and revise your Swift-Hohenberg code so that it simulates the 1d Kuramoto-Sivashinsky equation, $u_t = - u_{xx} - u_{xxxx}- u u_x$, with parameters Lx = 100, Nx = 512, and dt = 1/16,
initial condition $u(x,0) = \cos(ax) + 0.1 \cos(2ax)$ (same as before), and integrate from t=0 to t=100. Make a colorplot of $u(x,t)$ as before. It should look like this
{{:gibson:teaching:spring-2014:iam950:ks.png?direct&400|Kuramoto-Sivashinsky simulation}}
Make a plot of $u(x,100)$ versus x to turn in. Now play around with the domain size Lx (adjusting
Nx so that Lx/Nx is approximately constant), try replacing the initial condition with random numbers
of order 0.01, and answer the following questions
- Does the wavelength of the final pattern depend on r or the initial condition?
- Does the wavelength of the final pattern match you expectation from linear analysis?
- What qualitative changes in behavior do you observe as L increases from small (L=1) to large (L=100)?
**Problem 4.** For each of the above codes, fix the initial condition and parameters, and run the simulation
with dt = 1/8, 1/4, .... What happens? Why?
**Some help on Matlab's FFT:** Matlab documentation is not very helpful about the ordering or normalization of Fourier coefficients in the FFT. However, a small numerical experiment clarifies. Let's construct a function with energy in known wavenumbers and observe where nonzero coefficients appear in the numerical FFT. I'll do 8 gridpoints for the periodic domain [0, 2pi].
>> x = 1/8*(0:7)*2*pi
x =
0 0.7854 1.5708 2.3562 3.1416 3.9270 4.7124 5.4978
>> k = 0;
>> u = cos(k*x) + 0.1*sin(k*x);
>> [real(fft(u)); imag(fft(u))]
ans =
8 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
>> k = 1;
>> u = cos(k*x) + 0.1*sin(k*x);
>> [real(fft(u)); imag(fft(u))]
ans =
-0.0000 4.0000 0.0000 0 0.0000 0 0.0000 4.0000
0 -0.4000 0 -0.0000 0 0.0000 0 0.4000
>> k = 2;
>> u = cos(k*x) + 0.1*sin(k*x);
>> [real(fft(u)); imag(fft(u))]
ans =
-0.0000 -0.0000 4.0000 0.0000 0.0000 0.0000 4.0000 -0.0000
0 0 -0.4000 0 0 0 0.4000 0
>> k = 3;
>> u = cos(k*x) + 0.1*sin(k*x);
>> [real(fft(u)); imag(fft(u))]
ans =
-0.0000 0.0000 -0.0000 4.0000 0.0000 4.0000 -0.0000 0.0000
0 -0.0000 0.0000 -0.4000 0 0.4000 -0.0000 0.0000
>> k = 4;
>> u = cos(k*x) + 0.1*sin(k*x);
>> [real(fft(u)); imag(fft(u))]
ans =
0 0 0 0 8.0000 0 0 0
0 0.0000 0 0.0000 0 -0.0000 0 -0.0000
So the ordering of Fourier modes in the FFT for N=8 is k = [0 1 2 3 -4 -3 -2 -1]
--not what I suggested it would be in class. The normalization is also different:
the kth and -kth FFT coefficients for u(x) = cos(kx) are not 1/2, but N/2.
Also observe that the treatment of the highest-order Fourier mode k=-4 is a little weird,
in that the 8 represents the sum of the k=4 and k=-4 cosine modes, with no representation
of the k=4 and k=-4 sin modes. Without going into too much detail on this, Fourier spectral
PDE codes typically just zero the highest-order mode at every time step. We can ignore this
subtlety.
Based on the above, here's a short example of how to do Fourier differentiation in Matlab on
a [0,L] periodic domain. This should be plenty to get you started for the time-stepping codes.
% A demonstration of Fourier differentiation in Matlab
% Parameters
L = 10;
N = 16;
x = L/N*(0:N-1);
% Set up u(x) and du/dx for some known L-periodic function
a = 2*pi/L
u = sin(a*x) + 0.2*cos(a*2*x);
dudx = a*cos(a*x) - 0.4*a*sin(a*2*x);
% Now compute dudx via FFT
k = [0:N/2-1 -N/2:-1];
alpha = 2*pi*k/L;
D = i*alpha;
dudx_fft = real(ifft(D.*fft(u)));
% Plot everybody
plot(x,u, 'b', x,dudx, 'g', x, dudx_fft, 'r.')
legend('u','du/dx','du/dx via FFT','location','southwest')
xlabel('x')