非根据你的理解,我来把 MUGF 函数对应的数学公式用清晰的 LaTeX 格式展示出来:

📐 MUGF 函数的数学表达
完整形式
\\boxed{ \\begin{aligned} \\mathbf{GGT} = -\\Bigg\[ \& \\int_{\\Xi} \\begin{pmatrix} u \\ u\^2 \\ u v \\ u w \\ \\frac{1}{2}u(u^2+v^2+w\^2) \\end{pmatrix} \\left(a\^l_x H(u) + a\^r_x (1-H(u))\\right) g_0 , d\\Xi \\ * \& \\int_{\\Xi} \\begin{pmatrix} v \\ u v \\ v\^2 \\ v w \\ \\frac{1}{2}v(u^2+v^2+w\^2) \\end{pmatrix} a_y, g_0 , d\\Xi \\ * \& \\int_{\\Xi} \\begin{pmatrix} w \\ u w \\ v w \\ w\^2 \\ \\frac{1}{2}w(u^2+v^2+w\^2) \\end{pmatrix} a_z, g_0 , d\\Xi \\Bigg\] \\end{aligned} }

紧凑形式
GGT=−∫Ξu (aLH(u)+aR(1−H(u)))g0 ψ dΞ−∫Ξu (ay+az) g0 ψ dΞ \boxed{ \mathbf{GGT} = -\int_{\Xi} \mathbf{u}\,\left(a^L H(u) + a^R(1-H(u))\right)g_0\,\boldsymbol{\psi}\,d\Xi -\int_{\Xi} \mathbf{u}\,(a_y+a_z)\,g_0\,\boldsymbol{\psi}\,d\Xi } GGT=−∫Ξu(aLH(u)+aR(1−H(u)))g0ψdΞ−∫Ξu(ay+az)g0ψdΞ
🔑 符号说明
| 符号 | 含义 | 对应代码 |
|---|---|---|
| GGT\mathbf{GGT}GGT | 宏观通量向量 (5个守恒量) | GGT |
| u=(u,v,w)\mathbf{u} = (u,v,w)u=(u,v,w) | 粒子速度 | UFM0, UFN0, VFF0, WFF0 |
| H(u)H(u)H(u) | Heaviside阶跃函数 (区分正负速度) | UFM0(u<0), UFN0(u>0) |
| axl,axra^l_x, a^r_xaxl,axr | 界面左/右侧分布函数梯度系数 | ML0, MR0 |
| ay,aza_y, a_zay,az | 切向梯度系数 | MUD0, MOI0 |
| g0g_0g0 | 平衡态分布函数 | 隐含在 M 系数中 |
| ψ\boldsymbol{\psi}ψ | 矩向量 $(1,u,v,w,\frac{1}{2} | \mathbf{u} |
| dΞd\XidΞ | 速度空间积分元 | 预计算的 UF/VF/WF 矩 |
🔗 与代码的对应关系
GGT[0] → 质量通量 ∫ u·f dΞ
GGT[1] → X动量通量 ∫ u²·f dΞ
GGT[2] → Y动量通量 ∫ uv·f dΞ
GGT[3] → Z动量通量 ∫ uw·f dΞ
GGT[4] → 能量通量 ∫ ½u|u|²·f dΞ
TUVW(..., I1, I2, I3) → ∫ u^I1 · v^I2 · w^I3 · f dΞ
TUV_U2_V2_W2(...) → ∫ (u²+v²+w²) · f dΞ (能量项)
⚠️ 物理意义
这个公式计算的是 UGKS 界面通量的时间导数项,它体现了:
- 迎风特性 :H(u)H(u)H(u) 区分粒子是从左侧还是右侧来到界面
- 多维耦合 :ay,aza_y, a_zay,az 项考虑了切向梯度对法向通量的影响
- 全流域兼容 :通过 g0g_0g0 和梯度系数的组合,自动在连续流和稀薄流之间切换
这正是 UGKS 区别于传统格式的核心所在!🎯
一、MUGF函数的作用:计算界面平衡态气体分布函数的时间导数项 ( A )
在UGKS中,界面处的平衡态分布函数(麦克斯韦分布)被展开为:
g(x,t,\\mathbf{u}) = g_0 \\left\[ 1 + \\mathbf{a} \\cdot \\mathbf{x} + A t \\right\],
其中:
- ( \mathbf{a} = (a_x, a_y, a_z) ): 空间导数系数;
- ( A ): 时间导数系数(即 (\partial g/\partial t) 在 ( x=0,t=0 ) 的值);
- ( g_0 ): 局部平衡麦克斯韦分布。
根据文献 Xu & Huang (2010, Eq. (19)) :
M_{0,ab} A_b = \\left( \\frac{\\partial q}{\\partial t}, \\frac{\\partial (qU)}{\\partial t}, \\frac{\\partial E}{\\partial t} \\right)\^T = -\\frac{1}{q_0} \\int \\mathbf{u} , \[a_l, H(u) + a_r, (1-H(u))\],g_0 , \\boldsymbol{\\psi}, d\\Xi,
这就是所谓的兼容条件公式(Compatibility Condition),它确保碰撞项对守恒量矩的积分为零。
所以该方程实际上告诉我们:
( A ) 的值通过计算麦克斯韦分布在速度空间对各分量积分的通量项获得。
而MUGF函数就是这个右端项的离散实现。
二、MUGF的输入与输出物理意义
输入:
ML0= 左侧的空间导数 (对应 (a^l_x))MR0= 右侧的空间导数 (对应 (a^r_x))MUD0= (a_y): y方向空间导数MOI0= (a_z): z方向空间导数UFF0, UFM0, UFN0, VFF0, WFF0: 分别是预计算的速度矩阵,即:U\[I\], V\[I\], W\[I\] = \\int u\^I e\^{-\\lambda u\^2} du
对应不同方向上的速度矩。
输出:
GGT[0:4]: 每一个分量对应守恒变量的时间导数:GGT = (\\partial_t \\rho, \\partial_t (\\rho U), \\partial_t (\\rho V), \\partial_t (\\rho W), \\partial_t E)
三、MUGF的精确数学形式
代码为:
python
GGT[0] = -(TUVW(ML0, UFM0, VFF0, WFF0, 1, 0, 0)
+ TUVW(MR0, UFN0, VFF0, WFF0, 1, 0, 0)
+ TUVW(MUD0, UFF0, VFF0, WFF0, 0, 1, 0)
+ TUVW(MOI0, UFF0, VFF0, WFF0, 0, 0, 1))
因此第 0 个分量对应密度的时间导数:
(\\partial_t \\rho) = -\\bigg\[ \\int u, (a\^l_x H(u) + a\^r_x (1-H(u))), g_0 , d\\Xi + \\int v, a_y, g_0 , d\\Xi + \\int w, a_z, g_0 , d\\Xi \\bigg\],
类似地,第二、第三、第四个分量分别对应动量、能量的时间导数:
(1) 密度分量:( GGT_0 )
GGT_0 = -\\left(\\langle u,a_x\\rangle + \\langle v,a_y\\rangle + \\langle w,a_z\\rangle \\right),
在离散积分实现中:
\\langle u , a_x \\rangle = TUVW(a_x, U, V, W; 1,0,0), ;;\\langle v,a_y\\rangle = TUVW(a_y, U,V,W; 0,1,0), \\text{等等}.
(2) x动量分量:( GGT_1 )
GGT_1 = -\\left(\\langle u\^2,a_x\\rangle + \\langle u v,a_y\\rangle + \\langle u w,a_z\\rangle\\right),
离散形式:
GGT_1 = -\\Big\[ TUVW(a_x, UFM0,VFF0,WFF0; 2,0,0) * TUVW(a_y, UFF0,VFF0,WFF0; 1,1,0) * TUVW(a_z, UFF0,VFF0,WFF0; 1,0,1) \\Big\].
(3) y动量分量:( GGT_2 )
GGT_2 = -\\left(\\langle u v,a_x\\rangle + \\langle v\^2,a_y\\rangle + \\langle v w,a_z\\rangle\\right),
离散形式:
GGT_2 = -\[ TUVW(a_x,UFM0,VFF0,WFF0;1,1,0) * TUVW(a_y,UFF0,VFF0,WFF0;0,2,0) * TUVW(a_z,UFF0,VFF0,WFF0;0,1,1) \].
(4) z动量分量:( GGT_3 )
GGT_3 = -\\left(\\langle u w,a_x\\rangle + \\langle v w,a_y\\rangle + \\langle w\^2,a_z\\rangle\\right),
离散形式:
GGT_3 = -\[ TUVW(a_x,UFM0,VFF0,WFF0;1,0,1) * TUVW(a_y,UFF0,VFF0,WFF0;0,1,1) * TUVW(a_z,UFF0,VFF0,WFF0;0,0,2) \].
(5) 能量分量:( GGT_4 )
能量变化项包含额外的二次速度项:
GGT_4 = -\\frac{1}{2}\\left\[ \\langle u(u^2+v^2+w\^2),a_x\\rangle * \\langle v(u^2+v^2+w\^2),a_y\\rangle * \\langle w(u^2+v^2+w\^2),a_z\\rangle \\right\].
对应代码中的:
GGT\[4\] = -(TUV_U2_V2_W2(a_x,U,V,W;1,0,0)+\\dots)
四、TUVW函数背后的离散速度积分公式
在连续形式下:
TUVW(M,U,V,W,I_1,I_2,I_3) \\int (M_0 + M_1 u + M_2 v + M_3 w + \\tfrac{1}{2}M_4(u^2+v^2+w\^2)) , u^{I_1}v^{I_2}w\^{I_3} , g_0(\\mathbf{u}), d\\mathbf{u}.
代码中的实现:
python
UVW = M[0]*U[I1]*V[I2]*W[I3]
+ M[1]*U[I1+1]*V[I2]*W[I3]
+ M[2]*U[I1]*V[I2+1]*W[I3]
+ M[3]*U[I1]*V[I2]*W[I3+1]
+ 0.5*M[4]*(U[I1+2]*V[I2]*W[I3] + U[I1]*V[I2+2]*W[I3] + U[I1]*V[I2]*W[I3+2])
这正是上面那一串公式的离散化版本。
五、总结
因此函数 MUGF 在数学上表示:
\\boxed{ \\begin{aligned} GGT \&= -\\left\[ \\int \\begin{pmatrix} u \\ u\^2 \\ u v \\ u w \\ \\tfrac{1}{2}u(u^2+v^2+w\^2) \\end{pmatrix} (a\^l_x H(u) + a\^r_x (1-H(u))) g_0 , d\\Xi * \\int \\begin{pmatrix} v \\ u v \\ v\^2 \\ v w \\ \\tfrac{1}{2}v(u^2+v^2+w\^2) \\end{pmatrix} a_y, g_0 , d\\Xi * \\int \\begin{pmatrix} w \\ u w \\ v w \\ w\^2 \\ \\tfrac{1}{2}w(u^2+v^2+w\^2) \\end{pmatrix} a_z, g_0 , d\\Xi \\right\]. \\end{aligned} }
或者更紧凑地写:
\\boxed{ GGT = -\\int \\mathbf{u},(a\^L H(u) + a\^R(1-H(u)))g_0,\\boldsymbol{\\psi},d\\Xi -\\int \\mathbf{u},(a_y+a_z),g_0,\\boldsymbol{\\psi},d\\Xi }
这就是 UGKS 中用于确定界面时间导数项 A的源项(兼容条件右侧)。
✅ 总结一句话:
MUGF函数在数学上实现的是用速度空间矩积分计算平衡分布函数时间导数系数 ( A ),即 Eq.(19) 的右侧离散形式。它依据守恒律 (\partial_t W + \nabla\cdot F = 0),通过对麦克斯韦分布与空间斜率项的速度积分,以五个守恒变量形成时间演化向量 ( GGT = (\partial_t \rho, \partial_t (\rho U), \partial_t (\rho V), \partial_t (\rho W), \partial_t E) )。
fMUVSF
这个函数 fMUVSF 的目的是计算 UGKS 中界面处的平衡态通量 。
它计算的具体对象是宏观通量向量中的某一项(取决于传入的 I1, I2, I3),对应于守恒方程右端项的积分。
1. 具体的数学公式
该函数试图计算的表达式是平衡态分布函数 ggg 对时间的积分通量。
设平衡态分布函数 ggg 在界面处的一阶展开为:
g=g0+aˉ⋅x+bˉ⋅t g = g_0 + \bar{a} \cdot \mathbf{x} + \bar{b} \cdot t g=g0+aˉ⋅x+bˉ⋅t
其中:
- g0g_0g0 是界面中心的平衡态(对应
DN0)。 - aˉ\bar{a}aˉ 是空间导数项系数(对应
ML0, MR0, MUD0, MOI0)。 - bˉ\bar{b}bˉ 是时间导数项系数(对应
MT0)。
在 UGKS 中,通量项的形式通常为:
Flux≈C1⟨ug0⟩+C2⟨u(aˉ⋅x)⟩+C3⟨u(bˉt)⟩ \text{Flux} \approx C_1 \langle u g_0 \rangle + C_2 \langle u (\bar{a} \cdot \mathbf{x}) \rangle + C_3 \langle u (\bar{b} t) \rangle Flux≈C1⟨ug0⟩+C2⟨u(aˉ⋅x)⟩+C3⟨u(bˉt)⟩
fMUVSF函数计算的正是该公式的大括号部分 ⟨... ⟩\langle \dots \rangle⟨...⟩ 的加权组合。
具体的数学表达式为:
fMUVSF=R1⋅ρ0⟨uI1vI2wI3⟩⏟F[0]+R2⋅ρ0(⟨u⋅aL⟩L+⟨u⋅aR⟩R+⟨u⋅aT⟩)⏟F[1]+R3⋅ρ0⟨bˉ⟩⏟F[2] \text{fMUVSF} = R_1 \cdot \underbrace{\rho_0 \langle u^{I_1} v^{I_2} w^{I_3} \rangle}{\text{F[0]}} + R_2 \cdot \underbrace{\rho_0 \left( \langle u \cdot a_L \rangle{L} + \langle u \cdot a_R \rangle_{R} + \langle u \cdot a_T \rangle \right)}{\text{F[1]}} + R_3 \cdot \underbrace{\rho_0 \langle \bar{b} \rangle}{\text{F[2]}} fMUVSF=R1⋅F[0] ρ0⟨uI1vI2wI3⟩+R2⋅F[1] ρ0(⟨u⋅aL⟩L+⟨u⋅aR⟩R+⟨u⋅aT⟩)+R3⋅F[2] ρ0⟨bˉ⟩
其中: - R1,R2,R3R_1, R_2, R_3R1,R2,R3 是输入参数
RT向量的分量,代表时间积分系数(如 1,Δt,...1, \Delta t, \dots1,Δt,...)。 - I1,I2,I3I_1, I_2, I_3I1,I2,I3 是矩的阶数(例如质量方程对应 I1=1I_1=1I1=1,动量方程对应 I1=2I_1=2I1=2 等)。
2. 代码与公式的逐项对应
我们将代码拆解,对应到上述公式:
第一步:常数项 F[0]
代码:
python
F[0] = DN0 * UFF0[I1] * VFF0[I2] * WFF0[I3]
公式对应 :
F0=ρ0⟨uI1vI2wI3⟩ F_0 = \rho_0 \langle u^{I_1} v^{I_2} w^{I_3} \rangle F0=ρ0⟨uI1vI2wI3⟩
这是平衡态 g0g_0g0 的矩积分。DN0 对应密度 ρ0\rho_0ρ0,UFF0 对应全速度空间的积分系数 ⟨un⟩\langle u^n \rangle⟨un⟩。
第二步:空间导数项 F[1]
代码:
python
F[1] = (TUVW(ML0 ,UFM0, ...) + TUVW(MR0 ,UFN0, ...) + TUVW(MUD0, ...) + TUVW(MOI0, ...)) * DN0
公式对应 :
F1=ρ0∫u⋅(aˉ⋅x)⋅ψ dΞ F_1 = \rho_0 \int u \cdot (\bar{a} \cdot \mathbf{x}) \cdot \psi \, d\Xi F1=ρ0∫u⋅(aˉ⋅x)⋅ψdΞ
这一项计算的是非均匀性修正。代码将其分为了四个部分:
TUVW(ML0, UFM0, ...):左行分子(u<0u<0u<0)来自左侧的空间导数贡献。使用左半区间积分系数UFM0。TUVW(MR0, UFN0, ...):右行分子(u>0u>0u>0)来自右侧的空间导数贡献。使用右半区间积分系数UFN0。TUVW(MUD0, ...):切向(y方向)的空间导数贡献。TUVW(MOI0, ...):切向(z方向)的空间导数贡献。
注意 :TUVW函数内部的I1+1实现了乘以速度 uuu 的操作(即通量定义中的 u⋅fu \cdot fu⋅f)。
第三步:时间导数项 F[2]
代码:
python
F[2] = DN0 * TUVW(MT0, UFF0, VFF0, WFF0, I1, I2, I3)
公式对应 :
F2=ρ0⟨bˉ⟩ F_2 = \rho_0 \langle \bar{b} \rangle F2=ρ0⟨bˉ⟩
这是平衡态随时间变化项的贡献。MT0 是通过相容性条件求解出的时间导数系数。
第四步:加权组合
代码:
python
for I in range(3):
fMUVSF = fMUVSF + RT(I) * F(I)
公式对应 :
Result=R0F0+R1F1+R2F2 \text{Result} = R_0 F_0 + R_1 F_1 + R_2 F_2 Result=R0F0+R1F1+R2F2
这里将三部分矩积分结果乘以时间积分权重 RT 并求和,得到最终的通量分量。
总结
fMUVSF 函数计算的是单一守恒量分量(如质量、X动量等)的平衡态通量 。
它利用解析积分系数,将平衡态本身 、空间非均匀性 、时间变化率 三部分贡献加权求和,完整实现了 UGKS 界面通量表达式中的平衡态部分计算。
这是一个非常敏锐的问题!你发现了一个关键的数学变换细节。
简单来说:
- g0g_0g0 没有消失 ,它就是公式里的积分项,只不过它的具体形式写出来就是指数函数,积分结果变成了代码里的
UF系数。 - ρ0\rho_0ρ0 来自代码中的
DN0,它是界面处的宏观密度。
下面详细拆解这个变换过程:
1. g0g_0g0 去哪了?
g0g_0g0 是平衡态分布函数,它包含了密度、速度和温度信息。
在数学上,Maxwell 平衡态分布函数 g0g_0g0 的定义是:
g0=ρ0(λπ)K+32exp(−λ[(u−U)2+(v−V)2+(w−W)2]) g_0 = \rho_0 \left( \frac{\lambda}{\pi} \right)^{\frac{K+3}{2}} \exp \left( -\lambda \left[ (u-U)^2 + (v-V)^2 + (w-W)^2 \right] \right) g0=ρ0(πλ)2K+3exp(−λ[(u−U)2+(v−V)2+(w−W)2])
当我们计算通量时,我们需要计算它在速度空间的矩积分(也就是你问的积分部分):
积分项=∫uI1vI2wI3g0 du dv dw \text{积分项} = \int u^{I_1} v^{I_2} w^{I_3} g_0 \, du \, dv \, dw 积分项=∫uI1vI2wI3g0dudvdw
把 g0g_0g0 代进去 :
=ρ0∫uI1vI2wI3×[指数项] du dv dw = \rho_0 \int u^{I_1} v^{I_2} w^{I_3} \times \left[ \text{指数项} \right] \, du \, dv \, dw =ρ0∫uI1vI2wI3×[指数项]dudvdw
你会发现,积分符号里的内容正是代码中 COEF_INFITE 等函数算出来的东西!
UFF0[I1]这个变量,存储的就是积分 ∫uI1×[指数项] du\int u^{I_1} \times [\text{指数项}] \, du∫uI1×[指数项]du 的结果。- 所以,代码里的
UFF0[I1] * VFF0[I2] * WFF0[I3]这一项,实际上就是完成了对 g0g_0g0 的积分。
结论 :g0g_0g0 没有丢,它被"积掉"了,变成了代码里的积分系数UF。
2. ρ0\rho_0ρ0 是哪来的?
ρ0\rho_0ρ0 来自代码变量 DN0。
在 UGKS 的界面重构中,我们需要知道界面处的宏观状态(密度、速度、温度)。这些是通过黎曼求解器或重构得到的界面中心值。
-
在
fMUVSF函数的参数列表里:pythondef fMUVF(DN0, RT, ML0, ...): -
这里的
DN0就是界面处的密度 ρ0\rho_0ρ0(或者包含归一化系数的密度值)。
3. 完整公式还原
让我们把代码和公式完全对应起来:
代码行:
python
F[0] = DN0 * UFF0[I1] * VFF0[I2] * WFF0[I3]
数学含义拆解:
DN0→\rightarrow→ 对应 ρ0\rho_0ρ0 (界面密度)。UFF0[I1]→\rightarrow→ 对应 ∫uI1...du\int u^{I_1} \dots du∫uI1...du (已经包含了 g0g_0g0 里的指数部分积分)。VFF0[I2]→\rightarrow→ 对应 ∫vI2...dv\int v^{I_2} \dots dv∫vI2...dv。WFF0[I3]→\rightarrow→ 对应 ∫wI3...dw\int w^{I_3} \dots dw∫wI3...dw。
合起来 :
F[0]=ρ0⏟DN0×⟨uI1⟩⟨vI2⟩⟨wI3⟩⏟积分系数 F[0] = \underbrace{\rho_0}{\text{DN0}} \times \underbrace{\langle u^{I_1} \rangle \langle v^{I_2} \rangle \langle w^{I_3} \rangle}{\text{积分系数}} F[0]=DN0 ρ0×积分系数 ⟨uI1⟩⟨vI2⟩⟨wI3⟩
这正是平衡态 g0g_0g0 产生的通量项。
总结
- g0g_0g0 是被积函数的一部分,它通过解析积分变成了代码里的
UF...系数。 - ρ0\rho_0ρ0 是 g0g_0g0 的系数,直接作为参数
DN0传进来了,乘在最前面。
看不懂是非常正常的,因为这段代码省略了最关键的数学推导步骤:归一化 。
代码里的UF并不是直接等于物理上的积分值,而是归一化后的积分值 (也就是假设密度 ρ=1\rho=1ρ=1 时的积分结果)。
让我们把"数学公式"和"代码逻辑"一一对应起来,你就明白了。
1. 数学背景:积分算的到底是什么?
我们要算的积分是全速度空间的矩:
⟨un⟩=∫−∞+∞ung0 du \langle u^n \rangle = \int_{-\infty}^{+\infty} u^n g_0 \, du ⟨un⟩=∫−∞+∞ung0du
其中 g0g_0g0 是平衡态分布函数(Maxwell分布):
g0=ρ(λπ)1/2e−λ(u−U)2 g_0 = \rho \left(\frac{\lambda}{\pi}\right)^{1/2} e^{-\lambda (u-U)^2} g0=ρ(πλ)1/2e−λ(u−U)2
- ρ\rhoρ:密度
- UUU:宏观平均速度
- λ\lambdaλ:与温度有关的量(代码中的
EIGG)
2. 为什么代码里 UF[0] = 1.0?
让我们手动算一下 n=0n=0n=0 的情况(即概率积分):
⟨u0⟩=∫−∞+∞1⋅g0 du=ρ⋅∫−∞+∞(λπ)1/2e−λ(u−U)2 du⏟这一坨等于 1 \langle u^0 \rangle = \int_{-\infty}^{+\infty} 1 \cdot g_0 \, du = \rho \cdot \underbrace{\int_{-\infty}^{+\infty} \left(\frac{\lambda}{\pi}\right)^{1/2} e^{-\lambda (u-U)^2} \, du}_{\text{这一坨等于 1}} ⟨u0⟩=∫−∞+∞1⋅g0du=ρ⋅这一坨等于 1 ∫−∞+∞(πλ)1/2e−λ(u−U)2du
高斯积分的性质告诉我们,概率密度函数的积分等于 1。
所以,真实的积分结果是 ρ\rhoρ(密度)。
但在代码 COEF_INFITE 中,我们故意不乘 ρ\rhoρ ,我们先算归一化的系数。
所以代码写的是:
python
UF[0] = 1.0 # 对应数学上的 (积分结果 / ρ)
3. 为什么代码里 UF[1] = U?
再算一下 n=1n=1n=1 的情况(一阶矩):
⟨u1⟩=∫−∞+∞u⋅g0 du \langle u^1 \rangle = \int_{-\infty}^{+\infty} u \cdot g_0 \, du ⟨u1⟩=∫−∞+∞u⋅g0du
根据统计物理定义,速度的一阶矩就是平均速度 UUU。
真实积分结果是 ρU\rho UρU。
同样,代码只保留归一化部分:
python
UF[1] = U # 对应数学上的 (积分结果 / ρ)
4. 递推公式是怎么来的?(核心难点)
对于 n≥2n \ge 2n≥2,直接积分很麻烦,数学上有一个著名的递推关系。
数学推导 :
利用分部积分法,对于归一化的高斯函数 f(u)=λπe−λ(u−U)2f(u) = \sqrt{\frac{\lambda}{\pi}} e^{-\lambda(u-U)^2}f(u)=πλ e−λ(u−U)2,其矩 Mn=∫unf(u)duM_n = \int u^n f(u) duMn=∫unf(u)du 满足如下关系:
Mn=U⋅Mn−1+n−12λMn−2 M_n = U \cdot M_{n-1} + \frac{n-1}{2\lambda} M_{n-2} Mn=U⋅Mn−1+2λn−1Mn−2
代码对应:
python
# I 对应 n
# EIGG 对应 λ
# UF[I] 对应 M_n
# UF[I-1] 对应 M_{n-1}
# UF[I-2] 对应 M_{n-2}
UF[I] = U * UF[I-1] + 0.5 * (I-1) * UF[I-2] / EIGG
这一行代码就是在算这个递推公式!
U * UF[I-1]:代表平均速度对高阶矩的贡献。0.5 * (I-1) * UF[I-2] / EIGG:代表热运动(温度/方差)对高阶矩的贡献。
5. 总结:这一步算出的 UF 是什么?
UF 向量存储的是"单位密度下的积分系数"。
- 数学表达式 :
UF[n]=1ρ∫ung0 du \text{UF}[n] = \frac{1}{\rho} \int u^n g_0 \, du UF[n]=ρ1∫ung0du - 物理意义 :
UF[0]= 1 (归一化质量)UF[1]= UUU (平均速度)UF[2]= U2+12λU^2 + \frac{1}{2\lambda}U2+2λ1 (速度平方平均 = 动能)- ...
6. 最终怎么用?
回到上一问的公式:
python
F[0] = DN0 * UFF0[I1] * VFF0[I2] * WFF0[I3]
这里 DN0 就是 ρ\rhoρ。
代码逻辑是:
通量=ρ⏟DN0×UF[n]⏟积分系数 \text{通量} = \underbrace{\rho}{\text{DN0}} \times \underbrace{\text{UF}[n]}{\text{积分系数}} 通量=DN0 ρ×积分系数 UF[n]
这样设计是为了计算方便:先把复杂的指数积分算成系数 UF,最后要用的时候,只需要乘以密度 DN0 就能得到真实的物理通量了。
CPDTT
这是一个非常好的问题。之所以有 5 个分量,是因为 UGKS 的通量公式比传统的 CFD 复杂得多。它不仅包含平衡态项,还包含非平衡态(空间导数项)和时间导数项。
这 5 个系数分别对应 UGKS 积分通量公式中的 5 种不同类型的时间积分因子。
1. 为什么要算 5 个分量?
UGKS 的界面通量公式来源于对气体分布函数 fff 的演化方程积分。经过推导,最终的通量 FFF 由三部分组成:
F≈Fg0⏟平衡态项+Fspatial⏟空间导数项+Ftemporal⏟时间导数项 F \approx \underbrace{F_{g_0}}{\text{平衡态项}} + \underbrace{F{\text{spatial}}}{\text{空间导数项}} + \underbrace{F{\text{temporal}}}_{\text{时间导数项}} F≈平衡态项 Fg0+空间导数项 Fspatial+时间导数项 Ftemporal
在时间步 [0,Δt][0, \Delta t][0,Δt] 内积分时,不同的项前面带着不同的时间函数系数:
- 有的项前面是常数 111。
- 有的项前面是 e−t/τe^{-t/\tau}e−t/τ(碰撞松弛项)。
- 有的项前面是 ttt(线性增长项)。
- 有的项前面是 t⋅e−t/τt \cdot e^{-t/\tau}t⋅e−t/τ(混合项)。
这 5 个分量就是为了解析计算这些不同的时间积分而预先算好的系数。
2. 具体的公式形式
假设时间积分变量为 ttt,积分区间为 [0,Δt][0, \Delta t][0,Δt]。我们要算的是以下 5 种积分函数的解析解:
R[0]:主系数
- 积分公式 :
∫0Δt(1−e−t/τ) dt \int_{0}^{\Delta t} (1 - e^{-t/\tau}) \, dt ∫0Δt(1−e−t/τ)dt - 代码对应 :
DT - TAU * (1.0 - ET) - 物理含义 :
这是平衡态通量 的主要部分。公式里的 111 代表自由分子流极限,e−t/τe^{-t/\tau}e−t/τ 代表向平衡态的过渡。这个系数连接了连续流和自由分子流。
R[1]:非平衡空间导数系数
- 积分公式 :
∫0Δtt⋅e−t/τ dt \int_{0}^{\Delta t} t \cdot e^{-t/\tau} \, dt ∫0Δtt⋅e−t/τdt - 代码对应 :
(-DT + 2.0 * TAU * (1.0 - ET) - DT * ET) * TAU - 物理含义 :
这一项乘以空间导数项 (代码中的ML0,MR0等)。它表示气体从初始的非平衡状态向平衡状态松弛过程中,空间不均匀性对通量的贡献。
R[2]:自由输运系数
- 积分公式 :
∫0Δtt dt \int_{0}^{\Delta t} t \, dt ∫0Δttdt - 代码对应 :
0.5 * DT * DT(注:代码中后面减去的项是为了统一形式,核心是 0.5Δt20.5 \Delta t^20.5Δt2) - 物理含义 :
这是纯自由分子流 项。当碰撞时间 τ→∞\tau \to \inftyτ→∞ 或极稀薄时,气体分子不发生碰撞,直接飞过界面。这一项系数乘以初始分布,得到自由飞行的通量。
R[3]:碰撞松弛系数
- 积分公式 :
∫0Δte−t/τ dt \int_{0}^{\Delta t} e^{-t/\tau} \, dt ∫0Δte−t/τdt - 代码对应 :
(1.0 - ET) * TAU - 物理含义 :
这是纯松弛项。它描述了初始的非平衡分布如何在碰撞作用下指数衰减。
R[4]:混合时间系数
- 积分公式 :
∫0Δt(t−te−t/τ) dt \int_{0}^{\Delta t} (t - t e^{-t/\tau}) \, dt ∫0Δt(t−te−t/τ)dt
(注:代码的具体形式可能对应于时间导数项的某种组合) - 代码对应 :
(DT * ET - TAU * (1.0 - ET)) * TAU - 物理含义 :
这一项通常乘以时间导数项 (代码中的MT0)。用于处理流场随时间快速变化的情况(非定常流)。
3. 总结:怎么用这 5 个分量?
在实际计算通量时(可能在 fMUVSF 或更底层的函数中),代码会将物理量的空间导数、时间导数乘以对应的 R 系数,最后加起来:
总通量=A⋅R[0]+B⋅R[1]+C⋅R[2]+D⋅R[3]+E⋅R[4] \text{总通量} = A \cdot R[0] + B \cdot R[1] + C \cdot R[2] + D \cdot R[3] + E \cdot R[4] 总通量=A⋅R[0]+B⋅R[1]+C⋅R[2]+D⋅R[3]+E⋅R[4]
- R[0], R[3] →\to→ 处理 g0g_0g0 (平衡态)
- R[1] →\to→ 处理 a⋅xa \cdot xa⋅x (空间梯度)
- R[2], R[4] →\to→ 处理 b⋅tb \cdot tb⋅t (时间变化率)
简单记忆法: - R[0] 是基础通量。
- R[1] 是修正空间不均匀度的。
- R[2] 是修正纯自由飞行的。
- R[3], R[4] 是修正随时间变化的。
erfc erf 误差函数
这是一个非常基础且重要的数学问题。如果你没听过这两个函数,不用担心,它们本质上就是高斯积分 (也就是正态分布曲线下的面积)。
在气体动力学和 UGKS 中,它们是连接"微观速度"和"宏观物理量"的桥梁。
1. 它们是什么?公式是什么?
它们全称是 Error Function(误差函数)。
(1) 误差函数 erf(x)
定义公式 :
erf(x)=2π∫0xe−t2 dt \text{erf}(x) = \frac{2}{\sqrt{\pi}} \int_{0}^{x} e^{-t^2} \, dt erf(x)=π 2∫0xe−t2dt
- 直观理解 :它是正态分布曲线(钟形曲线)从中心开始,到 xxx 处围成的"面积"。
- 数值范围 :−1-1−1 到 111。
- 当 x→+∞x \to +\inftyx→+∞ 时,erf(x)=1\text{erf}(x) = 1erf(x)=1。
(2) 互补误差函数 erfc(x)
定义公式 :
erfc(x)=1−erf(x)=2π∫x∞e−t2 dt \text{erfc}(x) = 1 - \text{erf}(x) = \frac{2}{\sqrt{\pi}} \int_{x}^{\infty} e^{-t^2} \, dt erfc(x)=1−erf(x)=π 2∫x∞e−t2dt
- 直观理解 :它是正态分布曲线的"尾巴"部分的面积。从 xxx 一直积到无穷大。
- 数值范围 :000 到 222。
- 当 x→+∞x \to +\inftyx→+∞ 时,erfc(x)=0\text{erfc}(x) = 0erfc(x)=0(尾巴面积趋近于0)。
2. 为什么要算这个?有什么用?
在 UGKS(气体动理学格式)中,我们假设气体分子的速度分布服从 Maxwell 分布(高斯分布) 。
当我们计算通过界面的通量时,我们需要算类似这样的积分:
通量=∫−∞+∞u⋅e−u2 du \text{通量} = \int_{-\infty}^{+\infty} u \cdot e^{-u^2} \, du 通量=∫−∞+∞u⋅e−u2du
或者只算分子向右飞的通量:
右飞通量=∫0+∞u⋅e−u2 du \text{右飞通量} = \int_{0}^{+\infty} u \cdot e^{-u^2} \, du 右飞通量=∫0+∞u⋅e−u2du
这就是 erf 和 erfc 出场的时候!
- 代码中的
UF[0]:
你之前看到的代码UF[0] = 0.5 * DERFC(...),其实就是在算半个区间内的概率积分。- 如果我们想知道速度 u<Uu < Uu<U 的分子有多少,我们就需要积分 (−∞,U)(-\infty, U)(−∞,U) 区间的 Maxwell 分布。
- 这个积分没有简单的加减乘除公式,唯一的解析解就是误差函数 erf/erfc 。
总结它的作用:
- 代替复杂的数值积分 :
如果没有这两个函数,你就必须在每个网格点上用很多个高斯点去数值积分 e−u2e^{-u^2}e−u2,计算量巨大且不准。
有了erfc,我们可以直接写出精确的解析表达式,一步算出积分结果。 - 计算通量系数 :
在 UGKS 中,宏观通量(质量、动量、能量)是由微观分布函数积分得到的。- 质量通量 →\rightarrow→ 需要 ⟨u⟩\langle u \rangle⟨u⟩ →\rightarrow→ 涉及 u⋅e−u2u \cdot e^{-u^2}u⋅e−u2 积分 →\rightarrow→ 结果含
erf。 - 动量通量 →\rightarrow→ 需要 ⟨u2⟩\langle u^2 \rangle⟨u2⟩ →\rightarrow→ 涉及 u2⋅e−u2u^2 \cdot e^{-u^2}u2⋅e−u2 积分 →\rightarrow→ 结果含
erf。
- 质量通量 →\rightarrow→ 需要 ⟨u⟩\langle u \rangle⟨u⟩ →\rightarrow→ 涉及 u⋅e−u2u \cdot e^{-u^2}u⋅e−u2 积分 →\rightarrow→ 结果含
3. 代码里的 DERFC 在干嘛?
代码里写的那个长长的 DERFC 函数,就是一个计算器 。
因为计算机 CPU 本身通常没有直接算 erfc 的硬件指令(不像加减乘除),所以需要用数学级数(泰勒展开或者连分式展开)把它算出来。
- 当 xxx 很小时,用多项式加加减减算(代码里的
while循环部分)。 - 当 xxx 很大时,用分式逼近。
一句话总结:
erf和erfc是用来精确计算"高斯分布曲线下面积"的数学工具。在 UGKS 中,它们用于解析求解气体分子微观统计平均后的宏观通量。
flux计算
这是气体动理学格式(GKS)中计算 y方向界面通量 的核心 kernel。让我详细梳理整个计算流程:
一、整体流程图
┌─────────────────────────────────────────────────────────────────────────┐
│ flux_y() 计算流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ 1. 初始化变量 → 2. 获取左右状态 → 3. 坐标变换 → 4. 计算界面状态 │
│ ↓ │
│ 5. 计算物理参数 (EIG, TAU, RT) → 6. 计算空间/时间梯度系数 │
│ ↓ │
│ 7. 平衡态宏观通量 (FLUX_EQ) → 8. 非平衡态微观通量 (FLUX_UN) │
│ ↓ │
│ 9. 热流修正 (FLUX_Q, Shakhov模型) → 10. 总通量组装 │
└─────────────────────────────────────────────────────────────────────────┘
二、详细步骤解析
步骤1:变量初始化
python
ULC = ti.Vector([0.0, 0.0, 0.0, 0.0, 0.0]) # 左状态守恒变量
URC = ti.Vector([0.0, 0.0, 0.0, 0.0, 0.0]) # 右状态守恒变量
UN_U = ti.Vector([0.0, 0.0, 0.0, 0.0, 0.0]) # 上方相邻单元
UN_D = ti.Vector([0.0, 0.0, 0.0, 0.0, 0.0]) # 下方相邻单元
UN_O = ti.Vector([0.0, 0.0, 0.0, 0.0, 0.0]) # 外侧相邻单元 (z+)
UN_I = ti.Vector([0.0, 0.0, 0.0, 0.0, 0.0]) # 内侧相邻单元 (z-)
# ... 等等
| 变量前缀 | 含义 | 维度 |
|---|---|---|
ULC/URC |
Left/Right Cell | 5 (守恒变量) |
UN_* |
Neighbor | 5 (守恒变量) |
ML0/MR0/MUD0/MOI0/MT0 |
梯度系数 | 5 (a₁,a₂,a₃,a₄,A) |
FLUX_* |
通量 | 5 (质量,动量×3,能量) |
步骤2:获取左右状态并坐标变换
python
# 左状态 (y- 方向)
ULC = ctr_w[IX, IY - 1, IZ]
ULC[1], ULC[2] = ULC[2], -ULC[1] # ⚠️ 坐标变换
# 右状态 (y+ 方向)
URC = ctr_w[IX, IY, IZ]
URC[1], URC[2] = URC[2], -URC[1] # ⚠️ 坐标变换
为什么要坐标变换?
这是 局部坐标系变换,将全局坐标系转换到界面法向坐标系:
全局坐标系: (U, V, W) → 局部坐标系: (Uₙ, Uₜ₁, Uₜ₂)
对于 y 方向界面:
法向 = y 方向
切向1 = x 方向
切向2 = z 方向
变换规则:
Uₙ = V (法向速度 = 全局V)
Uₜ₁ = -U (切向速度1 = -全局U)
Uₜ₂ = W (切向速度2 = 全局W)
代码体现:
python
ULC[1], ULC[2] = ULC[2], -ULC[1]
# 原来: [ρ, ρU, ρV, ρW, ρE]
# 变换后: [ρ, ρV, -ρU, ρW, ρE]
# ↑ ↑ ↑ ↑
# 密度 法向 切向1 切向2
步骤3:获取多维相邻状态
python
# 上方 (x- 方向)
UN_U = 0.5*(ctr_w[IX - 1, IY - 1, IZ] + ctr_w[IX - 1, IY, IZ])
UN_U[1], UN_U[2] = UN_U[2], -UN_U[1]
# 下方 (x+ 方向)
UN_D = 0.5*(ctr_w[IX + 1, IY - 1, IZ] + ctr_w[IX + 1, IY, IZ])
UN_D[1], UN_D[2] = UN_D[2], -UN_D[1]
# 外侧 (z+ 方向)
UN_O = 0.5*(ctr_w[IX, IY - 1, IZ + 1] + ctr_w[IX, IY, IZ + 1])
UN_O[1], UN_O[2] = UN_O[2], -UN_O[1]
# 内侧 (z- 方向)
UN_I = 0.5*(ctr_w[IX, IY - 1, IZ - 1] + ctr_w[IX, IY, IZ - 1])
UN_I[1], UN_I[2] = UN_I[2], -UN_I[1]
物理意义 :获取界面周围6个方向的宏观状态,用于计算多维空间梯度。
z+
│
│ UN_O
│
x- ──┼── x+ y方向界面
UN_U │ UN_D (IX, IY, IZ)
│
│ UN_I
│
z-
步骤4:计算界面状态
python
# 界面守恒变量(左右平均)
UN0 = 0.5*(ULC+URC)
# 计算 Lambda 参数 (与温度相关)
EIG0 = EIG(UN0)
EIGL = EIG(ULC)
EIGR = EIG(URC)
# 计算碰撞时间
TAU = COLLISION_TIME_T(UN0[0], EIG0, ULC[0], EIGL, URC[0], EIGR, DELTT)
# 时间积分系数
RT = CPDTT(DELTT, TAU)
# 转换为原始变量 (密度,速度,温度)
DN0 = PHYSICAL_PAR(UN0)
| 函数 | 输入 | 输出 | 物理意义 |
|---|---|---|---|
EIG() |
守恒变量 | λ | 逆温度参数 λ=1/(2RT) |
COLLISION_TIME_T() |
左右状态 | τ | 碰撞时间(粘性相关) |
CPDTT() |
Δt, τ | RT[0:4] | 时间积分系数 |
PHYSICAL_PAR() |
守恒变量 | [ρ,U,V,W,T] | 原始变量 |
步骤5:计算速度矩积分系数
python
# 全速度空间积分 <u^n>, <v^n>, <w^n>
UFF0 = COEF_INFITE(EIG0, DN0[1])
VFF0 = COEF_INFITE(EIG0, DN0[2])
WFF0 = COEF_INFITE(EIG0, DN0[3])
# 半速度空间积分 <u^n>_{u>0}, <u^n>_{u<0}
UFM0 = COEF_INFITE_HARF_LEFT(EIG0, DN0[1])
UFN0 = COEF_INFITE_HARF_RIGHT(EIG0, DN0[1], UFF0, UFM0)
物理意义:预计算Maxwellian分布的速度矩积分,避免在循环中重复计算。
⟨Un⟩=∫−∞∞Une−λU2dU \langle U^n \rangle = \int_{-\infty}^{\infty} U^n e^{-\lambda U^2} dU ⟨Un⟩=∫−∞∞Une−λU2dU
⟨Un⟩U>0=∫0∞Une−λU2dU \langle U^n \rangle_{U>0} = \int_{0}^{\infty} U^n e^{-\lambda U^2} dU ⟨Un⟩U>0=∫0∞Une−λU2dU
步骤6:计算空间梯度系数
python
# 左法向梯度 ML0 (a^l)
DLNG = DIST[0] * UN0[0]
GGT = (UN0 - ULC) / DLNG
ML0 = DXE_f(EIG0, DN0[1], DN0[2], DN0[3], GGT)
# 右法向梯度 MR0 (a^r)
DLNG = DIST[1] * UN0[0]
GGT = (URC - UN0) / DLNG
MR0 = DXE_f(EIG0, DN0[1], DN0[2], DN0[3], GGT)
# y切向梯度 MUD0 (a^y)
DLNG = DIST[0] * UN0[0]
GGT = (UN_U - UN_D) / (4.0 * DLNG)
MUD0 = DXE_f(EIG0, DN0[1], DN0[2], DN0[3], GGT)
# z切向梯度 MOI0 (a^z)
DLNG = DIST[0] * UN0[0]
GGT = (UN_O - UN_I) / (4.0 * DLNG)
MOI0 = DXE_f(EIG0, DN0[1], DN0[2], DN0[3], GGT)
# 时间梯度 MT0 (A)
GGT = MUGF(ML0, MR0, MUD0, MOI0, UFF0, UFM0, UFN0, VFF0, WFF0)
MT0 = DXE_f(EIG0, DN0[1], DN0[2], DN0[3], GGT)
梯度系数物理意义
| 系数 | 对应项 | 物理意义 |
|---|---|---|
ML0 |
aˡ | 左状态空间梯度 ∂ln g/∂x (x<0) |
MR0 |
aʳ | 右状态空间梯度 ∂ln g/∂x (x>0) |
MUD0 |
aʸ | y方向空间梯度 ∂ln g/∂y |
MOI0 |
aᶻ | z方向空间梯度 ∂ln g/∂z |
MT0 |
A | 时间梯度 ∂ln g/∂t |
为什么 MT0 要调用 MUGF?
因为时间梯度通过相容性条件由空间梯度确定:
∫(∂g∂t+U∂g∂x+V∂g∂y+W∂g∂z)ψdU=0 \int \left(\frac{\partial g}{\partial t} + U\frac{\partial g}{\partial x} + V\frac{\partial g}{\partial y} + W\frac{\partial g}{\partial z}\right) \boldsymbol{\psi} dU = 0 ∫(∂t∂g+U∂x∂g+V∂y∂g+W∂z∂g)ψdU=0
MUGF 就是求解这个约束关系。
步骤7:平衡态宏观通量计算
python
FLUX_EQ[0] = fMUVSF(..., 1, 0, 0) # 质量通量
FXI = fMUVSF(..., 2, 0, 0) # x动量
FYI = fMUVSF(..., 1, 1, 0) # y动量
FZI = fMUVSF(..., 1, 0, 1) # z动量
FLUX_EQ[4] = (fMUVSF(..., 3, 0, 0) + fMUVSF(..., 1, 2, 0) + fMUVSF(..., 1, 0, 2)) * 0.5 # 能量
# 坐标逆变换
FLUX_EQ[1:3] = ICRTT(FXI, FYI, FZI, DIJK[:,:,2,IX,IY,IZ])
FLUX_EQ = FLUX_EQ * DLL # 乘以面积/时间
ICRTT 函数:将局部坐标系的通量转换回全局坐标系。
步骤8:非平衡态微观通量(速度空间循环)
python
for iu, iv, iw in ti.static(range(iuh, ivh, iwh)):
# 注意:这里是 y 方向,速度分量要交换
UN = dis_v[iu,iv,iw] # 法向速度 = 全局V
VNT = -dis_u[iu,iv,iw] # 切向速度1 = -全局U
WT = dis_w[iu,iv,iw] # 切向速度2 = 全局W
# 计算 Maxwellian 分布
G0 = ti.exp(-EIG0 * UV2 + ...) * DN0[0]
# 迎风分裂
if UN >= 0: H1 = 1.0; H2 = 0.0
else: H1 = 0.0; H2 = 1.0
# 平衡态微观通量
af_dis_f_h[...] = UN * G0 * (RT[0] + RT[1] * UN * (T5*H1 + T6*H2) + ...)
# 计算分布函数梯度
GGL[0] = (dis_f_h[...] - dis_f_h[...]) / dx
...
# 非平衡态修正
T1 = T11 * H1 + T12 * H2 + ...
af_dis_f_h[...] = (af_dis_f_h[...] + UN * T1) * DLL
# 速度空间积分 → 宏观非平衡通量
FLUX_UN[0] += WXY * UN * T1
FXI += WXY * UN * UN * T1
...
关键区别:y方向 vs x方向
| 方向 | 法向速度 | 切向速度1 | 切向速度2 |
|---|---|---|---|
| x方向 | dis_u |
dis_v |
dis_w |
| y方向 | dis_v |
-dis_u |
dis_w |
| z方向 | dis_w |
dis_u |
dis_v |
步骤9:热流修正(Shakhov模型)
python
if MPRAN == PRAN_SHAKHOV and EIG0 > EPSL:
# 计算热流矢量 Q
Q[0] = Q[0] + 0.5 * CX * QGH
Q[1] = Q[1] + 0.5 * CY * QGH
Q[2] = Q[2] + 0.5 * CZ * QGH
# Shakhov 修正系数
TX0 = 0.8 * (1.0 - prantle) * EIG0 * EIG0 / UN0[0]
# 第二个速度空间循环
for iu, iv, iw in ti.static(range(iuh, ivh, iwh)):
# Shakhov 修正项
T4 = 2.0 * EIG0 * UV2
GG = (T4 + CK[None] - 5.0) * TX0 * CQ * G0 * RT[0]
# 累加到分布函数
af_dis_f_h[...] = af_dis_f_h[...] + UN * GG * DLL
# 计算热流通量
FLUX_Q[0] += WXY * UN * GG
...
Shakhov 模型的作用
标准 BGK 模型的 Prandtl 数固定为 1,与实际气体不符。Shakhov 模型通过修正分布函数:
fShakhov=fBGK+(1−Pr)Pr⋅q⋅c5pRT⋅(c2RT−5)⋅g f^{Shakhov} = f^{BGK} + \frac{(1-Pr)}{Pr} \cdot \frac{\mathbf{q} \cdot \mathbf{c}}{5pRT} \cdot \left(\frac{c^2}{RT} - 5\right) \cdot g fShakhov=fBGK+Pr(1−Pr)⋅5pRTq⋅c⋅(RTc2−5)⋅g
| 参数 | 代码 | 物理意义 |
|---|---|---|
prantle |
Pr | Prandtl 数 |
Q[0:2] |
q | 热流矢量 |
TX0 |
系数 | (1-Pr)/Pr 相关 |
GG |
修正项 | Shakhov 修正 |
步骤10:总通量组装
python
if EIG0 <= EPSL:
FLUX_Q = 0.0 # 真空区域关闭热流
FLUX_Q = FLUX_Q * DLL
# 总通量 = 平衡态 + 非平衡态 + 热流修正
af_ctr_w[IX, IY, IZ] = FLUX_EQ + FLUX_UN + FLUX_Q
三、完整数据流图
┌──────────────────────────────────────────────────────────────────────────┐
│ flux_y() 数据流 │
└──────────────────────────────────────────────────────────────────────────┘
输入: ctr_w[IX, IY, IZ] (守恒变量场)
dis_f_h[...] (分布函数场)
dt_all (时间步长)
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 1. 状态重构 │
│ ULC, URC ← ctr_w (左右状态) │
│ UN_U, UN_D, UN_O, UN_I ← ctr_w (相邻状态) │
│ 坐标变换: [ρ,ρU,ρV,ρW,ρE] → [ρ,ρVₙ,ρUₜ,ρWₜ,ρE] │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 2. 物理参数计算 │
│ UN0 = 0.5(ULC+URC) │
│ EIG0 = EIG(UN0) → λ (逆温度) │
│ TAU = COLLISION_TIME_T → τ (碰撞时间) │
│ RT = CPDTT(Δt, τ) → 时间积分系数 │
│ DN0 = PHYSICAL_PAR → [ρ,U,V,W,T] │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 3. 梯度系数计算 │
│ ML0, MR0 ← (UN0-ULC)/Δx, (URC-UN0)/Δx (法向) │
│ MUD0 ← (UN_U-UN_D)/4Δx (y切向) │
│ MOI0 ← (UN_O-UN_I)/4Δx (z切向) │
│ MT0 ← MUGF(ML0,MR0,MUD0,MOI0) (时间,相容性条件) │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 4. 平衡态通量 FLUX_EQ │
│ fMUVSF(...) × 5次 → [ρU, ρU²+p, ρUV, ρUW, ρEU] │
│ ICRTT() → 坐标逆变换 │
│ × DLL → 乘以面积/时间 │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 5. 非平衡态通量 FLUX_UN (速度空间循环) │
│ for iu,iv,iw: │
│ - 计算 G0 (Maxwellian) │
│ - 迎风分裂 H1, H2 │
│ - 平衡态微观通量 │
│ - 分布函数梯度 GGL, GGR │
│ - 非平衡态修正 T1 │
│ - 速度空间积分 → FLUX_UN │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 6. 热流修正 FLUX_Q (Shakhov 模型) │
│ 计算热流矢量 Q[0:2] │
│ for iu,iv,iw: │
│ - Shakhov 修正项 GG │
│ - 速度空间积分 → FLUX_Q │
└─────────────────────────────────────────────────────────────────────┘
│
▼
输出: af_ctr_w[IX, IY, IZ] = FLUX_EQ + FLUX_UN + FLUX_Q
四、关键公式总结
| 步骤 | 公式 | 代码位置 |
|---|---|---|
| 界面状态 | U0=12(UL+UR)\mathbf{U}_0 = \frac{1}{2}(\mathbf{U}_L + \mathbf{U}_R)U0=21(UL+UR) | UN0 = 0.5*(ULC+URC) |
| 碰撞时间 | τ=f(ρL,λL,ρR,λR,Δt)\tau = f(\rho_L, \lambda_L, \rho_R, \lambda_R, \Delta t)τ=f(ρL,λL,ρR,λR,Δt) | COLLISION_TIME_T() |
| 分布函数 | f=g0[1+alxH(U)+arx(1−H(U))+At]f = g_0[1 + a^l x H(U) + a^r x (1-H(U)) + A t]f=g0[1+alxH(U)+arx(1−H(U))+At] | af_dis_f_h[...] |
| 宏观通量 | F=∫U⋅f⋅ψdU\mathbf{F} = \int U \cdot f \cdot \boldsymbol{\psi} d\mathbf{U}F=∫U⋅f⋅ψdU | FLUX_UN[...] += WXY * UN * T1 |
| Shakhov修正 | fSh=fBGK+1−PrPrq⋅c5pRT(c2RT−5)gf^{Sh} = f^{BGK} + \frac{1-Pr}{Pr}\frac{\mathbf{q}\cdot\mathbf{c}}{5pRT}(\frac{c^2}{RT}-5)gfSh=fBGK+Pr1−Pr5pRTq⋅c(RTc2−5)g | GG = (T4 + CK - 5) * TX0 * CQ * G0 |
五、与 flux_x() 的主要区别
| 项目 | flux_x() | flux_y() |
|---|---|---|
| 法向速度 | dis_u |
dis_v |
| 切向速度1 | dis_v |
-dis_u |
| 界面位置 | (IX, IY, IZ) vs (IX-1, IY, IZ) | (IX, IY, IZ) vs (IX, IY-1, IZ) |
| 相邻方向 | y±, z± | x±, z± |
| 坐标变换 | ULC[1], ULC[3] = ULC[3], -ULC[1] |
ULC[1], ULC[2] = ULC[2], -ULC[1] |
这就是 flux_y() 的完整计算流程!核心思想是:从介观分布函数出发,通过速度空间积分得到宏观通量,同时包含平衡态、非平衡态和热流修正三部分贡献。
update更新过程
这段代码是 UGKS 求解器的时间推进 核心部分。它根据前面计算出的通量(存储在 d_ctr_w 中),真正地更新流场变量。
以下是逐行详细解释:
python
@ti.kernel
def update():
# 遍历所有内部网格单元 (2 到 NX+2)
for I, J, K in ti.ndrange((2, NX + 2), (2, NY + 2), (2, NZ + 2)):
# --- 第一步:保存旧时刻的状态 ---
# 先把当前的守恒变量值取出来,存到 w_old 临时变量中
w_old = ctr_w[I, J, K]
# 将旧值存入 ctr_w_old 数组
# 这通常用于显式时间推进中的残差计算 或者多步龙格库塔方法的中转存储
ctr_w_old[I, J, K] = w_old
# --- 第二步:准备几何与时间参数 ---
# VOL_N: 当前网格单元的体积
VOL_N = VOL[I, J, K]
# DLL: 当前网格单元的局部时间步长 (这是为了局部时间步长技术,加速收敛)
DLL = DTL[I, J, K]
# --- 第三步:更新流场变量 ---
# 这是有限体积法的核心更新公式:
# U_new = U_old + (Flux_Net / Volume) * dt
#
# ctr_w[I, J, K]: 新时刻的守恒变量
# d_ctr_w[I, J, K]: 净通量变化量 (之前 sum_flux_x/y/z 累加的结果)
# 它代表的是 Sum(Flux_in - Flux_out)
# DLL / VOL_N: 将"总通量"转换为"单位体积的变化率"并乘以时间步长
ctr_w[I, J, K] = ctr_w[I, J, K] + d_ctr_w[I, J, K] * DLL / VOL_N
公式对应
这行代码直接对应流体力学有限体积法的离散方程:
Un+1=Un+ΔtΔV∑faces(Fin−Fout) U^{n+1} = U^n + \frac{\Delta t}{\Delta V} \sum_{faces} (F_{in} - F_{out}) Un+1=Un+ΔVΔtfaces∑(Fin−Fout)
- Un+1U^{n+1}Un+1 :
ctr_w[I, J, K](更新后) - UnU^nUn :
ctr_w[I, J, K](更新前) - ∑Flux\sum Flux∑Flux :
d_ctr_w[I, J, K](所有界面通量的累加和) - ΔtΔV\frac{\Delta t}{\Delta V}ΔVΔt :
DLL / VOL_N
注意 :这里使用了局部时间步长 技术。不同的网格单元根据自身的尺寸和声速,使用不同的 Δt\Delta tΔt (DLL)。这样可以大大加快数值模拟收敛到稳态的速度,但要注意,这只适用于求稳态解,不能用于做非定常(随时间变化精确)的物理模拟。