.. sectionauthor:: Yasuyuki SHIMIZU ############################################ Basics of partial differential equations ############################################ Finite differential schemes for advection equations ====================================================== One of the most basic partial differential equations that express the temporal and spatial fluid problems addressed by hydraulic engineers is the following advection equation. .. math:: :label: kiso_1 \cfrac{\partial f}{\partial t}+c\cfrac{\partial f}{\partial x}=0 Where, :math:`f` is the fluid advection amount, :math:`x` is the coordinate axis in the flow direction, :math:`t` is the time, and :math:`c` is the advection velocity. This equation expresses the state in which the variable :math:`f` is transported in the direction of :math:`x` at the velocity of :math:`c` while maintaining its value. The theoretical solution to Equation :eq:`kiso_1` can be relatively easily obtained as shown in the Appendix (refer to :ref:`advection`). For example, the first two terms on the left side of :eq:`mt_1` are included in this type of formula. You can see this type of formula on many different occasions. Now, as shown in :numref:`fig1`, we divide the :math:`x` axis by :math:`\Delta x` into 1, 2, 3, :math:`\cdots`, :math:`i-1, i, i+1`, :math:`\cdots`, :math:`N-1, N`. We also divide the :math:`t` axes by :math:`\Delta t` into 1, 2, 3, :math:`\cdots`, :math:`j-1, j, j+1, \cdots, J-1, J`. Then, if we assume that :math:`f` at :math:`(x, t)` is :math:`f(i,j)`, and :math:`f` at :math:`(x+\Delta x, t+\Delta t)` is :math:`f(i+1,j+1)`, then we have... .. _fig1: .. figure:: images/00/fig1.png :figclass: align-center :width: 90% : Placement of discrete variable in the space (:math:`x`, :math:`t`) The first term in Equation :eq:`kiso_1` expresses a temporal sequence. Then, generally it is expressed as follows. .. math:: :label: kiso2 \cfrac{\partial f}{\partial t} = \cfrac{f(i,j+1)-f(i,j)}{\Delta t} The second term expresses the spatial differentiation. There are the following three schemes that can be considered simple. .. math:: :label: forward c\cfrac{\partial f}{\partial x} = c\cfrac{f(i+1,j)-f(i,j)}{\Delta x} \; \; \; \; \; \mbox{[forward difference scheme]} .. math:: :label: backward c\cfrac{\partial f}{\partial x} = c\cfrac{f(i,j)-f(i-1,j)}{\Delta x} \; \; \; \; \; \mbox{[backward difference scheme]} .. math:: :label: central c\cfrac{\partial f}{\partial x} = c\cfrac{f(i+1,j)-f(i-1,j)}{2\Delta x} \; \; \; \mbox{[central difference scheme]} Considering the directions of these three difference schemes, Equation :eq:`forward` is called [forward difference scheme], Equation :eq:`backward` is called [backward difference scheme], and Equation :eq:`central` is called [central difference scheme]. [Central difference scheme] may seem the most intuitively accurate. But is it? Let us check which scheme gives the most accurate solutions in the following section. Differences in solutions by difference method ================================================ Backward difference scheme (The Python code and calculation results) ----------------------------------------------------------------------- Of the three difference schemes listed above, let us try the backward difference scheme first. Substituting Equation :eq:`kiso2` and Equation :eq:`backward` into Equation :eq:`kiso_1` gives us... .. math:: :label: kiso3 f(i,j+1)=f(i,j)-c\cfrac{f(i,j)-f(i-1,j)}{\Delta x}\Delta t To show the temporal and the spatial calculation range in an easily understandable way, we adopted the two-dimensional space of :math:`(i,j)`, as shown by :numref:`fig1`. However, in the actual calculation, once you calculate :math:`j \Rightarrow j+1`, you no longer need variables for :math:`j`. By coding this process as shown below, :math:`f` becomes a 1D problem. .. code-block:: python for i in range(1,N+1): fn[i]=f[i]-c*(f[i]-f[i-1])*dt/dx f=fn Calculate :math:`f` (here we assume it to be fn[i]) for a new “time”, then replace it with the :math:`f` of the old “time” and calculate the :math:`f` for the next time step. Then, repeat this process. The Python code for calculating the advection equation with a backward difference scheme is... https://github.com/YasuShimizu/Python-Code/blob/main/backward.py The calculation that results from this code is shown below. The initial distribution of :math:`f` is assumed to be a triangular distribution and is shown in :numref:`triangle`. Where, :math:`x_p` =10, :math:`x_b` =10, :math:`f_p` =0.5, and :math:`c` =0.5. .. _backward: .. figure:: images/00/backward.gif :width: 80% :align: center : Calculation results for the backward difference scheme (:math:`c>0`) .. _triangle: .. figure:: images/00/itg.png :width: 70% :align: center : Initial distribution of :math:`f` You may have noticed from :numref:`backward` that the solutions to this equation show the peak of the triangular distribution to gradually become smaller and the distribution shape to change, even though, as shown by :numref:`adv_anim` of Appendix, the triangular distribution should be maintained while it moves at a velocity of :math:`c`. The reasons will be explained later. Now, we make calculations using the forward difference scheme and the central difference scheme. The forward difference scheme (The Python code and calculation results) --------------------------------------------------------------------------- Substituting Equation :eq:`kiso2` and Equation :eq:`forward` into Equation :eq:`kiso_1` gives us the time-updated formula of :math:`f` using forward difference scheme as follows. .. math:: :label: kiso4 f(i,j+1)=f(i,j)-c\cfrac{f(i+1,j)-f(i,j)}{\Delta x}\Delta t The Python code for this section is... .. code-block:: python for i in range(1,N+1): fn[i]=f[i]-c*(f[i+1]-f[i])*dt/dx f=fn The source code is... https://github.com/YasuShimizu/Python-Code/blob/main/forward.py The calculation result for this code diverges ('ω'). .. _forward: .. figure:: images/00/forward.gif :width: 80% :align: center : Calculation results for the forward difference scheme (:math:`c>0`) Central difference scheme (The Python code and calculation results) ---------------------------------------------------------------------- Substituting Equation :eq:`kiso2` and Equation :eq:`central` into Equation :eq:`kiso_1` gives us the time-updated formula of using forward difference scheme as follows. .. math:: :label: kiso5 f(i,j+1)=f(i,j)-c\cfrac{f(i+1,j)-f(i-1,j)}{2 \Delta x}\Delta t The Python code is... https://github.com/YasuShimizu/Python-Code/blob/main/central.py The calculation result is... .. _central: .. figure:: images/00/central.gif :figclass: align-center :width: 80% : Calculation results for the central difference scheme (:math:`c>0`) In this case, the triangle seems to move at a constant velocity while keeping the value of the peak. However, the noise that’s generated backwards increases until the peak of noise exceeds the peak of the triangle, which is an unrealistic value. Summary ---------- Our comparison of the three difference schemes found the following. - None of them reproduce the theoretical solutions. - Although the backward difference scheme gives stable solutions, the solutions are inaccurate due to reductions in the peak values and for other reasons. - The central difference scheme maintains the initial distribution shape. However, it generates a lot of noise. - The solutions of the forward difference scheme diverge soon after the calculation starts. Advection direction and difference schemes ==================================================== The above discussions were for cases when the advection velocity, :math:`c`, is positive. Next, let us examine the cases of :math:`c<0`. The Python code and calculation results ------------------------------------------- Here, the calculation results for :math:`c<0` and the The Python code that correspond each case. .. _backward-: .. figure:: images/00/backward-.gif :width: 80% :align: center : Calculation results for the backward difference scheme (:math:`c<0`) https://github.com/YasuShimizu/Python-Code/blob/main/backward-.py .. _forward-: .. figure:: images/00/forward-.gif :width: 80% :align: center : Calculation results for the forward difference scheme (:math:`c<0`) https://github.com/YasuShimizu/Python-Code/blob/main/forward-.py .. _central-: .. figure:: images/00/central-.gif :width: 80% :align: center : Calculation results for the central difference scheme (:math:`c<0`) https://github.com/YasuShimizu/Python-Code/blob/main/central-.py Consequently, the features of the three difference schemes for :math:`c>0` and :math:`c<0` are summarized in the following table. .. list-table:: Summary of the three difference schemes :header-rows: 1 * - Difference scheme - Backward (:math:`i` and :math:`i-1`) - Forward (:math:`i` and :math:`i+1`) - Central (:math:`i-1` and :math:`i+1`) * - When :math:`c>0` - **Stable** but inaccurate - Divergence - Unstable but fairly accurate * - When :math:`c<0` - Divergence - **Stable** but inaccurate - Unstable but fairly accurate Therefore, stable calculation can be expected only for the backward difference scheme when :math:`c>0` and for the forward difference scheme when :math:`c<0`. These two schemes--the difference schemes in which the position data of i and i-1 are used when :math:`c>0` and in which i and i+1 are used when :math:`c<0`-- are called the **upwind difference scheme**, analogous to the naming convention for wind directions :math:`c`. The concept of **upwind difference scheme** is very important for numerical calculation. It means performing difference calculation in the direction of the information that is forwarded. However, the simple upwind difference schemes shown here have the shortcoming of providing stable but not highly accurate calculations. The reasons for this shortcoming will be discussed later. Next, we’ll talk about numerical solutions to diffusion equations, which in addition to advection equations, are important equations. Finite differential scheme for a diffusion equation ====================================================== Another important basic formula for fluid calculation is the diffusion equation shown below. .. math:: :label: diff_eq \displaystyle{{{\partial f}\over{\partial t}}=D{{\partial^2 f}\over{\partial x^2}}} Where, :math:`D` is the diffusion coefficient. Now, let us discuss the meaning of Equation :eq:`diff_eq`. .. _dif_ex1: .. figure:: images/00/diffusion_flux.png :width: 80% :align: center : Diffusion equation (1) Let us assume, as shown in :numref:`dif_ex1`, that :math:`f` is the density, that the density gradient :math:`\cfrac{\partial f}{\partial x}` occurs, that density transport is generated in the direction from high density to low density, that density transport is proportional to the density gradient, and that the proportional coefficient is :math:`D`, then the flux is expressed as :math:`-D\cfrac{\partial f}{\partial x}`. When the gradient is positive, flux transport is generated in the direction opposite to the :math:`x` axis. Therefore, please note that a positive transport volume is expressed in a negative value, thus put a minus sign, “-”. .. _dif_ex2: .. figure:: images/00/diffusion_cont.png :width: 80% :align: center : Diffusion equation (2) As shown in :numref:`dif_ex2`, we assume that the differences in the flux are caused by the density gradient between two points that are separated by the distance of :math:`\Delta x`. Such differences in flux generate density changes, :math:`f \Longrightarrow f+\cfrac{\partial f}{\partial t}\Delta t`, during time, :math:`\Delta t`. Then, we have... .. math:: :label: dif_def \left( \cfrac{\partial f}{\partial t}\Delta t \right) \Delta x =\left\{ \cfrac{\partial}{\partial x}\left(-D\cfrac{\partial f}{\partial x} \right) \Delta x \right\} \Delta t We divide both sides of Equation :eq:`dif_def` by :math:`\Delta x` and :math:`\Delta t`, and we assume that :math:`D` is a constant, then we have Equation :eq:`diff_eq`. The second derivative on the right side of :eq:`diff_eq` is obtained by first differentiating at both upper and lower sides of the calculation point and then differentiating them again. Therefore... .. math:: :label: second_dev D \cfrac{\partial^2 f}{\partial x^2}= \cfrac{D}{\Delta x} \left(\cfrac{f(i+1,j)-f(i,j)}{\Delta x} - \cfrac{f(i,j)-f(i-1,j)}{\Delta x}\right) \\ =\cfrac{D}{\Delta x^2}\Bigl\{f(i+1,j)-2f(i,j)+f(i-1,j)\Bigr\} If we assume that the differentiation of the left side in terms of time is simply the time difference, then the difference of :eq:`diff_eq` is expressed by the following equations. .. math:: :label: second_dec1 \cfrac{f(i,j+1)-f(i,j)}{\Delta t}= \cfrac{D}{\Delta x^2}\Bigl\{f(i+1,j)-2f(i,j)+f(i-1,j)\Bigr\} or .. math:: :label: second_dec2 f(i,j+1)=f(i,j)+ D \cfrac{\Delta t}{\Delta x^2} \Bigl\{f(i+1,j)-2f(i,j)+f(i-1,j)\Bigr\}\Delta t As we did for the advection equation in the previous section, we obtain the following, where f and fn are calculated by the successive interchanging of f and fn. .. code-block:: python for i in range(1,N+1): fn[i]=f[i]+D*(f[i+1]-2*f[i]+f[i-1])*dt/dx**2 f=fn The Python code and calculation results ------------------------------------------------- The entire source code is here. In addition, the calculation results when :math:`D=0.8` are shown by :numref:`diffusion_a`. https://github.com/YasuShimizu/Python-Code/blob/main/diffusion.py .. _diffusion_a: .. figure:: images/00/diffusion.gif :width: 80% :align: center : Calculation results for the diffusion equation Because :numref:`diffusion_a` expresses the situations where the peak becomes smaller and the distribution become wider, the situation is actually the diffusion phenomena. Thus, it is relevant. You may have noticed that :numref:`backward` and :numref:`forward-`, which are equivalent to the upwind difference scheme, diffuse similarly. The solutions to the advection equation are not supposed to diffuse in this way but are supposed to move while maintaining the initial distribution shape (:numref:`adv_anim`). For some reason, diffusion occurs at the same time as advection. In this way, the solutions to the advection equation are known to diffuse by “numerical calculation”, despite such diffusion not occurring in reality. Such diffusion is called “numerical diffusion” to distinguish it from the diffusion in real flow situation. Now, let us consider why such “numerical diffusion” occurs. .. _art_dif: Numerical diffusion caused by upwind differential shame ========================================================= The upwind difference scheme needs to change direction according to the direction of advection, or to the sign (+/-) of the value of :math:`c`. In coding, it’s sufficient to use “if” statements to make decisions each time, but explanations of the features are easier to understand when “if” statements are not used. Here, let me introduce a method that expresses the upwind difference scheme without “if” statements. First, let us consider the following equations. .. math:: :label: abs c + |c| = \Bigl\{ \begin{matrix} 2c & ;(c>0) \\ 0 & ;(c<0) \\ \end{matrix} \\ c - |c| = \Bigl\{ \begin{matrix} 0 & ;(c>0) \\ 2c & ;(c<0) \\ \end{matrix} Therefore, .. math:: :label: abs1 \cfrac{1}{2}(c + |c|) = \Bigl\{ \begin{matrix} c & ;(c>0) \\ 0 & ;(c<0) \\ \end{matrix} \\ \cfrac{1}{2}(c - |c|) = \Bigl\{ \begin{matrix} 0 & ;(c>0) \\ c & ;(c<0) \\ \end{matrix} Considering the features of Equation :eq:`abs1`, we assume the following equations. .. math:: :label: abs2 F=\cfrac{1}{2}(c + |c|)\cfrac{f(i)-f(i-1)}{\Delta x}+ \cfrac{1}{2}(c - |c|)\cfrac{f(i+1)-f(i)}{\Delta x} From Equation :eq:`abs1` and Equation :eq:`abs2`, .. math:: :label: abs3 F=\Biggl\{ \begin{matrix} c \cfrac{f(i)-f(i-1)}{\Delta x} & ;(c>0) \\ c \cfrac{f(i+1)-f(i)}{\Delta x} & ;(c<0) \\ \end{matrix} Therefore, .. math:: :label: abs4 \cfrac{\partial f}{\partial t}+F=0 or .. math:: :label: abs5 \cfrac{f_n(i)-f(i)}{\partial t} + \cfrac{1}{2}(c + |c|)\cfrac{f(i)-f(i-1)}{\Delta x}+ \cfrac{1}{2}(c - |c|)\cfrac{f(i+1)-f(i)}{\Delta x} =0 is an equation that expresses the upwind difference scheme without using “if” statements. Where, :math:`f_n(i)` and :math:`f(i)` respectively express :math:`f(i,j+1)=f(x,t+\Delta y)` and :math:`f(i,j)=f(x,t)`. From Equation :eq:`abs5`, the upwind difference scheme can be expressed by .. math:: :label: upwind_1 f_n(i)=f(i)- \underbrace{ \cfrac{c \Delta t}{2 \Delta x}\left\{ f(i+1)-f(i-1) \right\} }_{a} + \underbrace{ \cfrac{|c|\Delta t}{2 \Delta x} \left \{ f(i+1)-2f(i)+f(i-1) \right\}}_{b} Now, let us rewrite the central difference scheme in the advection equation of Equation :eq:`kiso5` and the difference scheme of the diffusivity equation, Equation :eq:`second_dec2`, with the same form, the central difference scheme of advection equation is .. math:: :label: central_1 f_n(i)=f(i)-\underbrace{ \cfrac{c \Delta t}{2 \Delta x} \left\{{f(i+1)-f(i-1)} \right\}}_{a'} The diffusivity equation is .. math:: :label: diffusion_1 f_n(i)=f(i)+ D \cfrac{\Delta t}{\Delta x^2} \Bigl\{f(i+1)-2f(i)+f(i-1)\Bigr\} Here, assuming that :math:`D=\cfrac{|c|\Delta x}{2}`, we obtain .. math:: :label: diffusion_12 f_n(i)=f(i)+\underbrace{ \cfrac{|c|\Delta t}{2\Delta x} \Bigl\{f(i+1)-2f(i)+f(i-1)\Bigr\}}_{b'} You can see that **a** in the Equation :eq:`upwind_1` is corresponding to **a’** in the Equation :eq:`central_1`, as well as **b** in Equation :eq:`upwind_1` is corresponding to the **b’** of Equation :eq:`diffusion_12`. The (**a+b**) part of the upwind difference scheme expressed by Equation :eq:`upwind_1` can be divided into a central difference scheme (**a'**) and a diffusion equation (**b'** ). Consequently, it’s in the form of their addition. The diffusion of the **b** part is initially an advection equation. Therefore, despite the diffusion of **b** not being included in reality, it is an element automatically included when we perform the upwind difference scheme. This is called "numerical diffusion" because it is included when numerical calculations are performed, in contrast to the original physical phenomena of "diffusion". This is what "numerical diffusion" really is. :numref:`backward` and :numref:`forward-` correspond to the upwind difference scheme. They are characterized by a central difference scheme that moves at a constant velocity while maintaining its shape and by diffusion whose peak decreases while its shape widens. This upwind difference scheme gives solutions that are stable but inaccurate. What we want are calculation results that are close to the theoretical values, as shown by :numref:`adv_anim`. So, in the next chapter, I will explain difference schemes that keep "numerical diffusion" as low as possible.