---
# System prepended metadata

title: 3. Diffusion equation
tags: [Finite difference method]

---

---
title: 3. Diffusion equation
tags: Finite difference method
---

# Diffusion equation

**Textbook**
1. Finite Difference Methods for Ordinary and Partial Differential Equations by *Randall J. LeVeque*

---

### Exercise 1

Consider the linear advection-diffusion equation
$$
u_t = u_{xx}-u_x, \quad x\in[0, 100], \quad t\ge 0,
$$
with initial and boundary conditions
$$
u(x,0) = e^{-(x-10)^2}, \quad u(0, t) = u(100,t)=0.
$$
Solve the equation using Crank-Nicolson method.
#### Solution
Given $N\in \mathbf{N}$. Consider the grid points $(x_i,t_n) = (ih,nk),\,i=0,\cdots,N$, where $h=\frac{100}{N+1}$ (mesh width), $k=\Delta t$ (time step). 
Let $U_i^n \approx u(x_i,t_n)$ denote the numerical approximation at grid point $(x_i,t_n)$.

Using Crank-Nicolson method, we obtain
$$D_t U_i^{n+0.5} = \frac{1}{2} [(D_x^2 U_i^{n+1} -D_x U_i^{n+1}) + (D_x^2 U_i^n -D_x U_i^n)]$$
where 
$D_t$ denote the $1^{st}$-order central difference w.r.t. $t$ , 
$D_x^2$ denote the $2^{nd}$-order central difference w.r.t. $x$, 
and $D_x$ denote the $1^{st}$-order central difference w.r.t. $x$.

\begin{align*}
    \implies \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+1}-U_{i-1}^{n+1}}{2h}]\\
                                                         &+  \frac{1}{2} [\frac{U_{i+1}^n-2U_i^n+U_{i-1}^n }{h^2}-\frac{U_{i+1}^n-U_{i-1}^n}{2h}]\\
\end{align*}
where $i=1,\cdots,N,\, n\geq 0$.

Let $r = \frac{k}{2h^2},\, s = \frac{k}{4h}$. then it can be rewritten as
\begin{align*}
    &(s-r) U_{i+1}^{n+1} + (1+2r) U_i^{n+1} - (r+s) U_{i-1}^{n+1}\\
    =& (r-s) U_{i+1}^n + (1-2r) U_i^n + (r+s) U_{i-1}^n
\end{align*}
where $i=1,\cdots,N,\, n\geq 0$.

In particular, at $i=1$
$$ (s-r) U_2^{n+1} + (1+2r) U_1^{n+1} = (r-s) U_2^n + (1-2r) U_1^n;$$
at $i=N$
$$ (1+2r) U_N^{n+1} - (r+s) U_{N-1}^{n+1} = (1-2r) U_N^n + (r+s) U_{N-1}^n $$

In matrix form, this is
\begin{align*}
    &\begin{pmatrix}
        1+2r   & s-r     &         &   &    \\
        -r-s   & 1+2r   & s-r   &    &     \\
        && \ddots &&\\
        &&& \ddots & s-r\\
        &&& -r-s & 1+2r
    \end{pmatrix}
    \begin{pmatrix}
        U_1^{n+1} \\ U_2^{n+1} \\ \vdots \\ \vdots \\  U_N^{n+1}
    \end{pmatrix}\\
    &=\begin{pmatrix}
        1-2r   & r-s     &         &   &    \\
         r+s   & 1-2r   & r-s   &    &     \\
        && \ddots &&\\
        &&& \ddots & r-s\\
        &&&  r+s & 1-2r
    \end{pmatrix}
    \begin{pmatrix}
        U_1^n \\ U_2^n \\ \vdots \\ \vdots \\ U_N^n
    \end{pmatrix}
\end{align*}

#### Code(python)
```python
#### Input ####
# grid_size: number of grid points excluding leftmost point x=0.
# dt: time step
# T : maximal time 

#### Output ####
# x: mesh grid
# u: solution. u[i,n] = u(x_i , t_n) = u(i*dx,n*dt)

def LADsolve(grid_size,dt,T): 
    N = grid_size
    k = dt
    # h: mesh width / spacial grid size. dx
    h = 100/N
    
    # iter_max: maximal iteration of time t. iter_max*k < T
    iter_max = int(T/k)
    
    # initial condition u(x,0) = exp(-(x-10)^2)
    x = np.arange(0,100+h,h)
    u = np.zeros( ( N+1 , iter_max+1 ) )
    u[:,0] = np.exp(-(x-10)**2)
    
    r = k/2/h**2
    s = k/4/h
    A = diags([ -r-s , 1+2*r , s-r] , [-1,0,1],shape=(N-1,N-1),format='csc')
    B = diags([ r+s , 1-2*r , r-s ] , [-1,0,1],shape=(N-1,N-1),format='csc')
    
    for i in range(iter_max):
        u[1:N,i+1] = spsolve(A,B*u[1:N,i])
    
    return x,u
```
#### Result
![](https://i.imgur.com/0u8XsP5.png)

![](https://i.imgur.com/Jveodiq.gif)

#### Local Truncation Error
Suppose that $u(x,t)$ is the true solution of our linear advection-diffusion equation, then the local truncation error is 
\begin{align*}
&\tau(x_i,t_{n+0.5})  \\
=&
\frac{ u(x_i,t_{n+1}) - u(x_i,t_n) }{k} \\
& - \frac{1}{2}[ \frac{u(x_{i+1},t_{n+1})-2u(x_i,t_{n+1})+u(x_{i-1},t_{n+1}) }{h^2} + \frac{u(x_{i+1},t_n)-2u(x_i,t_n)+u(x_{i-1},t_n) }{h^2} ]\\
& + \frac{1}{2} [\frac{u(x_{i+1},t_{n+1})-u(x_{i-1},t_{n+1})}{2h} + \frac{u(x_{i+1},t_n)-u(x_{i-1},t_n}{2h}]\\
=&
( u_t + \frac{ u_{ttt} }{24} k^3 + \dots ) - ( u_{xx} + \frac{ u_{xxtt} }{8} k^2 + \frac{ u_{xxxx} }{12} h^2 + \dots) + ( u_x + \frac{ u_{xtt} }{8} k^2 + \frac{ u_{xxx} }{6} h^2 + \dots )\\
=& 
( \frac{ u_{ttt} }{24} - \frac{ u_{xxtt} }{8} + \frac{ u_{xtt} }{8} ) k^2 + ( -\frac{ u_{xxxx} }{12} + \frac{ u_{xxx} }{6} ) h^2 + o(h^2+k^2),\quad \text{at } (x,t)=(x_i,t_{n+0.5})
\end{align*}

#### Estimating Error
Let $U_h^k$ denote the numerical solution with grid size $h$ and time step $k$.


1.  Consider $N=200$ ( $h = 100/N$) , $k = 0.01$ and $t=100$. 

    $$R = \frac{\lVert U_h^k - U_{h/2}^k \rVert_2}{\lVert U_{h/2}^k - U_{h/4}^k \rVert_2}=4.060143594084393 \approx 2^2$$

    Hence, if time step $k$ is small enough, $\lVert E_h^k\rVert = O(h^2)$, where h is mesh width.
1. Consider $N=10000$ $(h=0.01)$, $k = 0.1$ and $t=100$, then 

    $$ R = \frac{\lVert U_h^k - U_h^{k/2} \rVert}{\lVert U_h^{k/2} - U_h^{k/4} \rVert} =4.000489890896513 \approx 2^2$$

    Hence, if grid size $h$ is small enough, $\lVert E_h^k\rVert = O(k^2)$, where k is time step.
---

### Exercise 2

Consider the linear diffusion equation
$$
u_t = u_{xx}, \quad x\in[-1, 1], \quad t\ge 0,
$$
with initial and boundary conditions
$$
u(x,0) = \sin(\pi x), \quad u(-1, t) = u(1,t)=0.
$$
Solve the equation using Leap-Frog scheme given as 
$$
U^{n+2}_i = U^n_i + \frac{2k}{h^2}(U^{n+1}_{i-1}-2U^{n+1}_i+U^{n+1}_{i+1}).
$$

**Solution.**
First devide the interval $[-1,1]$ into $N+1$ pieces, so we insert $N$ points in $(-1,1)$.

* Partition: 
$x_0=-1, x_{N+1}=1,$
$x_i=-1+ih$ with $h=\dfrac{2}{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} = sin(\pi x_i), U_{0}^{n} = U_{N+1}^{n}=0$
* Unknows: $U_i^{n}=u(x_i,t_n)$ for $i=1,...,N$, $n > 0$

For the first time step, we use Crank-Nicolson method.

 Since 
 $$-rU_{i-1}^1 + (1+2r)U_i^1 - rU_{i+1}^1 = rU_{i-1}^0 + (1-2r)U_i^0 + rU_{i+1}^0 $$ 
 where $$r = \frac{k}{2h^2}, i=1,...,N $$

The corresponding system is 
$$
\begin{pmatrix}
    (1+r) & -r &   &   &  \\
    -r & (1+r) & -r   &     &  \\
      & -r  & (1+r)  & -r   &  \\
      &    &   & \ddots  &  \\ 
      &    &   &   -r  & (1+r)\\
\end{pmatrix}
\begin{pmatrix}
U_1^1 \\ U_2^1 \\ U_3^1 \\ \vdots \\ \vdots \\ U_N^1
\end{pmatrix}=
\begin{pmatrix}
 (1-2r)U_1^0+rU_2^0\\rU_1^0+(1-2r)U_2^0+rU_3^0\\ rU_2^0+(1-2r)U_3^0+rU_4^0\\ \vdots \\rU_{N-1}^0+(1-2r)U_N^0
\end{pmatrix}.
 $$
 
To Solve this system, we use Thomas's algorithm.

Then we use the given Leap-Frog scheme to solve the following time step.

Code:(C++)
```C++
#include <iostream>
#include <cmath>
#include <vector>
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;
}

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

    int M = (int) ((t/k)+0.5);
    long double h = 2.0/(N+1);
    long double r = k/(2*pow(h,2.0));
    long double u[M+1][N+2];           //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> U(N, 0.0);   //Create a vector for U_i

    for(int i=0;i<=N+1;i++){         //Devide [-1,1] into N+1 pieces such that x(0) = -1 , x(N+1) = 1
	x[i] = -1 + i*h;             //unknown points are x(1) ~ x(N)
    }
    for(int i=0; i<=N+1; i++)        //initializing u
    {
        u[0][i] = sinl(M_PI*x[i]);
    }

    for(int i=1;i<=N;i++){           //Compute r.h.s of the system
	F[i-1] = r*u[0][i+1] + (1-2*r)*u[0][i] + r*u[0][i-1];
    }

    vector<long double> MainDiag(N,1+2*r);     //Creating the tridiagonal matrix
    vector<long double> LowDiag(N,-r);
    vector<long double> HighDiag(N,-r);
    LowDiag[0] = 0;
    HighDiag[N-1] = 0;
                                          //Compute the first step by Crank-Nicolson method
    tdma(LowDiag,MainDiag,HighDiag,F,U);  //Solve the tridiagonal system by using Thomas's algorithm
	
    for(int i=1; i<=N; i++)              //Update u
    {
        u[1][i] = U[i-1];
    }

    u[1][0] = 0;
    u[1][N+1] = 0;

    int n;
    int n_1;
    int n_2;

    for(int t=2; t<=M; t++)                //Leap-frog
    {
        n = t;
        n_1 = t-1;
        n_2 = t-2;

        for(int i=1; i<=N; i++)              
        {
            u[n][i] = u[n_2][i] + 4*r*(u[n_1][i-1] - 2*u[n_1][i] + u[n_1][i+1]);
        }
        u[n][0] = 0;
        u[n][N+1] = 0;
    }

    cout << "[";               //output u[M+1][N+2]
    for(int i=0; i<=M; i++)
    {
        for(int j=0; j<=N; j++)
        {
            cout << u[i][j] << ",";
        }
        if(i == M) cout << u[i][N+1] << "]";
        else cout << u[i][N+1] << ";";
    }
    
}
```
Output: matrix of `U[M+1][N+2]`.

The exact solution is $sin(\pi x)exp^{-\pi^2t}$.

![$sin(\pi x)exp^{-\pi^2t}$](https://i.imgur.com/eo2FcZc.png)

**Order:**
Set $N=9,k=0.01$
![](https://i.imgur.com/w7Au8xd.png)

Set $N=19,k=0.005$
![](https://i.imgur.com/y2jLAq5.png)

Set $N=39,k=0.0025$
![](https://i.imgur.com/5lJVBHC.png)

Compute $Err=||u_{exact}-U||_2$ at $t=0.04$ with $N=9,19,39$ and $k=0.01,0.005,0.0025$ respectively. 

| $N$       | $h$         | $k$    |$Err$     |
| ---------- |:-------------- |:----------    |:---------- |
|  9 | $0.2000$ | $0.0100$ | $0.009164282576198$ |
| 19 | $0.1000$ | $0.0050$ | $0.002300993600481$ |
| 39 | $0.0500$ | $0.0025$ | $0.000578771135722$ |
    
Since 
 $$\frac{Err_{N=19}}{Err_{N=9}}=0.251082785951808 \approx 0.25$$ 
 $$\frac{Err_{N=39}}{Err_{N=19}}=0.251530962798487 \approx 0.25$$
the trucation error is $O(h^2) + O(k^2).$

**Convergence:**
Set $N=9,19,39$ and $k=0.005$ at $t=0.05$
![](https://i.imgur.com/n4AUbNW.png)
![](https://i.imgur.com/fw9PKO8.png)


Set $N=19$, $k=0.01,0.005,0.0025$ at $t=0.08$
 ![](https://i.imgur.com/dODq68Q.png)
![](https://i.imgur.com/U2sjvsl.png)


---

### Exercise 3

Consider the linear diffusion equation
$$
u_t = u_{xx}, \quad x\in[-1, 1], \quad t\ge 0,
$$
with initial and boundary conditions
$$
u(x,0) = \cos(\pi x), \quad u'(-1, t) = u'(1,t)=0.
$$

* Solve the equation using Backward Euler method.
* Show that the mass is conserved in the equation and verify whether or not your scheme preserve the mass.

#### Answer:
* Grid:
    To solve the Neumann problem, consider the ghost point method and design the grid
    $x_{-1}=-1-h, x_0=-1, ..., x_N=1, x_{N+1}=1+h, h=\frac2{N}$
* Scheme:
    The BE method iteratively solves (hence implicitly) $U^{n+1}_:$ using data from $U^n_:$.
    (write $r=k/h^2$)
    * For interior points, $\frac{U^{n+1}_i-U^n_i}{k}=\frac{U^{n+1}_{i+1}-2U^{n+1}_i+U^{n+1}_{i-1}}{h^2}$
    thus $U_i^n = (1+2r)U^{n+1}_i- rU^{n+1}_{i-1}- rU^{n+1}_{i+1}$
    * For $i=0$, model the Neumann condition using central difference $\frac{U^n_1-U^n_{-1}}{2h}=0$ and we get the relation $U_0^n = (1+2r)U^{n+1}_0- 2rU^{n+1}_{1}$
    * For $i=N$, model the Neumann condition using central difference $\frac{U^{n+1}_{N+1}-U^{n+1}_{N-1}}{2h}=0$ and we get $U^n_N=-2rU^{n+1}_{N-1}+(1+2r)U^{n+1}_N$.
    
    To summarize, we get a `(N+1)x(N+1)` system $$\begin{pmatrix} \frac{1+2r}2 & -r & 0 & ... \\ -r & 1+2r & -r & ... \\  & \ddots & \\ & &1+2r &-r \\ & ...& -r & \frac{1+2r}2 \end{pmatrix}_{N+1\times N+1}\begin{pmatrix} U^{n+1}_0 \\ U^{n+1}_1\\ ...  \\ ...\\ U^{n+1}_{N-1}  \\ U^{n+1}_{N}\end{pmatrix}_{N+1}=\begin{pmatrix} U^{n}_0/2 \\ U^{n}_1\\ ...  \\ ...\\ U^{n}_{N-1}  \\ U^{n}_{N}/2\end{pmatrix}_{N+1}$$
    
    
* Computation:
We compute `3x3` times with different h's and k's and compare them with the exact solution. $$u(x,t) = e^{-\pi^2t}\cos(\pi x)$$

Python codes -

```
def headtail(vec):
    n = np.shape(vec)[0]
    veca = np.copy(vec)
    veca[0] = vec[0]/2
    veca[n-1] = vec[n-1]/2
    return veca

def solve_heat_Neumann(n_x, n_t, k):
    grid = np.linspace(-1,1,n_x+1)
    h = grid[1]-grid[0]
    
    F = np.zeros(n_x+1)
    for i in range(n_x+1):
        F[i] = math.cos(math.pi*grid[i])
    
    lamb_t_U = [] #this list collects U(t^n)
    lamb_t_U.append(F)
    
    r = k/h**2
    b = (1+2*r)*np.ones(n_x+1) #diagonal
    b[0] = (1+2*r)/2
    b[n_x] = (1+2*r)/2
    c = (-r)*np.ones(n_x) #superdiagonal
    a = (-r)*np.ones(n_x) #subdiagonal

    
    for i in range(n_t):
        U_new = Thomas(a,b,c, headtail(lamb_t_U[i]))
        lamb_t_U.append(U_new)
    
    return lamb_t_U
```
Courtesy to cbllelei's implementation of Thomas' algorithm.
https://gist.github.com/cbellei/8ab3ab8551b8dfc8b081c518ccd9ada9

![](https://i.imgur.com/5V0Yk2b.png)
![](https://i.imgur.com/1XiKOcp.png)

* Error:

Theoretically, $\bigg\{\begin{array}{l}\frac{u(x,t)-u(x,t-k)}k=u_t-1/2 ku_{tt}+O(k^2)\\ \frac{u(x+h,t)-2u(x,t)+u(x-h,t)}{h^2}=u_{xx} +1/6 h^2 u_{xxxx}+O(h^4)\end{array}$
thus $\frac{u(x,t)-u(x,t-k)}{k}-\frac{u(x+h,t)-2u(x,t)+u(x-h,t)}{h^2}=u_t-\frac12ku_{tt} +O(k^2)-u_{xx}-\frac16h^2u_{xxxx}-O(h^4)$

$=-(1/2k - 1/6 h^2)u_{tt}+ O(k^2+h^4)=O(k+h^2)$

Experimentally, I tried 9 combinations and computed their `R`(grid refinement order) and `E`(error from exact solution).
![](https://i.imgur.com/rj0bgtd.png)

As h refines, R is roughly $0.24$, confirming that this method is $O(h^2)$
; while as k refines, R is roughly $0.3427$, where $-\log_2 0.3427=1.6228$, better than expected $O(k)$.

While fixing $\mu$, (compare diagonally)

![](https://i.imgur.com/2WnZhFa.png)

`R_1 = 0.3355674678742637`
`R_2 = 0.33774295514543007`
`R_inf = 0.3428220815840617`

which is similar to refining k.

* Mass conservation:

The mass of a system is defined as $\mu(t^*)=\int_{-1}^1 u(x,t^*) dx$. We can use trapezoidal rule to calculate it.

This shows the mass with various h's and k's.
Blue: h=1/64, Orange: h=1/32, Green: h=1/16.


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



* Codes:
```
def headtail(vec):
    n = np.shape(vec)[0]
    veca = np.copy(vec)
    veca[0] = vec[0]/2
    veca[n-1] = vec[n-1]/2
    return veca

def solve_heat_Neumann(n_x, n_t, k):
    grid = np.linspace(-1,1,n_x+1)
    h = grid[1]-grid[0]
    
    F = np.zeros(n_x+1)
    for i in range(n_x+1):
        F[i] = math.cos(math.pi*grid[i])
    
    lamb_t_U = [] #this list collects U(t^n)
    lamb_t_U.append(F)
    
    r = k/h**2
    b = (1+2*r)*np.ones(n_x+1) #diagonal
    b[0] = (1+2*r)/2
    b[n_x] = (1+2*r)/2
    c = (-r)*np.ones(n_x) #superdiagonal
    #c[0] = -2*r
    a = (-r)*np.ones(n_x) #subdiagonal
    #a[n_x-1] = -2*r
    
    realmat = np.diag(a,-1)+np.diag(b,0)+np.diag(c,1)
    
    for i in range(n_t):
        U_new = Thomas(a,b,c, headtail(lamb_t_U[i]))
        lamb_t_U.append(U_new)
    
    return lamb_t_U
```
Courtesy to cbllelei's implementation of Thomas' algorithm.
https://gist.github.com/cbellei/8ab3ab8551b8dfc8b081c518ccd9ada9


---

### Exercise 4

Consider the diffusion equation
$$
u_t = u_{xx}-e^{\sin(x)}, \quad x\in[0, 1], \quad t\ge 0,
$$
with initial and boundary conditions
$$
u(x,0) = \cos(\pi x), \quad u'(0, t) =1, \quad  u(1,t)=0.
$$
Solve the equation and find the long-time behavior of the solution.
#### Answer:
* Partition: 
$x_0=0, \ x_{N+1}=1,\ x_i=ih$ with $h=\dfrac{1}{N+1},\ i=1,...,N$  \
k is the time step , $t_n=nk$
$U_{N+1}^n=u(x_{N+1},t_n)=u(1,t_n)=0.$

* Unknown: $U_i^n=u(x_i,t_n)$ for $i=0,1,...,N$

$u_t = u_{xx}-e^{\sin(x)},
\quad\Rightarrow\quad\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}-e^{\sin(x_i)}$

For $i=1,2,\dots ,N-1$ 
let $r=\frac{k}{h^2}$ and we have $$(1+2r)U_i^{n+1}-rU_{i+1}^{n+1}-rU_{i-1}^{n+1}=U_i^{n}-ke^{\sin(x_i)}$$

For i=N
$$(1+2r)U_N^{n+1}-rU_{N+1}^{n+1}-rU_{N-1}^{n+1}=U_N^{n}-ke^{\sin(x_N)}$$
Since $U_{N+1}^{n+1}=0$ ,we get $(1+2r)U_N^{n+1}-rU_{N-1}^{n+1}=U_N^{n}-ke^{\sin(x_N)}$

* For i=0  find a ghost point $U_{-1}^{n+1}$ so that we can approximate $u'(0,t)$ 

Since $u'(0,t)=1\approx\dfrac{U_1^{n+1}-U_{-1}^{n+1}}{2h}\quad\Rightarrow\quad U_{-1}^{n+1}=U_1^{n+1}-2h$.

For i=0
$$(1+2r)U_0^{n+1}-rU_{1}^{n+1}-rU_{-1}^{n+1}=U_0^{n}-ke^{\sin(x_0)}$$

Substituting $U_{-1}^{n+1}=U_1^{n+1}-2h$.

we get $(1+2r)U_0^{n+1}-2rU_{1}^{n+1}=U_0^{n}-ke^{\sin(x_0)}-2rh$


Hence the system becomes
$$
\begin{pmatrix}
\frac{1+2r}{2}& -r &   &   \\
   -r & 1+2r & -r   &     &  \\
      & -r &1+2r  & -r     &  \\
      &    &\ddots & \ddots   \\ 
      &    & & -r  & 1+2r\\
\end{pmatrix}
\begin{pmatrix}
U_0^{n+1} \\ U_1^{n+1} \\ \vdots \\ \vdots \\ U_N^{n+1}
\end{pmatrix}=
\begin{pmatrix}
 \frac{U_0^{n}-ke^{\sin(x_0)}-2rh}{2}\\U_1^{n}-ke^{\sin(x_1)}\\U_2^{n}-ke^{\sin(x_2)}\\ \vdots \\U_N^{n}-ke^{\sin(x_N)}
\end{pmatrix}.
 $$

$u_t-u_{xx}+e^{\sin(x_i)}-\dfrac{U_{0}^{n+1}-U_{0}^{n}}{k}+ \dfrac{U_{1}^{n+1}-2U_{0}^{n+1}-U_{i-1}}{h^2}-e^{\sin(x_i)}=O(h^2)+O(k)$

檢驗收斂性 : 分別取N= 99,199,399點,time step k=0.01 疊代次數 n=500
$h\approx\frac{1}{N+1}$ Then $\frac{||U_\frac{h}{2}-U_\frac{h}{4}||}{||U_h-U_\frac{h}{2}||}=0.24999847521995003\approx\frac{1}{4}$


Python code:
```
def heat(N,k,n):
    #N : the number of points
    #k : time step
    #n : iterative times
    import numpy as np

    h=1/(N+1)
    r=k/(h**2)
    x=np.linspace(0,1,N+2)
    U0=np.cos(np.pi*x[0:N+1]) #U0 initial
    U=U0+(-1)*k*np.exp(np.sin(x[0:N+1]))
    U[0]=0.5*(U[0]-2*h*r)

    d0=(1+2*r)*np.ones(N+1)
    d0[0]=0.5*(1+2*r)
    D0=np.diag(d0)

    d1=-r*np.ones(N)
    D1=np.diag(d1,1)

    d2=-r*np.ones(N)
    D2=np.diag(d2,-1) 
    D=D0+D1+D2

    Dinv=np.linalg.inv(D)

    for i in range(n):
        U=np.dot(Dinv,U)
        U=U+(-1)*k*np.exp(np.sin(x[0:N+1]))
        U[0]=0.5*(U[0]-2*h*r)

    import matplotlib.pyplot as plt
    #plt.plot(range(1,U.size),U[1:U.size])
    plt.plot(x[1:N+1],U[1:U.size])
    return U
```
the long-time behavior of the solution.
![](https://i.imgur.com/4syNfuf.png)

---

### Exercise 5

Consider the nonlinear diffusion equation
$$
u_t = u_{xx}, \quad x\in[0, 1], \quad t\ge 0,
$$
with initial and boundary conditions
$$
u(x,0) = \cos(\pi x/2), \quad u'(0, t) =0, \quad  u(1,t)=\sin(t).
$$
Solve the equation and find the long-time behavior of the solution.

**Solution** (Code with Julia)
We use method of line to solve this problem.
But to check the accuracy and consistency of code,
we use the same method to solve a simple case first.


#### Simple case:
$$
u_t = u_{xx}, \quad x\in[0, 1], \quad t\ge 0, \quad
u(x,0) = \cos(\pi x/2), \quad u'(0, t) =0, \quad  u'(1,t)=0.
$$
exact solution:
$$u(x,t)=C_0+\sum_{k=1}^{\infty} C_k e^{-k^2 \pi^2 t} \cos (k\pi x) \quad , C_0=\frac{2}{\pi} \quad , C_k=2\int_{0}^{1} u(x,0) \cos (k \pi x) dx$$
We use central difference to approximate $u_{xx}$
\
$$
\frac{1}{h^2}(U_{i+1}-2U_i+U_{i-1})=u_{xx}
$$
With partition(ghost point): 
$\mu=0.16=\frac{h^2}{k^2}$ (fixed)
$k=0.1, 0.05, 0.025$ (time step)
$N=\frac{1}{h}$ and $h=\sqrt{0.16} \ k=0.04, 0.02, 0.01$
$x_i=ih-0.5h$ with $i=0 \sim N+1$ 
$x_{0}\approx x_1, \\ x_{N+1}\approx x_N,$
(With truncation error $O(h^2)$)

then we get the system : $\frac{dU}{dt}= A\,U$ 
$$\frac{dU}{dt}=\frac{1}{h^2} \begin{pmatrix}
-1 & 1 & 0 & \cdots & 0 \\
1 & -2 & 1 & \cdots & 0 \\
\vdots & \ddots & \ddots & \ddots & \vdots \\
0 & \cdots & 1 & -2 & 1 \\
0 & \cdots & 0 & 1 & -1 
\end{pmatrix}U
\\
\\
\text{with } U(x_i,0)=U^0_i=
\begin{pmatrix}
\cos (\frac{\pi x_1}{2})\\
\vdots\\
\cos (\frac{\pi x_i}{2})\\
\vdots\\
\cos (\frac{\pi x_N}{2})
\end{pmatrix}
$$

Now we get an ode problem, 
so we can use differential equation solvers of julia to solve it.
\
Method: Midpoint - The second order midpoint method
(With truncation error $O(k^2)$)

```
mu=0.16 ##=h^2/k^2
k1=0.1
h1=mu^0.5*k1
N1=Int64(round(1/h1, digits=0))
x1=(1:N1).*h1.-(0.5*h1);
T=4*pi;
du_c = repeat([1],N1-1);
d_c = [-1;repeat([-2],N1-2);-1];
dl_c = repeat([1],N1-1);
A_c = Tridiagonal{Float64}(dl_c,d_c,du_c)
u0 = cos.(pi.*x1/2);
f(u,p,t) = A_c*u/h1^2
tspan = (0.0,T)
prob = ODEProblem(f,u0,tspan)
sol = solve(prob, Midpoint(), reltol=1e-8, abstol=1e-8,save_everystep=false,dt=k1)
```

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


because we know the exact solution of this problem is 
$$u(x,t)=C_0+\sum_{k=1}^{\infty} C_k e^{-k^2 \pi^2 t} \cos k\pi x \quad , C_0=\frac{2}{\pi} \quad , C_k=2\int_{0}^{1} u(x,0) \cos (k \pi x) dx$$
we can get the error of long time behavior$(t=4 \pi)$

|$h=\sqrt{\mu}k$ | k=0.1 | k=0.05 | k=0.025 |
| -------- | -------- | -------- |-------- |
|1 norm|0.000104732 | 2.61807e-5 | 6.54503e-6|
|2 norm|0.000104732 | 2.61807e-5 | 6.54503e-6|
|$\infty$ norm|0.000104736 | 2.61837e-5 | 6.54825e-6|
which is  $O(k^2)=O(h^2)$

#### True case:
Now let $u(1,t)=\sin(t)$ 
approximate $U_{N+1}$:
(ghost point with truncation error $O(h^2)$)
$$
\sin(t) = u(1,t) \approx \frac{U_{N}+U_{N+1}}{2} \Rightarrow U_{N+1} \approx 2 \sin(t)- U_N \\
$$
then we get the system : $\frac{dU}{dt}= A\,U+p(t)$ 

$$\frac{dU}{dt}=\frac{1}{h^2} \begin{pmatrix}
-1 & 1 & 0 & \cdots & 0 \\
1 & -2 & 1 & \cdots & 0 \\
\vdots & \ddots & \ddots & \ddots & \vdots \\
0 & \cdots & 1 & -2 & 1 \\
0 & \cdots & 0 & 1 & -3 
\end{pmatrix}U+\frac{1}{h^2}
\begin{pmatrix}
0\\
0\\
\vdots\\
0\\
2 \sin t
\end{pmatrix}
\\
\\
\text{with } U(x_i,0)=U^0_i=
\begin{pmatrix}
\cos (\frac{\pi x_1}{2})\\
\vdots\\
\cos (\frac{\pi x_i}{2})\\
\vdots\\
\cos (\frac{\pi x_N}{2})
\end{pmatrix}
$$

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

#### long time behavior of the solution:

![](https://i.imgur.com/Yic8n3z.png)
which looks like a periodic solution




---
