FESTUNG模型介绍—1.对流方程求解
1. 控制方程
对流问题中,控制方程表达式为
[partial_t C + partial_x (u^1 C) + partial_y (u^2 C) = 0, quad mathrm{in} ; Omega
]
其中边界处包含 Dirichlet 和 Neumann 边界条件,分别为
[egin{array}{cl}
C = C_D & mathrm{on} ; partial Omega_D, \
-
abla C cdot mathbf{v} = g_N & mathrm{on} ; partial Omega_N.
end{array}
]
2. 数值离散
将控制方程利用间断有限元离散后,积分方程形式为
[underbrace{ int_{mathcal{T}_k} varphi_{ki} sum_{j=1}^N partial_t C_{kj} varphi_{kj} }_{I}
- underbrace{ int_{mathcal{T}_k} partial_x varphi_{ki} sum_{j=1}^N C_{kj} varphi_{kj} sum_{j=1}^N u^1_{kl} varphi_{kl}
- int_{mathcal{T}_k} partial_y varphi_{ki} sum_{j=1}^N C_{kj} varphi_{kj} sum_{j=1}^N u^1_{kl} varphi_{kl} }_{II} \
+ underbrace{ left {
egin{array}{c}
sum_{n=1}^3 int_{partial mathcal{T}_k} v_{kn}^1 u^1_{k} varphi_{ki} sum_{j=1}^N C_{kj}^* varphi_{kj}
+ sum_{n=1}^3 int_{partial mathcal{T}_k} v_{kn}^2 u^2_{k} varphi_{ki} sum_{j=1}^N C_{kj}^* varphi_{kj} quad mathrm{on} ; mathcal{E}_{Omega} \
sum_{n=1}^3 int_{partial mathcal{T}_k} v_{kn}^1 u^1_{k} varphi_{ki} sum_{j=1}^N C_D^* varphi_{kj}
+ sum_{n=1}^3 int_{partial mathcal{T}_k} v_{kn}^2 u^2_{k} varphi_{ki} sum_{j=1}^N C_D^* varphi_{kj} quad mathrm{on} ; mathcal{E}_{D}
end{array}
ight }
}_{III} = 0.
]
将方程写为矩阵形式
[mathbf{M} partial_t mathbf{C} + left( - mathbf{G}^1 - mathbf{G}^2 + mathbf{S}
ight) mathbf{C} = mathbf{K}_D,
]
其中 (mathbf{C}=[C_{11}, cdots, C_{1N}, cdots, C_{K1}, cdots, C_{KN}]^ op) 未知数待求系数。在方程中,(mathbf{M}, mathbf{G}^1,mathbf{G}^2,mathbf{S}) 为各系数矩阵,下面分别介绍各个矩阵表达式。
(mathbf{M}) 为质量矩阵,由于间断有限元局部性,可由各个单元质量矩阵组合而成
[mathbf{M} = egin{bmatrix}
M_{mathcal{T}_1} & & \
& ldots & \
& & M_{mathcal{T}_K}
end{bmatrix} quad
M_{mathcal{T}_k} = int_{mathcal{T}_k} egin{bmatrix}
varphi_{k1} varphi_{k1} & ldots & varphi_{k1} varphi_{kN} \
ldots & ldots & ldots \
varphi_{kN} varphi_{k1} & ldots & varphi_{kN} varphi_{kN}
end{bmatrix}
]
或者也可写为 (mathbf{M} = mathrm{diag} left ( M_{mathcal{T}_1}, ldots, M_{mathcal{T}_K}
ight ))。在第 (II) 项面积分中,由于包含三个基函数积分形式,因此 (mathbf{G}^1,mathbf{G}^2) 与传统刚度矩阵并不相同。与质量矩阵类似,(mathbf{G}^m = mathrm{diag} left ( G^m_{mathcal{T}_1}, ldots, G^m_{mathcal{T}_K}
ight ), min {1,2 }) 可写为对角矩阵块形式,其中每个单元内矩阵系数可写为
[G^m_{mathcal{T}_k} = sum_{l=1}^N u^m_{kl} int_{mathcal{T}_k} egin{bmatrix}
partial_{x^m} varphi_{k1} varphi_{kl} varphi_{k1} & ldots & partial_{x^m} varphi_{k1} varphi_{kl} varphi_{kN} \
ldots & ldots & ldots \
partial_{x^m} varphi_{kN} varphi_{kl} varphi_{k1} & ldots & partial_{x^m} varphi_{kN} varphi_{kl} varphi_{kN}
end{bmatrix}
]
在第 (III) 项面积分中,与前两项不同的是,由于面积分计算时边界通量可能采用其他单元内数值解,因此系数矩阵 (mathbf{S}) 不为对角形式。在文献 [1] 中,Frank 等将 (mathbf{S}^m, min {1,2 }) 写为对角块 (8a) 和非对角块 (8c) 部分,分别表示为
[left [ mathbf{S}^m
ight ]_{(k-1)N+i, (k-1)N+j} := sum_{E_{k n} in partial T_{k} cap mathcal{E}_{Omega}} v_{k n}^{m} u_{k}^m int_{E_{k n}} varphi_{k i} varphi_{k j} =
sum_{E_{k n} in partial T_{k} cap mathcal{E}_{Omega}} v_{k n}^{m} left[ mathbf{S}_{E_{kn}}
ight]
]
[left[mathbf{S}^{m}
ight]_{left(k^{-}-1
ight) N+i,left(k^{+}-1
ight) N+j} := v_{k^{-} n^{-}}^{m} u_{k^{+}} int_{E_{k^{-} n^{-}}} varphi_{k^{-} i} varphi_{k^{+} j}
]
上式中由于试验函数定义在 (k^-) 单元上,因此相邻单元基函数 (varphi_{k^{+} l}) 和 (varphi_{k^{+} j}) 在 (k^-) 单元边界 (E_{k^{-} n^{-}}) 上始终为 0,所以第二项表达式存在一定问题。但是由于相邻单元内相同编号的基函数 (varphi_{k^{-} j}) 和 (varphi_{k^{+} j}) 在边界 (E_{k^{-} n^{-}}) 上函数值分布不同,因此必须采用单元 (k^{+}) 的基函数进行表示。
在 Dirichlet 边界处,面积分计算需考虑边界条件 (C = C_D),由此包含右端项 (mathbf{K}_D) 等。
获得矩阵形式离散方程后,即可采用 Runge-Kutta 等方法进行计算,右端项表达式为
[mathrm{rhs} = mathbf{M}^{-1} left( mathbf{V} - mathbf{A} mathbf{C}^{(n)}
ight)
]
其中
[mathbf{A} = - mathbf{G}^1 - mathbf{G}^2 + mathbf{S}, quad mathbf{V} = mathbf{L} - mathbf{K}_D - mathbf{K}_N
]
2.1. 体积分与面积分主要区别
在离散后得到的控制方程中,面积分和体积分系数矩阵中基函数个数并不相同,其中体积分中为两个基函数与一个基函数导数相乘,而面积分为两个基函数相乘。存在这种区别的原因是,在体积分中,用基函数近似值 (u_h = sum_{j=1}^N u^m_{kl} varphi_{kl}) 来近似流速,而在面积分中,则直接采用 (u_h^m) 在边界积分节点函数值进行计算。因此面积分中省去了基函数 (varphi_{kl}) 项,仅包含 (varphi_{ki}) 与 (varphi_{kj}) 的积分计算。
3. 模型实现
3.1. 计算流程
在 FESTUNG 模型中建立求解器时,需要在文件夹内包含以下 4 个文件:
文件名 |
函数功能 |
configureProblem.m |
算例设置文件,包括网格宽度,计算步数,边界条件等 |
preprocessProblem.m |
前处理需要数据,包括计算网格,常系数矩阵等 |
initializeProblem.m |
初始化函数 |
主循环 |
计算过程 |
postprocessProblme.m |
后处理函数 |
其中主循环求解部分包括四个步骤:
函数名 |
说明 |
preprocessStep |
计算前处理 |
solveStep |
采用 Runge-Kutta 进行每步计算 |
postprocessStep |
每步计算后执行必要的数值处理 |
outputStep |
输出以及插值过程 |
在计算步 solveStep.m
中,调用了函数 iterateSubSteps
,在此函数中每一步进行了 (m) 次 Runge-Kutta 时间递进分步的计算,每步调用如下三个函数
函数名 |
说明 |
preprocessSubStep |
组装 (mathbf{G}, mathbf{R}, mathbf{K}_D, mathbf{K}_N, mathbf{L}) 等系数矩阵 |
solveSubStep |
计算右端项,求解线性方程组 |
postprocessSubStep |
判断 RK 迭代是否完成 |
在 preprocessSubStep
函数中,需要组装系数矩阵 (mathbf{G}^m, mathbf{R}, mathbf{K}_D, mathbf{K}_N, mathbf{L}) 等系数矩阵,这是由于在每步计算过程中需要更新 ( u^1, u^2, f) 等变量数值表达式,以及边界条件 (C_D, g_N) 等也可能随时间发生变化。
3.2. 通量计算
在对流方程计算中,面积分计算时采用迎风格式计算,因此在 (mathbf{S}^m) 组装时需要考虑边界处流速方向。在组装边界积分矩阵时,调用函数 assembleMatEdgePhiPhiValUpwind
。
首先考察面积分的化简,在 (mathbf{S}_{E_{kn}}) 中,其表达式为
[mathbf{S}_{E_{kn}}^m =
v_{k n}^{m} u^m_{kn} int_{E_{kn}} egin{bmatrix}
varphi_{k1} varphi_{k1} & ldots & varphi_{k1} varphi_{kN} \
ldots & ldots & ldots \
varphi_{kN} varphi_{k1} & ldots & varphi_{kN} varphi_{kN}
end{bmatrix}
]
对于面积分,首先将其投影至标准单元,随后转化为 (s in [0,1]) 范围进行计算
[int_{E_{k n}} varphi_{k i} varphi_{k j}
= frac{left|E_{k n}
ight|}{left|hat{E}_{n}
ight|} int_{hat{E}_{n}} hat{varphi}_{i}(hat{oldsymbol{x}}) hat{varphi}_{j}(hat{oldsymbol{x}}) mathrm{d} hat{oldsymbol{x}}
= left|E_{k n}
ight|
underbrace {int_{0}^{1} hat{varphi}_{i} circ hat{gamma}_{n}(s) hat{varphi}_{j} circ hat{gamma}_{n}(s) mathrm{d} s }_{=:left[ mathbf{ hat{S} }^{mathrm{diag}}
ight]_{i,j,n}}
]
其中 (hat{gamma}_{n}(s) : [0,1]
ightarrow hat{E}_{n}) 为标准单元边界投影,可将一维线单元的局部坐标转换为标准单元内边界节点坐标,表达式为
[hat{gamma}_{1}(s) :=left[egin{array}{c}{1-s} \ {s}end{array}
ight], qquad hat{gamma}_{2}(s) :=left[egin{array}{c}{0} \ {1-s}end{array}
ight], qquad hat{gamma}_{3}(s) :=left[egin{array}{l}{s} \ {0}end{array}
ight].
]
![](https://img2018.cnblogs.com/blog/651529/201906/651529-20190618134129328-1827350.png)
对于单位长度上面积分表达式,可将 ([ mathbf{ hat{S} }^{mathrm{diag}} ]_{i,j,n}) 提前进行计算,随后系数矩阵可表示为
[mathbf{S}_{E_{kn}}^m = v_{k n}^{m} u_{kn}^m left| {E}_{kn}
ight| [ mathbf{ hat{S} }^{mathrm{diag}} ]_{:,:,n}.
]
首先考察对角部分矩阵块
[mathbf{S}^{m, mathrm{diag}} =
sum_{n=1}^{3} left[egin{array}{ccc}{delta_{E_{1 n} in mathcal{E}_{Omega}}} & {} \ {} & {ddots} & {} \ {} & {} & {delta_{E_{K n} in mathcal{E}_{Omega}}}end{array}
ight] circ left[egin{array}{cccc}{v_{1}^{m}left|E_{1 n}
ight| u_{1 n}^m} & {} & {} \ {} & {ddots} & {} \ {} & {} & {} & {v_{K n}^{m} left|E_{K n}
ight| u_{K n}^m}end{array}
ight]
otimes [hat{mathbf{S}}^{mathrm{diag}} ]_{ :, :, n} \
= sum_{n=1}^{3} oldsymbol{delta}_E circ mathrm{diag} (v_k^m u_{kn}^m |E_{kn}| ) otimes [hat{mathbf{S}}^{mathrm{diag}} ]_{ :, :, n}
]
在上式中 (oldsymbol{delta}_E) 为 (K imes K) 大小的对角矩阵,其中每个元素代表单元对应面是否位于内部面 (delta_{E_{k n} in mathcal{E}_{Omega}}),(mathrm{diag} (v_k^m u_{kn}^m |E_{kn}| )) 则为每个单元上面积分时对应积分系数,最终 ([hat{mathbf{R}}^{mathrm{diag}} ]_{ :, :, l, n}) 为标准单元中基函数面积分大小。符号 (circ) 代表 Hadamard 乘积(矩阵元素点乘),(otimes) 为 Kronecker 算子。
为了考虑迎风通量,面积分时需要对系数 (v_k^m u_{kn}^m) 正负进行判断,当 (v_k^m u_{kn}^m > 0) 时采用原始系数矩阵,而当 (v_k^m u_{kn}^m le 0) 时则应将对应系数修改为 0,代表本单元数值解并不参与此单元面的计算。
此外,在面积分计算时必须采用数值积分方法进行计算。令 (R) 为积分节点总数,数值积分可进一步写为
[mathbf{S}^{m, mathrm{diag}} = sum_{n=1}^{3} sum_{r=1}^{R} oldsymbol{delta}_E circ mathrm{diag} (v_k^m u_{kn}^m(hat{q}_r) |E_{kn}| ) otimes [hat{mathbf{S}}^{mathrm{diag}} ]_{ :, :, n, r}
]
其中
[[hat{mathbf{S}}^{mathrm{diag}} ]_{ :, :, n, r} = omega_r egin{bmatrix}
varphi_{k1}(hat{q}_r) varphi_{k1}(hat{q}_r) & ldots & varphi_{k1}(hat{q}_r) varphi_{kN}(hat{q}_r) \
ldots & ldots & ldots \
varphi_{kN}(hat{q}_r) varphi_{k1}(hat{q}_r) & ldots & varphi_{kN}(hat{q}_r) varphi_{kN}(hat{q}_r)
end{bmatrix}
]
在非对角部分,同样可将面积分投影至标准长度线段中进行计算。需要注意的是,由于非对角部分表示相邻单元边界数值解在本单元边界上展开,因此积分计算时必须选取本地单元边界上相同位置的高斯节点进行计算。例如,当本地单元 (k^{-}) 边 (n^- = 1) 和相邻单元 (k^{+}) 边 (n^+ = 3) 相邻时,(n^{+}) 边界上的高斯节点局部坐标 (s^{+}) 与 (n^{-}) 边界上局部坐标是完全相反的 (s^{+} = 1 - s^{-})。为此,模型提出了一个投影算子 ( heta_{n^-, n^+}: hat{E}_{n^-}
ightarrow hat{E}_{n^+})(theta.m
),保证最终两侧边界计算时投影至相同高斯积分节点局部坐标大小相同,即二者有相同的坐标,保证 (varphi_{k^+, j}(s^{+}) = varphi_{k^-, j}(s^{-})),其中
[egin{matrix}
hat{oldsymbol{vartheta}}_{11} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{1-hat{x}^{1}} \ {1-hat{x}^{2}}end{array}
ight] &
hat{oldsymbol{vartheta}}_{12} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{0} \ {hat{x}^{2}}end{array}
ight] &
hat{oldsymbol{vartheta}}_{13} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{hat{x}^{1}} \ {0}end{array}
ight] \
hat{oldsymbol{vartheta}}_{21} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{1-hat{x}^{2}} \ {hat{x}^{2}}end{array}
ight] &
hat{oldsymbol{vartheta}}_{22} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{0} \ {1-hat{x}^{2}}end{array}
ight] &
hat{oldsymbol{vartheta}}_{23} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{hat{x}^{2}} \ {0}end{array}
ight] \
hat{oldsymbol{vartheta}}_{31} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{hat{x}^{1}} \ {1-hat{x}^{1}}end{array}
ight] &
hat{oldsymbol{vartheta}}_{32} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{0} \ {hat{x}^{1}}end{array}
ight] &
hat{oldsymbol{vartheta}}_{33} :left[egin{array}{c}{hat{x}^{1}} \ {hat{x}^{2}}end{array}
ight] mapstoleft[egin{array}{c}{1-hat{x}^{1}} \ {0}end{array}
ight] \
end{matrix}
]
而标准单元中面积分矩阵表达式可写为
[left[hat{mathbf{S}}^{ ext { offdiag }}
ight]_{i, j, n^{-}, n^{+}} :=int_{0}^{1} hat{varphi}_{i} circ hat{gamma}_{n^{-}}(s) hat{varphi}_{j} circ hat{oldsymbol{vartheta}}_{n^{-}n^{+}} circ hat{gamma}_{n^{-}}(s) mathrm{d} s
]
尽管 ( heta_{n^-, n^+}) 表达式较为复杂,但是可以看出,其作用就是根据 (k^{+}) 单元相邻面的编号将面局部坐标投影为相反顺序,如
[hat{oldsymbol{vartheta}}_{n^{-}1} circ hat{gamma}_{n^{-}}(s) = left[egin{array}{c}{s} \ {1-s}end{array}
ight], quad
hat{oldsymbol{vartheta}}_{n^{-}2} circ hat{gamma}_{n^{-}}(s) = left[egin{array}{c}{0} \ {s}end{array}
ight], quad
hat{oldsymbol{vartheta}}_{n^{-}3} circ hat{gamma}_{n^{-}}(s) = left[egin{array}{c}{1-s} \ {0}end{array}
ight]
]
![](https://img2018.cnblogs.com/blog/651529/201906/651529-20190618134108769-911030750.png)
可以看出,经过 (hat{oldsymbol{vartheta}}_{n^{-}n^{+}}) 变换后,局部坐标与原始标准单元边界投影是完全相反的,保证边界两侧基函数在相同高斯节点进行计算。
在组装全局矩阵系数时,同样需要判断单元边界是否相邻,因此引入 (K imes K) 大小的 (delta_E^{mathrm{offdiag}}) 矩阵,最终非对角项系数为
[mathbf{S}^{ ext { offdiag }} := sum_{n^{-}=1}^{3} sum_{n^{+}=1}^{3} egin{bmatrix}
0 & delta_{E_{1, n^{-}} = E_{2, n^{+}}} & cdots & cdots & delta_{E_{1, n^{-}} = E_{K, n^{+}}} \
delta_{E_{2, n^{-}} = E_{1, n^{+}}} & 0 & ddots & & vdots \
vdots & vdots & ddots & & vdots \
delta_{E_{K, n^{-}} = E_{K, n^{+}}} & ldots & ldots & delta_{E_{K, n^{-}} = E_{{K-1}, n^{+}}} & 0
end{bmatrix} \
circ egin{bmatrix}
v_{1 n^{-}}^m u_{1 n^{-}}^m | E_{1 n^{-}} | & ldots & v_{1 n^{-}}^m u_{1 n^{-}}^m | E_{1 n^{-}} | \
vdots & ddots & vdots \
v_{K n^{-}}^m u_{K n^{-}}^m | E_{K n^{-}} | & ldots & v_{K n^{-}}^m u_{K n^{-}}^m | E_{K n^{-}} |
end{bmatrix}
otimesleft[hat{mathbf{S}}^{ ext { offdiag }}
ight]_{:, :, n^{-}, n^{+} }
]
由于非对角项考虑的是相邻单元对本单元影响,因此当 (v_{kn^{-}}^m u_{kn^{-}}^m < 0) 时(边界为入流),对应系数不为 0,其他情况对应边界系数为 0。