--- 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) ---