2次元Poisson方程式に対する有限要素法

# 初めに
[1次元](https://qiita.com/ShotaDeguchi/private/44d3df3176fd08927b60)の続き．

有限要素法の幾何学的柔軟性を味わいたい．

# Methods
## Poisson方程式
以下のPoisson方程式を考える．
```math
\begin{alignat}{2}
    - \nabla^2 u 
    &= f \quad &&\text{in} \quad \Omega \\
    u 
    &= g_D \quad &&\text{on} \quad \Gamma_D \\
    \boldsymbol{n} \cdot \nabla u 
    &= g_N \quad &&\text{on} \quad \Gamma_N
\end{alignat}
```
ここで，$\Omega \subset \mathbb{R}^d$は有界領域（$d = 2$），$\Gamma = \partial \Omega$は$\Omega$の境界，$\Gamma_D$はDirichlet境界，$\Gamma_N$はNeumann境界である．また，$\Gamma = \bar{\Gamma}_D \cup \bar{\Gamma}_N$，$\Gamma_D \cap \Gamma_N = \emptyset$，$\Gamma_D \neq \emptyset$，$\boldsymbol{n}$は$\Gamma$上の外向き単位法線ベクトルである．なお，$f: \Omega \to \mathbb{R}$，$g_D: \Gamma_D \to \mathbb{R}$，$g_N: \Gamma_N \to \mathbb{R}$は既知の関数とする．

## 弱形式化
関数空間
```math
\begin{align}
    U 
    &= \lbrace 
        u \in H^1 \left( \Omega \right) 
        \mid \left. u \right|_{\Gamma_D} = g_D
    \rbrace \\
    V 
    &= \lbrace 
        v \in H^1 \left( \Omega \right) 
        \mid \left. v \right|_{\Gamma_D} = 0 
    \rbrace
\end{align}
```
を定める．任意の$v \in V$をPoission方程式の両辺に乗じて，$\Omega$上で積分する．
```math
\begin{align}
    - \int_{\Omega} \nabla^2 u v \; dx
    &= \int_{\Omega} f v \; dx \\
\end{align}
```
Greenの第一恒等式から，
```math
\begin{align}
    \int_{\Omega} \nabla u \cdot \nabla v \; dx
    &= \int_{\Omega} f v \; dx + \int_{\Gamma_N} g_N v \; ds
\end{align}
```
を得る．これを，元のPoission方程式に対する弱形式（weak form）と呼ぶ．なお，
```math
\begin{align}
    \langle u, v \rangle 
    &= \int_{\Omega} \nabla u \cdot \nabla v \; dx \\
    \left( u, v \right) 
    &= \int_{\Omega} u v \; dx \\
    \left[ u, v \right] 
    &= \int_{\Gamma_N} u v \; ds \\
\end{align}
```
という記号を導入しておくと，弱形式は次のように書ける．
```math
\begin{align}
    \langle u, v \rangle 
    &= \left( f, v \right) 
        + \left[ g_N, v \right] 
\end{align}
```
弱形式に対する解は弱解（weak solution）と呼ばれていて，この弱解を元の問題の解として採用する，という方針である．

## 有限要素法
領域を有限個の要素に分割し（$\bar{\Omega} \simeq \hat{\Omega} := \bigcup_{k=1}^{K} e_k$），各要素上でGalerkin近似を考える．2次元問題で最も広く利用される，三角形1次要素（P1要素）を念頭に考える．要素分割の注意として，

* 要素間の隙間
* 要素同士の重なり
* ある頂点が他の要素の辺上に存在

を認めないこととする．節点には，$\lbrace P_i \rbrace_{i=1}^{M}$という番号を与える（2次元なので，既に$K + 1 = M$などという単純な関係は無い）．

基底関数には，1次元のときの自然な拡張として，$\hat{\Omega}$上で連続で，$e_k$上で$x$と$y$の1次多項式を区分的1次多項式と呼び，その全体を$\hat{W}$で表す．2変数の1次関数$f = c_0 + c_1 x + c_2 y$は平面であるから，$\hat{W}$は三角形を連続に繋ぐ折れ面である．

試行関数の空間$\hat{U}$，試験関数の空間$\hat{V}$は，次のように選ぶ（$\hat{U} \subset \hat{W}, \ \hat{V} \subset \hat{W}$，両者を同じ基底で張る (Bubnov–) Galerkin型の方法）．
```math
\begin{align}
    \hat{U} 
    &= \lbrace 
        \hat{u} \in \hat{W}
        \mid \left. \hat{u} \right|_{\Gamma_D} = \hat{g}_D
    \rbrace \\
    \hat{V} 
    &= \lbrace 
        \hat{v} \in \hat{W}
        \mid \left. \hat{v} \right|_{\Gamma_D} = 0
    \rbrace
\end{align}
```
弱形式
```math
\begin{align}
    \langle u, v \rangle 
    &= \left( f, v \right) 
        + \left[ g_N, v \right] \quad (v \in V)
\end{align}
```
を有限次元近似（区分的1次近似）して，
```math
\begin{align}
    \langle \hat{u}, \hat{v} \rangle 
    &= \left( f, \hat{v} \right) 
        + \left[ g_N, \hat{v} \right] \quad (\hat{v} \in \hat{V})
\end{align}
```
を考える．

### 面積
要素$e_k$に属する節点を，半時計回りに$N^k_i = (x^k_i, y^k_i) \ (i = 0, 1, 2)$と名付ける．この要素の面積$|e_k|$は，上付き文字を省略して，
```math
\begin{align}
    |e_k|
    &= \frac{1}{2} 
    \det \left(
        \begin{array}{cc}
            x_1 - x_0 & x_2 - x_0 \\
            y_1 - y_0 & y_2 - y_0 \\
        \end{array}
    \right) \\
    &= \frac{1}{2} \left(
        (x_1 - x_0) (y_2 - y_0) - (x_2 - x_0) (y_1 - y_0)
    \right)
\end{align}
```
相対位置ベクトルが為す平行四辺形の面積を利用している．

### 面積座標（重心座標）
要素$e_k$に属する節点を，半時計回りに$N^k_i = (x^k_i, y^k_i) \ (i = 0, 1, 2)$と呼んでいる（$k$番目の要素についての話であることに気を付けながら，見易さのため，肩の数字を省略する）．

任意の1次関数
```math
\begin{align}
    \hat{u} (x, y)
    &= \alpha_0 + \alpha_1 x + \alpha_2 y \quad (x, y \in e_k)
\end{align}
```
は，3節点$N_i$における値$u^i = \hat{u} (N_i) \ (i = 0, 1, 2)$が定まれば，定まる．特に，節点$N_i$で1, その他の節点で0となる1次関数$L_i \ (i = 0, 1, 2)$を導入する．つまり，
```math
\begin{align}
    L_i (N_j)
    &= L_i (x_j, y_j)
     = \delta_{ij} \quad (i, j = 0, 1, 2)
\end{align}
```
$(L_0, L_1, L_2)$を用いると，任意の1次関数$\hat{u}$は，
```math
\begin{align}
    \hat{u} (x, y)
    &= \sum_{i=0}^{2} u^i L_i (x, y) \quad (x, y \in e_k)
\end{align}
```
と書ける．即ち，$(L_0, L_1, L_2)$は1次関数の基底になる．

任意の点$P (x, y) \in e_k$に対して，3つの実数の組$(L_0(P), L_1(P), L_2(P))$を，点$P$の面積座標（area coordinate），或いは重心座標（barycentric coordinate）と呼ぶ．多分，数学ではこういう呼び方をしていて，工学では形状関数（shape function）と呼ぶ方が馴染みがある（と思う）．

任意の点$P (x, y) \in e_k$に対して，
```math
\begin{align}
    L_0 (P) + L_1 (P) + L_2 (P) 
    &= 1
\end{align}
```
が成り立つ．

面積座標における積の積分には，$i, j, k \in \mathbb{Z}_{\ge 0}$に対して
```math
\begin{align}
    \int_{e_l}
        L_0^i L_1^j L_2^k
    \; dx
    &= \frac{2 |e_l| i! j! k!}{(2 + i + j + k)!}
\end{align}
```
が成り立つことが知られている（全然良く理解していないが，取り敢えず認めよう）．

### 面積座標の係数
$L_i \ (i = 0, 1, 2)$は，節点$N_i$で1, その他の節点で0となる．その係数を
```math
\begin{align}
    L_i
    &= a_i + b_i x + c_i y
\end{align}
```
とすると，
```math
\begin{align}
    \delta_{ij}
    &= L_i (N_j)
     = L_i (x_j, y_j) \\
    &= a_i + b_i x_j + c_i y_j \\
    &= \left( 
        \begin{array}{ccc}
            1 & x_j & y_j
        \end{array}
    \right) 
    \left( 
        \begin{array}{c}
            a_i \\
            b_i \\
            c_i
        \end{array}
    \right) \\
\end{align}
```
より（Kroneckerのdeltaを回すとidentityになるから），
```math
\begin{align}
    I
    &= \left( 
        \begin{array}{ccc}
            1 & x_0 & y_0 \\
            1 & x_1 & y_1 \\
            1 & x_2 & y_2 \\
        \end{array}
    \right) 
    \left( 
        \begin{array}{ccc}
            a_0 & a_1 & a_2 \\
            b_0 & b_1 & b_2 \\
            c_0 & c_1 & c_2 \\
        \end{array}
    \right) \\
\end{align}
```
であるから，
```math
\begin{align}
    B
    &:= \left( 
        \begin{array}{ccc}
            1 & x_0 & y_0 \\
            1 & x_1 & y_1 \\
            1 & x_2 & y_2 \\
        \end{array}
    \right) 
\end{align}
```
とすると，
```math
\begin{align}
    \left( 
        \begin{array}{ccc}
            a_0 & a_1 & a_2 \\
            b_0 & b_1 & b_2 \\
            c_0 & c_1 & c_2 \\
        \end{array}
    \right) 
    &= B^{-1}
\end{align}
```
である．$B^{-1}$を具体的に計算しておく．
```math
\begin{align}
    B^{-1}
    &= \left( 
        \begin{array}{ccc}
            1 & x_0 & y_0 \\
            1 & x_1 & y_1 \\
            1 & x_2 & y_2 \\
        \end{array}
    \right)^{-1}
     = \frac{1}{\det B} \tilde{B} \\
\end{align}
```
[基本変形と行列式の関係](https://mathlandscape.com/elementary-matrix/#toc10)から，
```math
\begin{align}
    \det B
    &= \det
    \left( 
        \begin{array}{ccc}
            1 & x_0 & y_0 \\
            1 & x_1 & y_1 \\
            1 & x_2 & y_2 \\
        \end{array}
    \right) \\
    &= \det
    \left( 
        \begin{array}{ccc}
            1 & x_0       & y_0       \\
            0 & x_1 - x_0 & y_1 - y_0 \\
            0 & x_2 - x_0 & y_2 - y_0 \\
        \end{array}
    \right) \\
    &= \det
    \left( 
        \begin{array}{cc}
            x_1 - x_0 & y_1 - y_0 \\
            x_2 - x_0 & y_2 - y_0 \\
        \end{array}
    \right) \\
    &= 2 |e_k| \\
    &= (x_1 - x_0) (y_2 - y_0) - (x_2 - x_0) (y_1 - y_0)
\end{align}
```
$B$の余因子行列$\tilde{B}$は，
```math
\begin{align}
    \tilde{B}
    &= \left( 
        \begin{array}{ccc}
            (-1)^{1+1} |\tilde{B}_{11}| & (-1)^{1+2} |\tilde{B}_{12}| & (-1)^{1+3} |\tilde{B}_{13}| \\
            (-1)^{2+1} |\tilde{B}_{21}| & (-1)^{2+2} |\tilde{B}_{22}| & (-1)^{2+3} |\tilde{B}_{23}| \\
            (-1)^{3+1} |\tilde{B}_{31}| & (-1)^{3+2} |\tilde{B}_{32}| & (-1)^{3+3} |\tilde{B}_{33}| \\
        \end{array}
    \right)^{\top} \\
    &= \left( 
        \begin{array}{ccc}
            x_1 y_2 - x_2 y_1 & y_1 - y_2 & x_2 - x_1 \\
            x_2 y_0 - x_0 y_2 & y_2 - y_0 & x_0 - x_2 \\
            x_0 y_1 - x_1 y_0 & y_0 - y_1 & x_1 - x_0 \\
        \end{array}
    \right)^{\top} \\
    &= \left( 
        \begin{array}{ccc}
            x_1 y_2 - x_2 y_1 & x_2 y_0 - x_0 y_2 & x_0 y_1 - x_1 y_0 \\
            y_1 - y_2         & y_2 - y_0         & y_0 - y_1 \\
            x_2 - x_1         & x_0 - x_2         & x_1 - x_0 \\
        \end{array}
    \right) \\
\end{align}
```
即ち，
```math
\begin{align}
    B^{-1}
    &= \left( 
        \begin{array}{ccc}
            a_0 & a_1 & a_2 \\
            b_0 & b_1 & b_2 \\
            c_0 & c_1 & c_2 \\
        \end{array}
    \right) \\
    &= \frac{1}{2 |e_k|} \left( 
        \begin{array}{ccc}
            x_1 y_2 - x_2 y_1 & x_2 y_0 - x_0 y_2 & x_0 y_1 - x_1 y_0 \\
            y_1 - y_2         & y_2 - y_0         & y_0 - y_1 \\
            x_2 - x_1         & x_0 - x_2         & x_1 - x_0 \\
        \end{array}
    \right) \\
\end{align}
```

### 要素係数行列
弱形式（の有限次元近似）を再掲する．
```math
\begin{align}
    \langle \hat{u}, \hat{v} \rangle 
    &= \left( f, \hat{v} \right) 
        + \left[ g_N, \hat{v} \right] \quad (\hat{v} \in \hat{V})
\end{align}
```
記号
```math
\begin{align}
    \langle \hat{u}, \hat{v} \rangle_{e_k}
    &= \int_{e_k} \nabla \hat{u} \cdot \nabla \hat{v} \; dx \\
    \left( f, \hat{v} \right)_{e_k} 
    &= \int_{e_k} f \hat{v} \; dx \\
\end{align}
```
を導入し，積分は，要素毎に計算しておき，後から和を取る方針（$\int_{\Omega} = \sum_{k} \int_{e_k}$）を取る．即ち，
```math
\begin{align}
    \sum_{k=1}^{K} \langle \hat{u}, \hat{v} \rangle_{e_k} 
    &= \sum_{k=1}^{K} \left( f, \hat{v} \right)_{e_k} 
        + \left[ g_N, \hat{v} \right] \quad (\hat{v} \in \hat{V})
\end{align}
```
を考える．ここで，$u^j := \hat{u} (N_j), \ v^j := \hat{v} (N_j) \ (j = 0, 1, 2)$を用いて，
```math
\begin{align}
    \hat{u}
    = \sum_{j=0}^{2} u^j L_j , \quad
    \hat{v}
    = \sum_{i=0}^{2} v^i L_i \quad (\text{on } e_k) 
\end{align}
```
という補間を与えると，
```math
\begin{align}
    \langle \hat{u}, \hat{v} \rangle_{e_k}
    &= \sum_{j=0}^{2} \sum_{i=0}^{2} v^i A_{ij}^{(k)} u^j \\
    \left( f, \hat{v} \right)_{e_k}
    &= \sum_{i=0}^{2} v^i f_i^{(k)} \\
\end{align}
```
但し，
```math
\begin{align}
    A_{ij}^{(k)}
    &:= \langle L_j, L_i \rangle_{e_k} \\
    f_i^{(k)}
    &:= \left( f, L_i \right)_{e_k}
\end{align}
```
いま，
```math
\begin{align}
    \boldsymbol{u}_k
    &:= \left( u^0, u^1, u^2 \right)^{\top} \\
    \boldsymbol{v}_k
    &:= \left( v^0, v^1, v^2 \right)^{\top} \\
    \boldsymbol{f}_k
    &:= \left( f_0^{(k)}, f_1^{(k)}, f_2^{(k)} \right)^{\top} \\
    \boldsymbol{A}_k
    &:= \left(
        \begin{array}{ccc}
            A_{00}^{(k)} & A_{01}^{(k)} & A_{02}^{(k)} \\
            A_{10}^{(k)} & A_{11}^{(k)} & A_{12}^{(k)} \\
            A_{20}^{(k)} & A_{21}^{(k)} & A_{22}^{(k)} \\
        \end{array}
    \right)
\end{align}
```
とおくと，$\boldsymbol{A}_k$は対称で，
```math
\begin{align}
    \langle \hat{u}, \hat{v} \rangle_{e_k}
    &= \boldsymbol{v}_k^{\top} \boldsymbol{A}_k \boldsymbol{u}_k \\
    \left( f, \hat{v} \right)_{e_k}
    &= \boldsymbol{v}_k^{\top} \boldsymbol{f}_k \\
\end{align}
```
と書ける．ここで，$A_{ij}^{(k)} = \langle L_j, L_i \rangle_{e_k}$は，
```math
\begin{align}
    A_{ij}^{(k)}
    &= \langle L_j, L_i \rangle_{e_k} \\
    &= \int_{e_k} \nabla L_j \cdot \nabla L_i dx \\
    &= \int_{e_k} \nabla (a_j + b_j x + c_j y) \cdot \nabla (a_i + b_i x + c_i y) dx \\
    &= \int_{e_k} 
        \left( 
            \begin{array}{c}
                 b_j \\ c_j 
            \end{array}
        \right)
        \cdot
        \left( 
            \begin{array}{c}
                 b_i \\ c_i
            \end{array}
        \right)
    dx \\
    &= \left( b_j b_i + c_j c_i \right) |e_k|
\end{align}
```
一方，$f_i^{(k)} = \left( f, L_i \right)_{e_k}$については，$f^j := f (N_j) \ (j = 0, 1, 2)$を用いて，
```math
\begin{align}
    f
    = \sum_{j=0}^{2} f^j L_j
\end{align}
```
という補間を与え，
```math
\begin{align}
    f_i^{(k)}
    &= \left( f, L_i \right)_{e_k} \\
    &= \left( \sum_{j=0}^{2} f^j L_j, L_i \right)_{e_k} \\
    &= \sum_{j=0}^{2} f^j \left( L_j, L_i \right)_{e_k} \\
    &= \sum_{j=0}^{2} f^j \int_{e_k} L_j L_i dx \\
\end{align}
```
面積座標における便利な公式
```math
\begin{align}
    \int_{e_k}
        L_0^p L_1^q L_2^r
    dx
    &= \frac{2 \; |e_k| \; p! \; q! \; r!}{(2 + p + q + r)!}
\end{align}
```
から，
```math
\begin{align}
    \int_{e_k} L_0^2 \; dx
    &= \frac{2 \; |e_k| \; 2! \; 0! \; 0!}{(2 + 2 + 0 + 0)!}
     = \frac{|e_k|}{6} \\
    \int_{e_k} L_0 L_1 \; dx
    &= \frac{2 \; |e_k| \; 1! 1\; ! \; 0!}{(2 + 1 + 1 + 0)!} 
     = \frac{|e_k|}{12} \\
    \int_{e_k} L_1 L_2 \; dx
    &= \frac{2 \; |e_k| \; 0! \; 1! \; 1!}{(2 + 0 + 1 + 1)!} 
     = \frac{|e_k|}{12} \\
    \int_{e_k} L_0 L_2 \; dx
    &= \frac{2 \; |e_k| \; 1! \; 0! \; 1!}{(2 + 1 + 0 + 1)!} 
     = \frac{|e_k|}{12} \\
\end{align}
```
より，
```math
\begin{align}
    f_i^{(k)}
    &= \sum_{j=0}^{2} f^j \int_{e_k} L_j L_i dx \\
    f_0^{(k)}
    &= f^0 \int_{e_k} L_0 L_0 dx 
        + f^1 \int_{e_k} L_1 L_0 dx
        + f^2 \int_{e_k} L_2 L_0 dx \\
    &= \frac{|e_k|}{12} \left( 2 f^0 + f^1 + f^2 \right) \\
    f_1^{(k)}
    &= \frac{|e_k|}{12} \left( f^0 + 2 f^1 + f^2 \right) \\
    f_2^{(k)}
    &= \frac{|e_k|}{12} \left( f^0 + f^1 + 2 f^2 \right) \\
\end{align}
```
を得る．

### 直接剛性法
1次元のときと同様に，系全体に拡大する．全節点には，$\lbrace P_i \rbrace_{i=1}^{M}$という番号を与えていることを思い出す．

$u_i := \hat{u} (P_i), v_i := \hat{v} (P_i) \ (i = 1, ..., M)$として，
```math
\begin{align}
    \boldsymbol{u}
    &:= \left( u_1, u_2, ..., u_M \right)^{\top} \\
    \boldsymbol{v}
    &:= \left( v_1, v_2, ..., v_M \right)^{\top} \\
\end{align}
```
とする．

要素$e_k \ (k = 1, ..., K)$に属する節点$N^k_0, N^k_1, N^k_2$に対し，
```math
\begin{align}
    N^k_0 = P_{i^k_0}, \
    N^k_1 = P_{i^k_1}, \
    N^k_2 = P_{i^k_2}
\end{align}
```
となる整数$i^k_0, i^k_1, i^k_2$を取る．これらを全体節点番号と呼ぶ．

続いて，$\boldsymbol{f}_{k}^{*} \in \mathbb{R}^M$を，第$i^k_0, i^k_1, i^k_2$成分が$f^{(k)}_0, f^{(k)}_1, f^{(k)}_2$であり，それ以外の成分がゼロのベクトルとすると，
```math
\begin{align}
    \left( f, \hat{v} \right)_{e_k}
    = \boldsymbol{v}_k^{\top} \boldsymbol{f}_k
    = \boldsymbol{v}^{\top} \boldsymbol{f}_k^{*} \quad (k = 1, ..., K)
\end{align}
```
同様に，$\boldsymbol{g}_{k}^{*} \in \mathbb{R}^M$をNeumann条件が課された節点でのみ値を持ち，それ以外の成分がゼロのベクトルとすると，
```math
\begin{align}
    \left[ g_N, \hat{v} \right] 
    = \boldsymbol{v}^{\top} \boldsymbol{g}_k^{*} \quad (k = 1, ..., K)
\end{align}
```
さらに，$\boldsymbol{A}_{k}^{*} \in \mathbb{R}^{M \times M}$をゼロで埋められた行列とする．

但し，第$(i^k_m, i^k_n)$成分には$A_{mn}^{(k)}$を代入する．これを用いると，
```math
\begin{align}
    \langle \hat{u}, \hat{v} \rangle_{e_k}
    = \boldsymbol{v}_k^{\top} \boldsymbol{A}_k \boldsymbol{u}_k
    = \boldsymbol{v}^{\top} \boldsymbol{A}_k^{*} \boldsymbol{u} \quad (k = 1, ..., K)
\end{align}
```
以上より，弱形式
```math
\begin{align}
    \sum_{k=1}^{K} \langle \hat{u}, \hat{v} \rangle_{e_k} 
    &= \sum_{k=1}^{K} \left( f, \hat{v} \right)_{e_k} 
        + \left[ g_N, \hat{v} \right] 
\end{align}
```
は，
```math
\begin{align}
    \sum_{k=1}^{K} \boldsymbol{v}^{\top} \boldsymbol{A}_k^{*} \boldsymbol{u}
    &= \sum_{k=1}^{K} \boldsymbol{v}^{\top} \boldsymbol{f}_k^{*}
        + \boldsymbol{v}^{\top} \boldsymbol{g}_k^{*} \\
    \boldsymbol{v}^{\top} 
    \left(
        \sum_{k=1}^{K} \boldsymbol{A}_k^{*} \boldsymbol{u}
        - \sum_{k=1}^{K} \boldsymbol{f}_k^{*}
        - \boldsymbol{g}_k^{*}
    \right)
    &= 0 \\
\end{align}
```
に同値となる．
```math
\begin{align}
    \boldsymbol{A}^{*}
    &= \sum_{k=1}^{K} \boldsymbol{A}_k^{*} \\
    \boldsymbol{b}^{*}
    &= \sum_{k=1}^{K} \boldsymbol{f}_k^{*} + \boldsymbol{g}_k^{*} \\
\end{align}
```
とおくと，
```math
\begin{align}
    \boldsymbol{v}^{\top} 
    \left(
        \boldsymbol{A}^{*} \boldsymbol{u}
        - \boldsymbol{b}^{*}
    \right)
    &= 0 \\
\end{align}
```
である．$\boldsymbol{v} \in \check{V} = \lbrace \boldsymbol{v} \in \mathbb{R}^{M} \mid v_i = 0 \text{ for } i \text{ s.t. } P_i \in \Gamma_D \rbrace$の任意の元であるから，
```math
\begin{align}
    \boldsymbol{A}^{*} \boldsymbol{u}
    - \boldsymbol{b}^{*}
    \in \breve{V}
    &= \lbrace
        \boldsymbol{w} \in \mathbb{R}^{M} 
        \mid w_i = 0 \text{ for } i \text{ s.t. } P_i \notin \Gamma_D
    \rbrace
\end{align}
```
即ち，
```math
\begin{align}
    \boldsymbol{A}^{**} \boldsymbol{u}
    &= \boldsymbol{b}^{**}
\end{align}
```
ここで，
```math
\begin{align}
    \boldsymbol{A}^{**}
    &:= \boldsymbol{A}^{*} \text{の第$i$行（$P_i \in \Gamma_D$なる$i$）を除いた行列} \\
    \boldsymbol{b}^{**}
    &:= \boldsymbol{b}^{*} \text{の第$i$成分（$P_i \in \Gamma_D$なる$i$）を除いた縦ベクトル} \\
\end{align}
```
である．いま，$\boldsymbol{u} \in \mathbb{R}^M$に対して，Dirichlet条件$u_i = g_D (P_i) \ (P_i \in \Gamma_D)$を課す．
```math
\begin{align}
    \boldsymbol{A}^{**}
    &= \left(
        \begin{array}{cccc}
            \boldsymbol{a}_1 & \boldsymbol{a}_2 & ... & \boldsymbol{a}_M \\
        \end{array}
    \right)
\end{align}
```
と書くと，
```math
\begin{align}
    \sum_{i=1}^{M} \boldsymbol{a}_i u_i
    &= \boldsymbol{b}^{**} \\
    \sum_{P_i \in \Gamma_D} \boldsymbol{a}_i u_i
    + \sum_{P_i \notin \Gamma_D} \boldsymbol{a}_i u_i
    &= \boldsymbol{b}^{**} \\
    \sum_{P_i \notin \Gamma_D} \boldsymbol{a}_i u_i
    &= \boldsymbol{b}^{**} 
    - \sum_{P_i \in \Gamma_D} \boldsymbol{a}_i u_i \\
    \boldsymbol{A} \boldsymbol{u}^{*}
    &= \boldsymbol{b}
\end{align}
```
を解けば良い．但し，
```math
\begin{align}
    \boldsymbol{A}
    &:= \boldsymbol{A}^{**} \text{の第$i$列（$P_i \in \Gamma_D$なる$i$）を除いた正方行列} \\
    \boldsymbol{u}^{*}
    &:= \boldsymbol{u} \text{の第$i$成分（$P_i \in \Gamma_D$なる$i$）を除いた縦ベクトル} \\
    \boldsymbol{b}
    &:= \boldsymbol{b}^{**} 
    - \sum_{P_i \in \Gamma_D} \boldsymbol{a}_i u_i \\
\end{align}
```
である．

# Results
## Square
幾何学的柔軟性は見え辛いが，先ずは最も素朴に．

### 斉次Dirichlet条件
Dirichlet問題
```math
\begin{alignat}{2}
    - \nabla^2 u &= f \quad &&\text{in} \quad \Omega \\
    u &= g_D \quad &&\text{on} \quad \Gamma_D \\
\end{alignat}
```
を考え，$\Omega = (-1, 1)^2, \ \Gamma_D = \partial \Omega$とし，$f = 1, \ g_D = 0$とする（斉次Dirichlet境界値問題）．ネット上の拾い物だが，[こちら](https://people.inf.ethz.ch/arbenz/FEM17/pdfs/0-19-852868-X.pdf)に変数分離による解が載っている．
```math
\begin{align}
    u
    &= \frac{1 - x^2}{2}
        - \frac{16}{\pi^3} \sum_{k = 1, \ k \in \mathrm{odd}}^{\infty}
            \frac{\sin(k \pi (1 + x) / 2)}{k^3 \sinh(k \pi)}
            \left(
                \sinh(k \pi (1 + y) / 2) + \sinh(k \pi (1 - y) / 2)
            \right) \\
    &\simeq \frac{1 - x^2}{2}
        - \frac{16}{\pi^3} \sum_{k = 1, \ k \in \mathrm{odd}}^{201}
            \frac{\sin(k \pi (1 + x) / 2)}{k^3 \sinh(k \pi)}
            \left(
                \sinh(k \pi (1 + y) / 2) + \sinh(k \pi (1 - y) / 2)
            \right) \\
\end{align}
```
これを有限和で近似しておき，解像度を徐々に増加させながら解くことで，数値解の収束を確認する．[`scipy.spatial.Delaunay`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.Delaunay.html)を利用してメッシュを作成し，ソルバーには[昔作った](https://qiita.com/ShotaDeguchi/items/bd10ad3e65922b797d77)CG法を使った（`numpy.allclose`を使って確認したところ，`numpy.linalg.solve`でも同じ結果であった）．[CSCとかCSRとかの工夫](https://docs.scipy.org/doc/scipy/reference/sparse.html)はしていない．後で触れるため，有限差分法による解を併記する（今は触れない）．

| $M: \text{# node}$ | $M=25$ | $M=81$ | $M=289$ | $u (0, 0)$ | $\mathrm{Error}$ |
|:-:|:-:|:-:|:-:|:-:|:-:|
| $u_{\text{FDM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/26574768-eeef-1fb8-bb7a-24b5000322e0.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0d685267-6064-55ca-d875-f50139f9f39d.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/f820f1a7-3df9-7412-9271-e6eef5b40e3c.png) | ![fig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/2179989b-e717-3043-47e6-2d0a2ee2adb8.png) | ![fig (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e866af48-fd5b-1970-0511-e4b66af54c12.png) |
| $u_{\text{FEM}}$ | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/266b71db-7460-f7f4-046e-bcb7001a3837.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c3c26a95-f737-78e1-3892-2aed9b9923f3.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/efc751a6-78b7-b8e6-8b79-4323bd84b39d.png) | ![convergence_u_h.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/6ab391ea-20b5-c71d-ccb4-e39d247a4635.png) | ![convergence_h.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/94edc752-b4e1-7468-e2ac-d521d92dea73.png) |

[1次元のとき](https://qiita.com/ShotaDeguchi/private/44d3df3176fd08927b60)と同じく，誤差の最大値が2次の速度で収束する．また，全体的な誤差は1次の速度で収束する（1次元のときは見えなかったが，これが良く聞く$\mathcal{O}(h^p)$の収束のことだろうか？と思ったが，[Karniadakis&Sherwin2005](https://doi.org/10.1093/acprof:oso/9780198528692.001.0001)を見ると，一般には，誤差の$H^1$ノルムが$\sim \mathcal{O}(h^p)$で減少するらしい）．ところで，後で登場するGmshと比べると，隅付近のメッシュの品質に疑問があるが，まあいいか．

### 斉次Dirichlet条件 + 斉次Neumann条件
混合境界値問題
```math
\begin{alignat}{2}
    - \nabla^2 u &= f \quad &&\text{in} \quad \Omega \\
    u &= g_D \quad &&\text{on} \quad \Gamma_D \\
    \boldsymbol{n} \cdot \nabla u &= g_N \quad &&\text{on} \quad \Gamma_N
\end{alignat}
```
を考え，
```math
\begin{align}
    \Omega
    &= (0, 1)^2 \\
    \Gamma_D
    &= \lbrace (x, 0) \cup (0, y) \mid x \in (0, 1), y \in (0, 1) \rbrace \\
    \Gamma_N
    &= \lbrace (x, 1) \cup (1, y) \mid x \in (0, 1), y \in (0, 1) \rbrace \\
\end{align}
```
とし，$f = 1, \ g_D = g_N = 0$とする．要素数$K$を徐々に増加させながら解く．再度，`scipy.spatial.Delaunay`を利用してメッシュを作成し，ソルバーには昔作ったCG法を使った．CSCとかCSRとかの工夫はしていない．

|   | $K=8$ | $K=32$ | $K=128$ | $K=512$ |
|:-:|:-:|:-:|:-:|:-:|
| $2D$ | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/2d8437ee-b5eb-b9ac-2afa-2a20ac9f0b60.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/75f751e2-c077-2f39-3695-6a34f56de286.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0a430a2f-5422-d6f2-d8dd-80a58f724d37.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/1a85731b-b1ee-e126-a55e-5f71a3912520.png) |
| $3D$ | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e9c43bd2-b3b5-7951-8e5f-e002b2a01a84.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c1a2d4a2-6779-a4c9-df6e-dda29a8425d2.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/84412437-2ffd-3f3f-1e99-f2372a3ed3ca.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/3079e8be-a519-a3f0-211f-846d437bda99.png) |

[こちら](http://nalab.mind.meiji.ac.jp/~mk/labo/report/open/2004-nagi.pdf)を見ると，恐らく正しそうだ．

また，線形ソルバー（反復法）の比較もしてみたが，[昔の実験](https://qiita.com/ShotaDeguchi/items/bd10ad3e65922b797d77)と同じような結果を得た．

|   | Residual | Solution |
|:-:|:-:|:-:|
| $K=512$   | ![solver_comparison.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/a7eac7e1-d7c7-cbee-28a4-14791c3fd388.png) | ![solver_comparison_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/1f484fee-aba4-90f8-2888-2a736300875c.png) |
| $K=2,048$ | ![solver_comparison.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/a9c520ca-5122-ec12-f68e-0b7c464c6c72.png) | ![solver_comparison_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/972944d9-f797-cb54-59bc-78bb9f4a9785.png) |
| $K=8,192$ | ![solver_comparison.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/533dede2-e9fd-894c-bce7-3dde4599c5d1.png) | ![solver_comparison_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/bb23d3a7-a815-ba59-7409-37ab934283b4.png) |

Residualのカラムで，$M_{(\cdot)}$は反復行列，$\varrho (\cdot)$はスペクトル半径である（タイトルの$M$は節点数，$K$は要素数，$\kappa_{(\cdot)}$は条件数）．SOR法の緩和パラメータは，えいやっと$\omega = 1.8$を選んだ[^1]．最適 / 準最適ではないだろうが，少なくとも悪い数字ではないはずだ（経験的に，大きい問題ほど，$\omega \to 2$を攻めると効果がある[^2]）．CG法については，[戸川1977](https://ci.nii.ac.jp/ncid/BN0068903X)の
[^1]: 最適な緩和パラメータは，Jacobi法の反復行列のスペクトル半径を用いて計算できるそうだが，わざわざJacobi法の反復行列を作り，固有値計算までやらなければならないのは骨が折れる（大きい問題では特に）．
[^2]: 同様のことが，[こちら](http://emoss.starfree.jp/OpenSTF/chap2_2.htm)でも言及されている．

> 共役勾配法によれば有限回（$n$元の方程式の場合，高々$n$回）で厳密解を得ることができるが，実際には，$n$よりももっとはるかに少ない回数で十分な精度の解が得られる場合が少なくない．

という記述の確からしさが確認できる．自由度が小さいときは何れの方法も収束するが，自由度が大きくなるとGauss-Seidel法などは（現実的な時間内に）収束し切れず，劣悪な解しか得られない（が，スムージングされていることは強調すべきであろう, cf. [マルチグリッド法との関係](https://www.youtube.com/watch?v=4UoJpazu_fU)）．

### 斉次Dirichlet条件 + 非斉次Neumann条件 + non-constant source
昔，大学院で有限要素法の講義を受講したとき，以下のような問題をFreeFEMで解いた事がある（cf. [github](https://github.com/ShotaDeguchi/FreeFEM)）．
```math
\begin{alignat}{2}
    - \nabla^2 u 
    &= - \sin \left( 2 \pi \left( x + y \right) \right) \quad &&\text{in} \quad \Omega = (0, 1)^2 \\
    u 
    &= 0      \quad &&\text{on} \quad y=0 \\
    \nabla u  \cdot \boldsymbol{n}
    &= 0.05 \quad &&\text{on} \quad y=1,\ x=0,\ x=1
\end{alignat}
```
以下はFreeFEMによる有限要素法の解と自作コードの有限差分法の解．同じことを，自作の有限要素法でできるか？当然，できなければならない（勿論，離散化スキームやメッシャーの違いなどに起因する数値解の若干の揺らぎはあるだろうが，この程度の簡単な問題で，各手法における数値解の間に大きな乖離が存在するとは考え辛い）．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/f4007525-810b-d14b-84fc-97e82dea3e4c.png)

先ずは，non-constantなsourceの導入（$h$は解像度を意味する離散化パラメータ）．

| $h$ | $\sim 0.12$ | $\sim 0.06$ | $\sim 0.03$ |
|:-:|:-:|:-:|:-:|
| $u_{\text{FDM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/28be208c-a9e2-6624-02fc-a708f4dea1c1.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/36a4f1e8-5f9e-8d52-0aa4-1d2e8bb49e8e.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/08291f6a-67ea-f131-7618-c4d372cae6dd.png) |
| $u_{\text{FEM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/8c0a2758-cbf6-7a4e-d428-f7985950375f.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/6a465fa0-9986-14b2-46ec-ee19f6b5f425.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/ddbd320a-d057-c1c5-ca0e-20c473db12de.png) |

次いで，斉次Neumann条件への書き換え．

| $h$ | $\sim 0.12$ | $\sim 0.06$ | $\sim 0.03$ |
|:-:|:-:|:-:|:-:|
| $u_{\text{FDM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/932a4be9-4e52-a962-3808-0a62d91c8720.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/ad0d618e-9041-676c-7ec9-0424022dae6b.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0acbc573-bc1b-8aee-64c2-8ef1587921ba.png) |
| $u_{\text{FEM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/855c0059-c7f9-92e2-3498-7d7e9dd2d8da.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/a3fded56-389a-da7a-7877-4605bd767631.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/5d4daacd-559d-4ff8-c494-feca4d200dc3.png) |

最後に，非斉次Neumann条件の導入．

| $h$ | $\sim 0.12$ | $\sim 0.06$ | $\sim 0.03$ |
|:-:|:-:|:-:|:-:|
| $u_{\text{FDM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/61e460de-d4d5-5bde-a67a-c84b59138f73.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/6708df36-7c6c-00a3-dc2a-dde52d468f4b.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e07180d5-7c1e-141e-0c95-e2494fc4e111.png) |
| $u_{\text{FEM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/d11e5414-5a6b-21cb-4290-1b6a6ea43a97.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/ffb1c179-43a3-e69a-0d74-7cdb5b9bee8c.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e411cfc2-4ea9-af9e-d9af-a9e8d90c2023.png) |

FDM，FEM両者は同じ自由度（節点数）である．さらに，全ての節点は全く同じ座標に置いている．但し，FEMにはP1要素を使っているので，要素数としてはFEMが多い．また，FDMにおけるLaplace作用素は2次精度の近似，Neumann境界の取り扱いは1次精度の近似である（外側にghost cellを置いて2次精度にするなどの工夫はしていない）．加えて，線形ソルバーが違っていて，FDMはpoint Jacobi，FEMはConjugate Gradientとしている．全くフェアとは言えないが，収束判定の閾値は同じ値にしている（$\le 10^{-6}$）．また，可視化も同じ方法（[`matplotlib.pyplot.tricontourf`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.tricontourf.html)）．

上記のような違いはあるが，FreeFEM，自作FDM，自作FEMの何れの方法においても，殆ど同等の数値解を得たと言って良いだろう．本稿のスコープとしては，自作FEMがFreeFEMと同じような解を得たのは喜ばしい．ところで，FreeFEMの解と自作FDM，自作FEMの$h \sim 0.03$は殆ど同じくらいの節点数を持つ（1軸を32分割，要素の品質は違うから，要素数も多分少し違う）．

なお，解像度の意味では，FDMよりFEMの方が収束速度が速いだろうか？誤差解析とかをきちんと勉強すれば，きちんと比較できる気がする．菊池先生の本（[菊池1994](http://www.baifukan.co.jp/cgi-bin/db/fromjapanbook.pl?ISBN=4-563-03388-X)，[菊池1999](https://www.saiensu.co.jp/search/?isbn=978-4-7819-0911-0&y=1999)）のどちらかに載っていたように記憶している（多分，前者だろうね）．FDMの誤差解析は存在するのだろうか？余り聞いたことが無い（今の時代，FDMをやっている人も少ないし）．

興味深いこととして，最も粗い解像度（$h \sim 0.12$）のときのFDM solとFEM solを比較すると，FEMの方がNeumann境界付近での解が良好であるように見える（特に右上のピーク）．FDMではNeumann条件を1次精度で陽に課した一方，有限要素法ではこれを弱形式に取り込み陽に課した訳ではない．にも関わらず，FEMの方がパワフルに見える（見えるだけかもしれない）．これも，きちんと誤差解析を勉強すれば議論できそうな気がするが，未だ十分な知識を持ち合わせていない．

### 非斉次Dirichlet条件
非斉次なDirichlet条件を課す問題を探していたところ，Laplace方程式だが，以下を見つけた（[Millan+2015](https://doi.org/10.1016/j.cma.2014.10.012)）．

$\Omega = (0, 1)^2$において，
```math
\begin{alignat}{2}
    \nabla^2 u &= 0 \quad &&\text{in} \quad \Omega \\
    u &= 0      \quad &&\text{on} \quad x=0,\ x=1,\ y=0 \\
    u &= x(1-x) \quad &&\text{on} \quad y=1
\end{alignat}
```
に対して，
```math
\begin{align}
    u
    &= \frac{8}{\pi^3}
        \sum_{n=1, \ 3, \ 5, \ ...}^{\infty}
        \frac{1}{n^3 \sinh(n \pi)}
        \sin  (n \pi x)
        \sinh (n \pi y)
\end{align}
```
が解．$N = \lbrace 1, 21, 51, 101, 201, 401, 801 \rbrace$までの有限級数を作ってみたところ，$N = \lbrace 401, 801 \rbrace$では解が吹き飛んだ．3乗とかの速度で数値が大きくなることによる数値誤差の影響だろう．話題がすっかり変わるが，尤度関数の代わりに対数尤度関数の計算を使うのも，こういう理由で都合が良いのだろう．

| $N = 21$ | $N = 201$ | $N = 401$ | $u_{\text{max}}$ | $\| u_{\text{max}} - 0.25 \|$ |
|:-:|:-:|:-:|:-:|:-:|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/4ea73b0a-c8f3-2a9b-6d5e-7f10440bfdfa.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c9a0a90d-cc9c-680b-baf2-2f6ceca650a1.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/878541f2-a788-c86e-50bd-4ad00f547baa.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/76ba54c2-7ecb-216d-6c40-79008d18e2e7.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/ffab0c51-d755-fab0-74ac-571217d90261.png) |

安全のため，$N = 101$までの有限級数で近似し，これを厳密解として取り扱う．

上記の問題から引き続き，FDMとFEMで解く．今回は厳密解が分かっているので，FDM，FEM両者で誤差の収束が議論できるのが嬉しい．

| $h$ | $\sim 0.12$ | $\sim 0.06$ | $\sim 0.03$ | $\text{Error}$ |
|:-:|:-:|:-:|:-:|:-:|
| $u_{\text{FDM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/3c992f9f-e14b-870d-4cba-ef45609caed5.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/41f9f603-ad69-c562-ebc6-9de44ba1a559.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/64da9ee1-a567-c007-92f9-2cc54fdcefc6.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/ffcd8ffc-42a5-1316-832e-459cfacde7aa.png) |
| $u_{\text{FEM}}$ | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/da58c45d-d4ca-ff7a-6f7e-8b82e44b21e9.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0fc1c65e-8fa9-0ec0-95a7-4abdb81c3d83.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/40de68c3-e76e-a43a-d1b3-13389c5366c8.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/a999c06f-fa4f-656f-a30d-a5eb07b8ff13.png) |

相変わらず，FDMとFEM両者は同じだけの節点を持ち，節点の座標はFDM，FEMで共通している．FDMは正方形のセル，FEMはそれを二分するP1要素で解いている．FDMの係数行列が対称でないから，両者に[`scipy.sparse.linalg.spsolve`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.spsolve.html)（直接法）を使った．非対称な系のための反復法（e.g., bicgstab, gmres）も幾つか試したのだけれど，途中から爆発していき，うまく収束の傾向を見られなかった（V字のような収束の傾向）．`scipy`を使っただけなので理由が良く分からなかったのが残念だが，取り敢えず，ソルバーに起因する問題と解像度に起因する誤差の収束は切り分けるべきだろうと思ったので，一貫して安定して解けた直接法を使った．スコープをFDMとFEMの比較に絞れば，かなりフェアにできただろうかと思っている（或いはバイアスされているかもね）．可視化には，FDMでは四角形セルを用いたことを強調するために`plot_surface`を，FEMでは三角形要素を用いたことを強調するために`plot_trisurf`を使った（可視化の都合だが，いまは分かり易さが大切だと思った）．

FDMは，$L^2$，$L^\infty$の両者が1次程度の速度で収束した（因みに，最初に取り上げた素朴な問題（$- \nabla^2 u = 1 \text{ in } \Omega, u = 0 \text{ on } \Gamma$）に対しても同様の調査を行ったが，やはりFDMでは，$L^2$，$L^\infty$共に1次収束であった）．FEMは，他の問題でも見た通り，$L^2$が1次程度，$L^\infty$が2次程度の速度で収束した．係数行列は殆ど同じなのだけれど，こうして少しでも違いがあるとは面白い（同じになると予想していた）．が，$L^2$の意味では同じくらいだし，大差無いと言ってしまっても良いだろうか？ただ，個人的には，有限差分法の収束を見ることができて嬉しい．だって，局所的な離散化は2次精度（Laplacianは2次精度中心差分近似した）なのに，大域的には1次精度でしか収束しないだなんて，どっひゃー面白いじゃないか（どうでも良いことだが，[陽的Euler法](https://qiita.com/ShotaDeguchi/items/639657f65ee136d17add)でも同様の性質を見たことを思い出す）．

以上の観測結果から大雑把なことを言ってしまうと，FDMとFEMの違いは$L^\infty$の収束速度であるように感じる（勿論，このような簡単な問題に限った話）．混合境界値問題のときに見た，FEMのピークを捉える上手さは，ここから来ているのだろうか．観測ベースなので数学的でないのが残念だが，現在の私の直感的な理解はこんなところだ．やはり，きちんと数学を学ばなければそろそろdead endだ．


## Pentagon
[アメリカ国防総省の本庁舎](https://en.wikipedia.org/wiki/The_Pentagon)．頂点が1つ増えただけだが，有限差分法では既に取り扱いが難しい（有限差分法でも工夫すれば不可能ではない？cf. [こちら](https://qiita.com/atily17/items/ce3127bb71dcac7b5aab)）．外側の節点の座標は[こちら](https://keisan.casio.jp/exec/user/1334446988)で計算し，メッシュの作成にはGmsh（[Geuzaine&Remacle2009](https://doi.org/10.1002/nme.2579)）を用いた．$f = 1$とする．

### 斉次Dirichlet条件
Gmshでは，目安となるメッシュサイズ$h$を指定する（target mesh sizeと呼ばれる）．必ず達成できる訳ではない．図中には，$h$に加えて節点数$M$，要素数$K$を併記した．

|   | $h=1.6$ | $h=0.8$ | $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|:-:|:-:|:-:|
| $2D$ | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/928898eb-dca4-4701-50e5-645740149646.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/41555729-3b6e-69d7-3313-7a58f9d9a80b.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/3f613bd5-219c-907c-4ee1-e56a5047639b.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/7e122b4b-9fd2-edcd-c9ac-d43cf19937aa.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/acc8724c-d793-b240-3180-56ac764b4ec4.png) |
| $3D$ | ![solution_3d_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e5e7f5dd-9cc6-04d6-1095-c7a51a987784.png) | ![solution_3d_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/3a00bab7-31a2-2fa8-ae5f-6e552fea4f4a.png) | ![solution_3d_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/35e916ad-900c-0046-d953-1a0970813cf4.png) | ![solution_3d_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/cce9845e-a90a-a10e-bbac-b835f96a7a91.png) | ![solution_3d_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c6916b1a-a506-d47f-8544-c05bc3cd876b.png) |

2Dの図における背景のグレーの線は，メッシュを意味する．特に，低解像度の解から，要素内の補間がpolynomial of 1st order（折れ面）で形成されているのが確認できる（あれ，可視化上の都合かな，，まあ都合の良い解釈で良いか）．

ところで，[`scipy.sparse.linalg.spsolve`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.spsolve.html#scipy.sparse.linalg.spsolve)を利用し，且つ係数行列をCSR形式で渡しておくと，問題が大きいときにかなり有利であることが分かった（単に`scipy.sparse.linalg.spsolve`を使うだけだとpay-offは少ない[^3]）．なお，CSRとCSCは余り差が無かった，対称な所為だろうか，，（きちんと読んでいないが，類似の議論があったのでメモしておく: [こちら](https://qiita.com/damyarou/items/8ca3432f9bba20a1f5ea#%E7%96%8E%E8%A1%8C%E5%88%97%E5%87%A6%E7%90%86%E5%B0%8E%E5%85%A5%E3%81%AB%E3%82%88%E3%82%8B%E9%80%A3%E7%AB%8B%EF%BC%91%E6%AC%A1%E6%96%B9%E7%A8%8B%E5%BC%8F%E5%87%A6%E7%90%86%E3%81%AE%E9%AB%98%E9%80%9F%E5%8C%96)）
[^3]: 実は，[`scipy.sparse.linalg.spsolve`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.spsolve.html#scipy.sparse.linalg.spsolve)には，"The square matrix A will be converted into CSC or CSR form"と書いてあるから，特別何もしなくても速くなることを期待したのだけれど（利用している`scipy==1.13.1`のドキュメンテーションを見ている）．CSC/CSRに変更しないまま`spsolve`に渡すと，`SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format`と警告される．
```python: pseudocode
import numpy as np
import scipy as sp
A, b = assemble(A_k, b_k, ...)   # A_k, b_k: element-wise matrix, vector
A, b = set_boundary_condition(A, b, ...)
u_np = np.linalg.solve(A, b)
u_sp = sp.linalg.solve(A, b, assume_a="sym")
u_ss = sp.sparse.linalg.spsolve(A, b)
u_sc = sp.sparse.linalg.spsolve(sp.sparse.csr_matrix(A), b)
```
target mesh size $h$ を変えながら64回解き，要した時間の平均値と（Bessel補正された）標本標準偏差を記録した．マーカー付き実線は平均値，shadeは1倍の標本標準偏差．

![solver_comparison.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/7f0dd6ba-83ab-013c-ef64-845a173e02a8.png)

横軸はメッシュサイズなので，右側ほど問題規模が小さく，左側ほど問題規模が大きい（後から気づいたが，`sp.sparse.linalg.spsolve`は直接法らしい，おっとっと，，）．

`plt.spy`とか`plt.imshow`とかを使えば，`A`がスパースであることが確認できる．問題規模が大きいほど，sparsityがある．

| $h=1.6$ | $h=0.4$ | $h=0.1$ |
|:-:|:-:|:-:|
| ![matrix_A_heatmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/33162893-0ac2-3fad-b757-820e465f16d3.png) | ![matrix_A_heatmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/aa9a61fe-769e-19ba-1611-ea4720fb3ae9.png) | ![matrix_A_heatmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/4d6fe1e7-93ac-70e6-66ca-1c05cd55bae5.png) |

ここでは，`plt.imshow`を使った．青い箇所が$<0$，赤い箇所が$>0$，白い箇所が$=0$（背景の白色と同化しているが）．

### 斉次Dirichlet条件 + 斉次Neumann条件 (1)
左側の境界に斉次Dirichlet条件を課す．その他は斉次Neumann条件．

| $h=1.6$ | $h=0.8$ | $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|:-:|:-:|
| ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/3b73df77-9958-8c7c-ecb8-0cd160032650.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/a424f1ba-a0c0-e65a-c0fd-a34c9214eb69.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/190f418d-b9dc-470a-c2b0-14e9ec75230c.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0eb5f980-7358-3510-4e54-6611bd75323c.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e2ff2f1d-91a9-13cc-fdc3-cffc84a127d7.png) |

### 斉次Dirichlet条件 + 斉次Neumann条件 (2)
$y \le 0$なる境界ノードに斉次Dirichlet条件を課す．その他は斉次Neumann条件．

| $h=1.6$ | $h=0.8$ | $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|:-:|:-:|
| ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/62434d00-5d43-f33f-24ac-28831a652a71.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/1323f1d8-b96a-c1aa-8472-86e9359d9384.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/f35472e6-9497-6743-1eac-d29aa0e93697.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/9ce51f0f-df9c-68d9-90c8-ec2a474c1a8f.png) | ![solution_gmsh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/25061f29-42af-4c1f-5c92-1427be285ffb.png) |

左端に$y = 0$なる境界ノードが有ったり無かったりで様子が違うが，まあご愛嬌かな．

## Icosagon (20-gon)
正20角形．本当は円がやりたかったが，Gmshでの円の定義，というか，適切なメッシュ切りが良く理解できなかったので，誤魔化す．勉強し直して戻って来たい．

### 斉次Dirichlet条件
| $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|
| ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0c60a568-177f-4c53-3890-d1fccf722b51.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/97919609-649d-696e-491a-622758421ff6.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/dba8037b-60ae-5663-06fb-b44185ede87c.png) |

### 斉次Dirichlet条件 + 斉次Neumann条件
| $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|
| ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/d9286246-ba1f-04df-a882-68fce6e10ab7.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/f2066a15-ea43-3f96-89cc-e4dd3a7184cd.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/7ce1eb33-967e-4d48-445d-8f10b1dc8e5c.png) |

## L-shape
L字型．$f = 1$とする．

### 斉次Dirichlet条件
|  | $h=0.8$ | $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|:-:|:-:|
| $2D$ | ![L_h0.8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/2273cbf1-2a26-5ebc-ace7-1015100b2474.png) | ![L_h0.4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/82b9cd70-3754-40c6-1d4a-4dffe38fbb71.png) | ![L_h0.2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/36e1b631-18fc-dabf-9050-a8dd5a837c33.png) | ![L_h0.1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/3b433ea8-92cf-a3c3-c06a-7c3c61a68f55.png) | 
| $3D$ | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/846603cf-a72d-786f-6378-f912f86ce021.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/0dcfb19c-b744-8e4d-3e69-68ec7c1ac119.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/14490a1e-3c63-f40c-aa82-ad1f425f251c.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/693f9557-a9af-42a9-8416-95bda8541f50.png) |

$h=0.8$は劣悪だが，やはりP1要素の補間を感じることができる．高解像度化するにつれ，数値解が収束してゆき，[こちら](https://people.inf.ethz.ch/arbenz/FEM17/pdfs/0-19-852868-X.pdf)と合致してくるので，正しくコードが書けていると思う．

ところで，Gmshでは，特定の節点周辺のみ高解像度化することができる．Gmshに特別な話ではなく，一般的な有限要素法でも行われる．非一様なメッシュと呼ばれる．

|  | $h_f=h_c/2$ | $h_f=h_c/4$ | $h_f=h_c/8$ | $h_f=h_c/16$ |
|:-:|:-:|:-:|:-:|:-:|
| $h_c=0.8$ | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/f9e11cdf-5d06-fdad-8362-a48da581f1c0.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/99ef8ad0-1ac3-064c-284c-2712a847dc6e.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/718c8934-4b42-bd2f-f78f-229ee8bd3d17.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/b4153fae-729b-9ea7-bd6b-43064ac82e2a.png) |
| $h_c=0.4$ | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/1e77e067-2d96-6fef-cb15-c66d1c5b3ce0.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/2aa18cd7-17df-e28e-40a9-c1344aa41483.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/e478d278-39d6-3e56-4cdc-ae3a6476709b.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/bafa70e8-25e3-f8ee-22ab-e85eaf33af8c.png) |
| $h_c=0.2$ | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c0ffa411-5fac-ff63-408f-ac391c53d8cc.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/be93317b-38fd-c236-294a-53ed392b54cd.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/cf2f2413-ee2e-8022-189d-19e1ea99f37b.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/b87dbe7b-4444-70e2-ac40-f61b5f3eb486.png) |
| $h_c=0.1$ | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/03748e63-d604-ad73-617f-7bf343668406.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/757b5e71-6dcd-2d2c-5ace-86fd270736b3.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c1157b33-000b-20cd-f867-edd97aa5dd7d.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/78cced03-001a-fefc-daed-34be49f9388f.png) |

$h_f$は凹な箇所付近での細かい（fine）メッシュのサイズ，$h_c$はそれ以外の箇所での粗い（coarse）メッシュのサイズである（タイトルの$h$は$h_c$に対応している）．凹な箇所付近だけ高解像度化できている．自由度の増加を適切に抑えつつ，興味がある領域のみ高解像度化できる（局所的な高解像度化）．

### 斉次Dirichlet条件 + 斉次Neumann条件
|  | $h=0.8$ | $h=0.4$ | $h=0.2$ | $h=0.1$ |
|:-:|:-:|:-:|:-:|:-:|
| $2D$ | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/8462e576-7242-d0f0-98fa-9cb38fdb9e20.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/9aa9d93c-2ac5-edfb-e865-3f40aa881e74.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/b0002ad1-55c1-8f47-4c36-46d226718898.png) | ![solution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/f54d3dd2-c8e6-b925-8453-f31fe6f44938.png) | 
| $3D$ | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/518fbef1-21bb-5333-3b5a-0d3ba80b0752.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/c69404a7-de35-d397-3629-c28d0d53d147.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/37d52c29-0221-a9b9-2c4c-c4897423a59a.png) | ![solution_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529612/b5976b29-9f34-ea13-6ec2-fdad24d041a5.png) | 

参照できる解が無いが，等値線がperpendicularに突き刺さり，正しそうだ．

<!---
## Circle
円．$f = 1$とし，全体に斉次Dirichlet条件を与える．

## Annulus
円環．$f = 1$とし，全体に斉次Dirichlet条件を与える．

## Landolt C
視力検査のアレ．$f = 1$とし，全体に斉次Dirichlet条件を与える．

## Dolfin
イルカﾁｬﾝ．FEniCS/DOLFINx（[Baratta+2023](https://doi.org/10.5281/zenodo.10447666)，[こちら](https://fenicsproject.org/olddocs/dolfin/1.5.0/python/demo/documented/stokes-taylor-hood/python/documentation.html)）がオリジナルのようだが，PyVista（[Sullivan&Kaszynski2019](https://doi.org/10.21105/joss.01450)，[こちら](https://docs.pyvista.org/examples/00-load/read-dolfin)）から取った．$f = 1$とし，イルカ周辺に斉次Neumann条件，外部境界全体に斉次Dirichlet条件を与える．

| Mesh | Quality (Scaled Jacobian) | Solution |
|:-:|:-:|:-:|
|   |   |   |

本当は[Decimation](https://docs.pyvista.org/examples/01-filter/decimate#sphx-glr-examples-01-filter-decimate-py)・[Subdivision](https://docs.pyvista.org/examples/01-filter/subdivide#sphx-glr-examples-01-filter-subdivide-py)機能を用いて低・高解像度化してみたかったが，どちらも
```python
AttributeError: 'UnstructuredGrid' object has no attribute 'decimate'
AttributeError: 'UnstructuredGrid' object has no attribute 'subdivide'
```
で怒られたので，諦めた．
--->

# 終わりに
ムズいなぁ，，

実は，手法の議論は，殆ど[桂田先生の資料](http://nalab.mind.meiji.ac.jp/~mk/lecture/applied-complex-function-2019/members/fem.pdf)を焼き増した形になってしまった，，余り良くない（桂田先生の資料は非常に明快なのだが，我が物顔で色々言うのは違う，という意味）．数値実験を色々試し，その中で自分が気になったことに触れる，という形で差分を作った（つもりだ）．

しかし，コードを自作して，当初の予定通り有限要素法の幾何学的柔軟性を体験できたり，予定外だったけどP1の補間の様子を体験できたり，局所的高解像度化の様子を体験できたりしたのは，喜ばしいことだよね．

それと，Neumann条件を厳密に満たすように近似解を構成している訳ではないのに，全体として近似の精度が良い関数を構成できる，というのは面白い．これはどちらかと言うと，弱形式の枠組み自体の特徴だろうか（cf. [最小二乗法 vs. Galerkin法](https://qiita.com/ShotaDeguchi/items/4bfd94b11adea89d8a85)）．[Karniadakis&Sherwin2005](https://doi.org/10.1093/acprof:oso/9780198528692.001.0001)のch2.2.1.1には，"in the Galerkin formulation Dirichlet boundary conditions have to be specified explicitly whereas Neumann conditions are dealt with implicitly as part of the formulation."という記述があり，この文は個人的に分かり易いと感じた．

<!---
# Appendix
## 収束性の確認
最も簡単な
```math
\begin{alignat}{2}
    - \nabla^2 u &= f \quad &&\text{in} \quad \Omega \\
    u &= g_D \quad &&\text{on} \quad \partial \Omega \\
\end{alignat}
```
を考える．$\Omega$はunit squareとし，$f, \ g_D$は共に定数とする．

方針としては，斉次方程式（homogeneous eq, Laplace方程式）の解$u_h$


### 全体: 斉次Dirichlet条件
Dirichlet問題を考える．
```math
\begin{alignat}{2}
    - \nabla^2 u &= f \quad &&\text{in} \quad \Omega \\
    u &= g_D \quad &&\text{on} \quad \partial \Omega
\end{alignat}
```
$\Omega = (0, 1)^2$とし，$f = 1, \ g_D = 0$とする．要素数$K$を徐々に増加させながら解く．

--->