---
# System prepended metadata

title: 5. Fisher-KPP equation
tags: [Finite difference method]

---

---
title: 5. Fisher-KPP equation
tags: Finite difference method
---

---

### Problem 3 (亞衛)

@RyanHsieh 1. 你的方法以及你的 code 在收斂階數上有沒有一致需要 check. 2. 所以原題在 $t=40$ 的時候的解究竟長怎樣? 在你的回答裡我看到三條不一樣的線, 所以是誰? 還是都不是? 


@RyanHsieh 1. stability 一開始假設的有點跟我不一樣, 沒有$\lambda$? 2. Von Neumann 應該只能做線性的部分, 非線性那一項應該做不動. 3. 看起來 x=0 的邊界有錯, 解在那邊怪怪的. 

Fisher-KPP equation
$$
u_t = u_{xx}+u-u^2, \quad x\in[0, 100], \quad t\in[0, 40],
$$
with initial and boundary conditions
$$
u(x,0) = e^{-x}, \quad u(0, t) =1, \quad  u(100,t)=0.
$$

#### **solution**.
We fisrt consider the same equation with boundary condition:
$u(x,0) = (1+\exp(\sqrt{\dfrac{1}{6}}x))^{-2}, \\ 
u(0,t) = (1+\exp(\dfrac{-5}{6}t))^{-2}, \text{and} \\
u(200,t) = (1+\exp(\dfrac{-5}{6}t+\sqrt{\dfrac{1}{6}}\times 200))^{-2}.$
The Exact solution is 
$$u(x,t)=(1+\exp(\dfrac{-5}{6}t+\sqrt{\dfrac{1}{6}}x))^{-2}.
$$
First devide the interval $[0,100]$ into $N+1$ pieces, so we insert $N$ points in $(0,100)$.
Nonation : Here we use $U_i^n$ instead of using $u(x_i,t_n)$ ,the numerical approximation.

* **Partition**: 
$x_0=0, \quad x_N=100,\quad x_i=ih$  with  $h=\dfrac{100}{N+1}$ for $i=0,1,2,...,N,N+1$.
$t_0=0, \quad t_M=40,\quad t_n=nk$ with $k=\dfrac{40}{M}$ for $n=0,1,...,M$.
* **Unknows**: $U_i^n=u(x_i,t_n)$ for $i=0,1,...,N-1$ and $n=1,2,...,M$.

#### Central Difference Method
Here we use the Backward Euler method, so the original equation
$$u_t = u_{xx}+u-u^2$$ becomes
$\dfrac{U_i^{n+1}-U_i^{n}}{k} 
= \dfrac{U_{i+1}^{n+1}-2U_i^{n+1}+U_{i-1}^{n+1}}{h^2}
+U_i^n(1-U_i^n)$.
Hence 
$-rU_{i+1}^{n+1}+(1+2r)U_i^{n+1}-rU_{i-1}^{n+1}
= (1+k-kU_i^n)U_i^n$  where  $r=\dfrac{k}{h^2}$.

So the correponding system is 
$$
\begin{pmatrix}
    1+2r & -r &   &   &  \\
    -r & 1+2r & -r   &     &  \\
      & -r  & 1+2r  & -r   &  \\
      & & & \ddots &  \\
      &    &   &   -r  & 1+2r\\
\end{pmatrix}
\begin{pmatrix}
U_1^{n+1} \\ U_2^{n+1} \\ \vdots \\ \vdots \\ U_{N-1}^{n+1}
\end{pmatrix}=
\begin{pmatrix}
 (1+k-kU_1^n)U_1^{n}+rU^{n+1}_0 \\ (1+k-kU_2^n)U_2^{n} \\ \vdots \\ \vdots \\ (1+k-kU_{N-1}^n)U_{N-1}^{n}+rU^{n+1}_N
\end{pmatrix}\quad\quad(*)
 $$

#### Truncation error
$\dfrac{U_i^{n+1}-U_i^{n}}{k} 
= \dfrac{U_{i+1}^{n+1}-2U_i^{n+1}+U_{i-1}^{n+1}}{h^2}
+U_i^n(1-U_i^n)$

The local truncation error is 
\begin{align*}
\tau(x_i,t_n) & =D_tu_i^n-D_{xx}u_i^{n+1}-u_i^{n}(1-u_i^n) \\
& =(ku_t+\frac{k^2}{2}u_{tt}+\frac{k^3}{6}u_{ttt}+\dots)-(u_{xx}+\frac{h^2}{12}u_{xxxx}+\dots)-u(1-u)\\
&=(u_t-u_{xx}-u(1-u)) + (k-1)u_t+\frac{k^2}{2}u_{tt}+\dots-\frac{h^2}{12}u_{xxxx}+\dots \\
&\approx O(h^2) + O(k).
\end{align*}


---

__2020.07.02 Update__


##### Matlab code
```matlab=
clc;clear;

% Initailization
N=10;
h=100/N;
k=0.1;
r=k/(h^2);
T=40;
M=T/k;
xx=[0:h:100];
tt=[0:k:T];

% Boundary Condition
Sol=zeros(M+1,N+1);
v=zeros(N-1,1);
Sol(1,:) = (1+exp(sqrt(1/6)*xx)).^(-2);
Sol(:,1) = (1+exp((-5/6)*tt)).^(-2);
Sol(:,N+1) = (1+exp((-5/6)*tt+sqrt(1/6)*100)).^(-2);

% Tridiagonal system
S = diag((1+2*r)*ones(1,N-1))+diag((-r)*ones(1,N-2),1)+diag((-r)*ones(1,N-2),-1);
x_new = Sol(1,:);

% Central Difference Method
for i=1:M
    x_old = x_new;
    v(1) = r*Sol(i+1,1);
    v(N-1) = r*Sol(i+1,N+1);
    right = (((1+k-k.*Sol(i,2:N)).*Sol(i,2:N))' + v);
    x_new = S\right;
    Sol(i+1,:)=[Sol(i+1,1),(x_new)',Sol(i+1,N+1)];
end

% Creating Exact solution
ts = (-5/6)*tt';
xs = sqrt(1/6)*xx;
ET = repmat(ts,1,N+1);
EX = repmat(xs,M+1,1);
Exact = (1+exp(ET+EX)).^(-2);

% Calculate the Error
Error = abs(Exact - Sol);
err = norm(Error,inf)
```

Setting $T=40$
| $N$       | $h$    | $k$  |$k/h^2$|$Err$  | $\frac{Err_h}{Err_{2h}}$|
| :---------- |:---|:-------------- |:----------    |:---------- |:-|
|  $10$ | $10$ | $0.1$ | $10^{-3}$ | $3.195845119677438$| |
|  $20$ | $5$ | $0.025$ | $10^{-3}$ | $3.754365127925062$| $1.174764416713660$|
|  $40$ | $2.5$ | $0.00625$ | $10^{-3}$ | $2.869063707583049$|$0.764194107345309$ |
|  $80$ | $1.25$ | $0.0015625$ | $10^{-3}$ | $1.593838088400404$|$0.555525513144873$ |
|  $160$ | $0.625$ | $0.000390625$ | $10^{-3}$ | $0.815406831116279$| $0.511599538905882$|
|  $320$ | $0.3125$ | $0.00009765625$ | $10^{-3}$ | $0.409762213268130$|$0.502524871795803$ |
Exact Solution when $T=40$ with $N=80(h=1.25)$ and $k=0.0015625$:
![](https://i.imgur.com/zKXRPsa.png)
Numerical Solution when $T=40$ with $N=80(h=1.25)$ and $k=0.0015625$:
![](https://i.imgur.com/P2ezYwl.png)


Setting $T=1$
| $N$       | $h$    | $k$  |$k/h^2$|$Err$  | $\frac{Err_h}{Err_{2h}}$|
| :---------- |:---|:-------------- |:----------    |:---------- |:-|
|  $10$ | $10$ | $0.1$ | $10^{-3}$ | $0.004976076044017$| |
|  $20$ | $5$ | $0.1$ | $10^{-3}$ | $0.002158588593650$|$0.433793329232857$ |
|  $40$ | $2.5$ | $0.1$ | $10^{-3}$ | $0.005017586842186$| $2.324475750935783$|
|  $80$ | $1.25$ | $0.1$ | $10^{-3}$ | $0.002908354883233$| $0.579632196652908$|
|  $160$ | $0.625$ | $0.1$ | $10^{-3}$ | $0.001483586242644$| $0.510111833737019$|
|  $320$ | $0.3125$ | $0.1$ | $10^{-3}$ | $0.000746273196146$|$0.503019760291128$ |
|  $640$ | $0.078125$ | $0.1$ | $10^{-3}$ | $0.000373472669036$|$0.500450332351122$ |

Exact Solution when $T=1$ with $N=80(h=1.25)$ and $k=0.0015625$:
![](https://i.imgur.com/Xqy30SY.png)
Numerical Solution when $T=1$ with $N=80(h=1.25)$ and $k=0.0015625$:
![](https://i.imgur.com/Ga4T0yl.png)

Convergence:
$T=1$
![](https://i.imgur.com/8m2kjpW.png)
$T=10$
![](https://i.imgur.com/fnpTb0L.png)
$T=40$
![](https://i.imgur.com/bK0sUZN.png)

From the table above, we can check that the trucation error is $O(h^2) + O(k).$

To solve the original equation, the code is the same except
```Matlab=
Sol(1,:) = exp(-xx);
Sol(:,1) = 1;
Sol(:,N+1) = 0;
```
Result:
$T=40$ with $N=160(h=0.625)$ and $k=0.15625$.
![](https://i.imgur.com/B9iVsRl.png)
Convergence:
$N=10,20,40,80,160$ at $T=40$
![](https://i.imgur.com/hCvSrQ0.png)





References:
1. [Numerical Study of One Dimensional Fishers KPP Equation with Finite Difference Schemes.](https://pdfs.semanticscholar.org/1263/aed1db64f0ea7577e6d22f15930aa379a064.pdf)
2. [A Numerical Treatment of Fisher Equation.](https://cyberleninka.org/article/n/611770.pdf)

---

### Problem 4 (沂君)

@7G35H_3DTJyS0go4-C366Q good job, 不過 0.26 -> 0.25 -> 0.22 看起來不像會收斂到 0.25 的樣子? N 再往上取試試. 如果要跑很久, 算到 T=1 就好. 

Fisher-KPP equation
$$
u_t = u_{xx}+u-u^2, \quad x\in[0, 200], \quad t\in[0, 40],
$$
with initial and boundary conditions
$$
u(x,0) = e^{-x}, \quad u(0, t) =1, \quad  u(200,t)=0.
$$

#### **Solution.**
First we solve the equation with different initial and boundary condition to check our code.

$$
u_t = u_{xx}+u-u^2, \quad x\in[0, 200], \quad t\in[0, 40],
$$

$$
u(x,0) = (1+exp(\sqrt{\frac{1}{6}}x))^{-2}, \quad u(0, t) =(1+exp(-\frac{5}{6}t))^{-2}, 
$$

$$
u(200,t)=(1+exp(-\frac{5}{6}t+\sqrt{\frac{1}{6}}\times 200))^{-2}.
$$

Exact solution:
$$
u(x,t)=(1+exp(-\frac{5}{6}t+\sqrt{\frac{1}{6}} x))^{-2}
$$

Devide the interval $[0,200]$ into $N+1$ pieces, so we insert $N$ points in $(0,200)$.

* Partition: 
$x_0=0, x_{N+1}=200,$
$x_i=0+ih$ with $h=\dfrac{200}{N+1}$ , $i=1,...,N$
$t_n = nk$ , $k = \Delta t, n \geq 0$
$U_{i}^{n} = u(x_{i},t_{n})$
$U_{i}^{0} = (1+exp(\sqrt{\frac{1}{6}}x_i))^{-2}$
* Initial and boundary conditions:
$U_{0}^{t} = (1+exp(-\frac{5}{6}t))^{-2}$
$U_{200}^{t} = (1+exp(-\frac{5}{6}t+\sqrt{\frac{1}{6}}\times 200))^{-2}$
* Unknows: $U_i^{n}=u(x_i,t_n)$ for $i=1,...,N$, $n > 0$

Using Crank-Nicolson method, we obtain
$$
\frac{ U_i^{n+1} - U_i^n }{k} = 
\frac{1}{2}[\frac{U_{i+1}^{n+1}-2U_i^{n+1}+U_{i-1}^{n+1} }{h^2} + \frac{U_{i+1}^n-2U_i^n+U_{i-1}^n }{h^2}]\\
        +  \frac{U_i^{n+1}+U_i^n}{2} - (\frac{U_i^{n+1}+U_i^n}{2})^2
$$

$$
\implies (-\frac{1}{2}r)U_{i-1}^{n+1}+(1+r-\frac{k}{2})U_i^{n+1}+(-\frac{1}{2}r)U_{i+1}^{n+1}\\
+(-\frac{1}{2}r)U_{i-1}^{n}+(-1+r-\frac{k}{2})U_i^n+(-\frac{1}{2}r)U_{i+1}^n\\
+k(\frac{U_i^{n+1}+U_i^n}{2})^2=0=F(U), \quad r =\frac{k}{h^2}
$$

In each time step $t=(n+1)k$, we use newton's method to find $U_i^{n+1}$.

That is, find $U^m= \left[\begin{matrix} U_1^{n+1} \\ U_2^{n+1} \\ \vdots \\ U_N^{n+1} \\\end{matrix}\right]$ by $U^{m+1} = U^m - (J[U^m])^{-1}F[U^m]$

with initial guass $U^0=0$, $J$ is Jocabian matrix of $F$ and consider $U_i^n$ as known constant.

So we get the system

$U^{m+1}=$
$$
U^m-
\begin{pmatrix}
    1+r-\frac{k}{2}+\frac{k}{2}(U_1^{n+1}+U_1^{n}) & -\frac{1}{2}r &   &   &  \\
    -\frac{1}{2}r & 1+r-\frac{k}{2}+\frac{k}{2}(U_2^{n+1}+U_2^{n}) & -\frac{1}{2}r   &     &  \\
      &    &   & \ddots  &  \\ 
\end{pmatrix}^{-1}
F(U^m).
$$

##### Pseudo code
1. $X = \{0+ih | i=0,\dots,N+1,\, h=\frac{200}{N+1} \},\quad M=\frac{40}{k}$
1. $U_i^0 = (1+exp(\sqrt{\frac{1}{6}} x_i))^{-2}$
1. $\text{for }t=1,\dots,M\\
    \quad U^0=[(1+exp(-\frac{5}{6}t))^{-2} \quad 0\dots0 \quad(1+exp(-\frac{5}{6}t+\sqrt{\frac{1}{6}} \times 200))^{-2}]^t\\
    \quad \text{while not convergent:}\\
    \quad \quad U^k \leftarrow U^{k-1}\\
    \quad \quad U^k \leftarrow U^k - J(U^k)^{-1} F(U^k)\\
    \quad \text{endwhile}\\
    \quad U_i^t=U^k(i-1), \quad i=1,\dots,N\\
    \quad U_0^t=(1+exp(-\frac{5}{6}t))^{-2}\\
    \quad U_{200}^t=(1+exp(-\frac{5}{6}t+\sqrt{\frac{1}{6}} \times 200))^{-2}\\
    \text{endfor}$


##### Code:(C++)
```C++
#include <iostream>
#include <cmath>
#include <vector>
#include <fstream>
using namespace std;

const double SMALL = 1.0E-30;

bool tdma( const vector<long double> &a, 
           const vector<long double> &b,
           const vector<long double> &c,
           const vector<long double> &d, 
           vector<long double> &X )
/*
Solving a tri-diagonal system by using the Thomas Algorithm (TDMA).              
a_i X_i-1 + b_i X_i + c_i X_i+1 = d_i,     i = 0, n - 1                                       
Since this is the n x n matrix equation,
a[i], b[i], c[i] are the non-zero diagonals of the matrix and d[i] is the RHS. 
so a[0] and c[n-1] aren't used.                       

Code Refrences:
http://www.cplusplus.com/forum/beginner/247330/                            
*/
{
   int n = d.size();
   vector<long double> P( n, 0 );
   vector<long double> Q( n, 0 );
   X = P;

   // Forward pass
   int i = 0;
   double denominator = b[i];
   P[i] = -c[i] / denominator;
   Q[i] =  d[i] / denominator;
   for ( i = 1; i < n; i++ )
   {
      denominator = b[i] + a[i] * P[i-1];
      if ( abs( denominator ) < SMALL ) return false;
      P[i] =  -c[i]                   / denominator;
      Q[i] = ( d[i] - a[i] * Q[i-1] ) / denominator;
   }

   // Backward pass
   X[n-1] = Q[n-1];
   for (i=n-2;i>=0;i--) X[i]=P[i]*X[i+1]+Q[i];
   return true;
}

long double infinity_norm(const vector<long double> &a) {
    long double max=0;
    long double k;
    for(int i = 0; i < a.size(); i++)
    {
        k = fabs(a[i]);
        if(k > max) max = k;
    } 
    return max;
}

int main(void) {

    ofstream outfile("./u.txt");

    cout.precision(10);           //More precisely 
    int N;                        //N : number of unknown points, k : time step
    double k;
    cout << "Please enter N(an interger):";
    cin >> N;
    cout << "Please enter k :";
    cin >> k;

    int M = (int) ((40/k)+0.5);       //max t = 40
    long double h = 200.0/(N+1);
    long double r = k/(pow(h,2.0));
    long double u[2][N+2]={0};           //Store u
    vector<long double> x(N+2, 0.0); //Create a vector for x_i
    vector<long double> F(N, 0.0);   //Create a vector for F_i
    vector<long double> V(N, 0.0);   //Create a vector for V_i

    for(int i=0;i<=N+1;i++){         //Devide [0,200] into N+1 pieces such that x_0 = 0 , x_(N+1) = 200
    	x[i] = 0 + i*h;             //unknown points are x_1 ~ x_(N)
    }
    
    for(int i=0; i<=N+1; i++)        //initializing u
    {
        u[0][i] = pow( ( 1 + ( exp( pow(0.166666666666667,0.5)*x[i]))) ,-2); 
    }
    
    if(outfile.is_open()){
        outfile << "[";
        for(int j=0; j<=N; j++)
        {
            outfile << u[0][j] << ",";
        }
        if(0 == M) outfile << u[0][N+1] << "]";
        else outfile << u[0][N+1] << ";";   
    }
    

    int n;
    int n_1;

    for(int t=1; t<=M; t++)                
    {
        n = t%2;                            //Time n
        n_1 = ((n%2)+2-1)%2;                //Time n-1
        
        u[n][0] = pow( 1+exp( (-0.833333333333333)*t*k ) ,-2);
        u[n][N+1] = pow( 1+exp( (-0.833333333333333)*t*k + pow(0.166666666666667,0.5)*200) ,-2);
        
        long double Err = 1;
        long double Tol = 1.0E-16;
        vector<long double> Unew(N,0.0);
        vector<long double> Uold_Unew(N);

        while(Err > Tol)
        {            
            for(int i=0; i<N; i++)      //update u
            {
                u[n][i+1] = Unew[i];
            }

            for(int i=1;i<=N;i++){     
	        F[i-1] = (-0.5)*r*u[n][i+1] + (1+r-0.5*k)*u[n][i] + (-0.5)*r*u[n][i-1] 
                        + (-0.5)*r*u[n_1][i+1] + (-1+r-0.5*k)*u[n_1][i] + (-0.5)*r*u[n_1][i-1]
                        + k*pow( (u[n][i]+u[n_1][i])/2, 2) ;
	    }

            vector<long double> MainDiag(N,1+r-0.5*k);     //Creating the tridiagonal matrix J
	    vector<long double> LowDiag(N,-0.5*r);
	    vector<long double> HighDiag(N,-0.5*r);
            LowDiag[0] = 0;
            HighDiag[N-1] = 0;
            for(int i=0; i<N; i++)
            {
                MainDiag[i] = MainDiag[i] + 0.5*k*u[n][i] + 0.5*k*u[n_1][i];
            }
        
            tdma(LowDiag,MainDiag,HighDiag,F,V);

            //V = J^(-1)F
            for(int i=0; i<N; i++)
            {
                Unew[i] = u[n][i+1]-V[i];
            }

            for(int i=0; i<N; i++)
            {
                Uold_Unew[i] = u[n][i+1]-Unew[i];
            }

            Err = infinity_norm(Uold_Unew);
        }

        for(int i=0; i<N; i++)              //Update u
        {
            u[n][i+1] = Unew[i];
        }
        
        if(outfile.is_open()){
            //if(t==M){ outfile << "[";
            for(int j=0; j<=N; j++)
            {
                outfile << u[n][j] << ",";
            }
            if(t == M) outfile << u[n][N+1] << "]";
            else outfile << u[n][N+1] << ";";
            //}
        }
        
    }
}
```

Output: matrix of `U[M+1][N+2]`.

Exact solution:
![](https://i.imgur.com/wuhgoSH.png)


Set $N=199, k=0.1$
![](https://i.imgur.com/B5WzgqD.png)


At t=40.
![](https://i.imgur.com/pJSmcC6.png)


Compute $Err=||u_{exact}-U||_1$ at $t=40$ with $N=99,199,399,799,1599,3199,6399$ and $k=0.2,0.1,0.05,0.025,0.0125,0.00625,0.003125$ respectively. 

| $N$       | $h$    | $k$  |$Err$  | $\frac{Err_h}{Err_{2h}}$|
| ---------- |:-------------- |:----------    |:---------- |:-|
|  99 | $2.00000$ | $0.200000$ | $5.563056214616273$ | |
| 199 | $1.00000$ | $0.100000$ | $1.466021177852882$ |$0.263528017926744$ |
| 399 | $0.50000$ | $0.050000$ | $0.370390248021738$ |$0.252649998251872$ |
| 799 | $0.25000$ | $0.025000$ | $0.092811838248455$ |$0.250578514807462$ |
| 1599 | $0.12500$ | $0.012500$ | $0.023217880269299$ |$0.250160762974497$ |
| 3199 | $0.06250$ | $0.006250$ | $0.005808800758313$ |$0.250186523960759$ |
| 6399 | $0.03125$ | $0.003125$ | $0.001456418463975$ |$0.250726186793426$ |

From the table above, we can check that the trucation error is $O(h^2) + O(k^2).$

To solve the original equation, the code is the same except
```C++
for(int i=0; i<=N+1; i++)        //initializing u  //line 89
{
    u[0][i] = exp(-x[i]);
}
u[0][0]=1;
u[0][N+1]=0;

for(int t=1; t<=M; t++)  //line 101              
{
        n = t%2;                            //Time n
        n_1 = ((n%2)+2-1)%2;                //Time n-1
        
        u[n][0] = 1;         
        u[n][N+1] = 0;
```

Set $N=199, k=0.1$
![](https://i.imgur.com/ux9SPyF.png)


Convergence:
![](https://i.imgur.com/YSwYZEX.png)

---