I've been writing a PDE solver for a reaction diffusion equation in one dimension. To test it I'm using the "method of manufactured solutions" (that's the term my supervisor gave it - I'm not sure if that's a common term).
The equation is:
$$\frac{\partial u}{\partial t}=D\frac{\partial^2 u}{\partial x^2}+f(x,t,u)$$
I have chosen a specific solution: $$u(x,t)=-e^{-t}x^2(2x-3L)$$ Which is the solution to the following particular equation: $$\frac{\partial u}{\partial t}=\frac{\partial^2 u}{\partial x^2}-u+De^{-t}(12x-6L)$$
I'm breaking this into two stages. I'm using forward Euler to solve the reaction part, and Crank-Nicolson to solve the diffusion part. In other words, I'm solving: $$\frac{\partial u}{\partial t}=f(x,t,u)$$ Using the numerical scheme: $$\frac{U^{k+1}_j-U^k_{j}}{\Delta t}=-U^{k}_j+De^{-t^{k}}(12x_j-6L)$$ Which gives the next time step as: $$U^{k+1}_j=U^{k}_j(1-\Delta t)+\Delta t De^{-t^{k}}(12x_j-6L)$$ (Note: superscripts represent time steps, and subscripts represent space steps, i.e. $t^{k}$ is the kth time step) A matrix equaion for this is: $$\hat{U}^{k+1}=\hat{U}^{k}(1-\Delta t)+\Delta t De^{-t^{k}}(12\hat{X}-6L)$$
And then solving: $$\frac{U^{k+1}_{j}-U^{k}_{j}}{\Delta t}=\frac{D}{2(\Delta x)^2}\left[(U^{k+1}_{j+1}-2U^{k+1}_{j}+U^{k+1}_{j-1})+(U^{k}_{j+1}-2U^{k}_{j}+U^{k}_{j-1})\right] +f(x_j,t^{k},U^{k}_{j})$$
Which boils down to this matrix equation: $$A\hat{U}^{k+1}=B\hat{U}^k+2\Delta t\hat{f}$$ (the hats represent vectors)
Apologies if this is not explicit enough, I'm trying to avoid writing out a huge matrix equation that is a pain to format. Please ask if clarification is needed.
So, up to now is what I'll call my "devised scheme". The next bit is about my "implemented scheme" that I've written up in python.
To solve this, I'm using a tridiagonal solver to solve the matrix equation: $$\hat{U}^{k+1}=A^{-1}(B\hat{U}^k+2\Delta t\hat{f})$$
Anyway, what I've done next is to replace the $\hat{f}$ with the $\hat{U}^{k+1}$ I get from the forwards Euler step. I'm not so sure if this is the right thing to do.
When I solve this matrix equation and plot the results I get:
Where the dotted lines are the numerical solution and the solid lines are the exact solution.
Now, this is clearly not correct.
When I change the matrix equation to this however:
$$\hat{U}^{k+1}=A^{-1}(B\hat{U}^k\highlight{-}2\Delta t\hat{f})$$
and again replace the $\hat{f}$ with the $\hat{U}^{k+1}$ I get from the forwards Euler step, I get the follwing result.
Much better isn't it?
So my question is, why? What am I missing, what am I doing wrong? Please just assume that the numerical method can't be changed. I can use a different way easy enough, but I need to know what is going on here to make sure I know what I'm doing in general.
EDIT:Here is my code.
import numpy as np
import scipy.linalg as la
import matplotlib.pyplot as plt
def fwdeuler(L,dt,T,uin,D):
nx=len(uin)
unext=np.zeros(nx)
dx = L/float(nx)
for j in xrange(nx):
unext[j]= uin[j]*(1-dt)+ D*dt*np.exp(-T)*(12*j*dx-6*L)
return unext
#parameters for the simulation
xsteps=100
tsteps=200
tf=2
L=5
D=.01
dt=tf/float(tsteps)
dx=L/float(xsteps)
r=(dt*D)/(dx**2)
#the A matrix
ac=np.ones(xsteps-1)*(-r)
ca=np.ones(xsteps-1)*(-r)
#no flux BCs
ac[0]=-2*r
ca[-1]=-2*r
b=np.ones(xsteps)*2*(1+r)
#the matrix for the tridiagonal solver
band=np.vstack((np.hstack(([0],ac)),np.vstack((b,np.hstack((ca,[0]))))))
sol=np.zeros((xsteps,tsteps))
x=np.linspace(0,L,xsteps)
#initial conditions
sol[:,0]=-(x**2)*(2*x-3*L)
#creating the B matrix
a1=np.ones(xsteps)*2*(1-r)
ta2=np.ones(xsteps-1)*r
ta3=np.ones(xsteps-1)*r
ta2[0]=2*r
ta3[-1]=2*r
poststep=np.diag(ta1)+np.diag(ta2,1)+np.diag(ta3,-1)
for i in xrange(1,tsteps):
#first step make the RHS of the equation
#bvec, as in Ax=b
bvec=np.dot(poststep,sol[:,i-1])-2*dt*fwdeuler(L,dt,i*dt,sol[:,i-1],D)
#second step solves x=A^-1*b
sol[:,i]=la.solve_banded((1,1),band,bvec)
plt.figure(num=None, figsize=(20,16), dpi=80, facecolor='w', edgecolor='k')
for i in xrange(0,tsteps,tsteps/10):
plt.plot(x,sol[:,i],'--')
plt.plot(x,-np.exp(-dt*i)*(2*x**3-3*L*x**2))
plt.show()