Gmsh 和 FiPy 求解稳态圆柱绕流
本项目的源码保存在 github 仓库 https://github.com/cjyyx/CFD_Learning/tree/main/CFD软件学习/FiPy/cylinder。如果下载整个目录,可以直接运行 SIMPLE.py
,结果如图
网格生成
采用 Gmsh 的 python 接口生成网格,源码为 Mesh.py
,生成网格如图
控制方程组
假设流体是不可压缩流,则流体满足如下控制方程组
连续性方程
\]
动量方程
\]
其中,\(\vec{u} = (u_{x} , u_{y})\) 表示流场,\(p\) 表示压力场,\(\rho\) 表示密度,\(\mu\) 表示粘度。
将上述方程展开,有
连续性方程
\]
动量方程 \(x\) 方向分量
\]
动量方程 \(y\) 方向分量
\]
SIMPLE 算法
如上面的控制方程组所示,不可压缩流的控制方程组是非线性且耦合的,即流场 \(\vec{u}\) 非齐次,流场与压力场相耦合。
SIMPLE 算法的核心思想是把流场拆分为网格面上的流场 \(\vec{v}\),网格内部的流场 \(\vec{u}\),压力场 \(p\)。先假设压力场 \(p\) 和网格面上的流场 \(\vec{v}\) 已知,求网格内部的流场 \(\vec{u}\),再通过求得的流场求网格面上的流场,进而求压力场,如此迭代至较高精度。
因此,我们可以在 FiPy 中声明变量
U = 10.
Vx = CellVariable(mesh=mesh, name="x velocity", value=U)
Vy = CellVariable(mesh=mesh, name="y velocity", value=0.)
Vf = FaceVariable(mesh=mesh, rank=1)
Vf.setValue((Vx.faceValue, Vy.faceValue))
p = CellVariable(mesh=mesh, name="pressure", value=0.)
pc = CellVariable(mesh=mesh, value=0.) # 压力修正项,后面会提到
首先,我们假设压力场已知,为 \(p^{*}\),且各网格面上的流场已知,为 \(\vec{v}\),则可离散化动量方程,求出网格内部的流场 \(\vec{u}^{*}\)
\]
其中 \(a_{P}, a_{A}\) 都可通过网格面上的流场 \(\vec{v}\) 和网格的几何信息计算。\(V_{P}\) 是控制体的体积,\(\left(\nabla p^{*}\right)_{P}\) 是一个源项,通过压力场 \(p^{*}\) 计算。
在 FiPy 中的代码如下
mu = 0.1
rho = 1.
Vx_Eq = \
UpwindConvectionTerm(coeff=Vf, var=Vx) * rho == \
DiffusionTerm(coeff=mu, var=Vx) - \
ImplicitSourceTerm(coeff=1.0, var=p.grad[0])
Vy_Eq = \
UpwindConvectionTerm(coeff=Vf, var=Vy) * rho == \
DiffusionTerm(coeff=mu, var=Vy) - \
ImplicitSourceTerm(coeff=1.0, var=p.grad[1])
对这个方程进行求解
Rv = 0.8
apx = CellVariable(mesh=mesh, value=1.)
apy = CellVariable(mesh=mesh, value=1.)
Vx_Eq.cacheMatrix()
Vx_Eq.cacheRHSvector()
xres = Vx_Eq.sweep(var=Vx, underRelaxation=Rv)
xmat = Vx_Eq.matrix
xrhs = Vx_Eq.RHSvector
apx[:] = numerix.asarray(xmat.takeDiagonal())
Vy_Eq.cacheMatrix()
Vy_Eq.cacheRHSvector()
yres = Vy_Eq.sweep(var=Vy, underRelaxation=Rv)
ymat = Vy_Eq.matrix
yrhs = Vy_Eq.RHSvector
apy[:] = numerix.asarray(ymat.takeDiagonal())
其中,xmat, ymat
是 \(a_{P}, a_{A}\) 构成的系数矩阵;xrhs, yrhs
是 \(-V_{P}\left(\nabla p^{*}\right)_{P}\) 构成的列向量;apx, apy
是系数矩阵对角线上的值,即 \(a_{P}\) 构成的列向量;xres, yres
是残差,与迭代的收敛相关。
事实上,xmat, ymat
这两个矩阵是完全一致的,即
xmat.matrix.data == ymat.matrix.data # True
且当欠松弛系数 Rv = 1.
时,有
Vc = mesh.cellVolumes
xrhs == (-p.grad[0].value * Vc) # True
yrhs == (-p.grad[1].value * Vc) # True
总之,我们通过 p
和 Vf
求出了 Vx, Vy
,下面可以通过 Vx, Vy
更新 Vf
Vf.setValue((Vx.faceValue, Vy.faceValue))
值得注意的是,直接通过几何插值获取网格面上的流场,可能会造成网格问题,更好的方案是利用 Rhie-Chow 插值
Vcf = CellVariable(mesh=mesh, value=Vc).faceValue
presgrad = p.grad
facepresgrad = presgrad.faceValue
Vf[0] = Vx.faceValue + Vcf / apx.faceValue * \
(presgrad[0].faceValue-facepresgrad[0])
Vf[1] = Vy.faceValue + Vcf / apx.faceValue * \
(presgrad[1].faceValue-facepresgrad[1])
接下来,可以通过流场来更新压力场。当然我们不能只靠动量方程,还要结合连续性方程。我们假设精确的流场和压力场分别为
\]
\]
将精确值代入离散动量方程和连续性方程,有
\]
\]
由于 \(\vec{u}_{P}^{*}\) 已经满足离散动量方程,则有
\]
忽略 \(\sum\limits_{f} a_{A} \vec{u}_{A}^{\prime}\) 项(大概这个忽略不会对最终的结果造成太大的影响吧),有
\]
代入连续性方程,可得
\]
该方程的形式为扩散方程,因此相应的代码为
coeff = (
1. / (
apx.faceValue
* mesh._faceAreas
* mesh._cellDistances
)
)
pc_Eq = \
DiffusionTerm(coeff=coeff, var=pc) \
- Vf.divergence
求解,然后可以更新压力场
pcres = pc_Eq.sweep(var=pc)
p.setValue(p + Rp * pc)
其中 Rp
是欠松弛系数,用来控制收敛速度和稳定性。
接下来可以根据 \(\vec{u} = \vec{u}^{\ast} + \vec{u}^{\prime}\) 更新流场
Vx.setValue(Vx-(Vc*pc.grad[0])/apx)
Vy.setValue(Vy-(Vc*pc.grad[1])/apx)
presgrad = p.grad
facepresgrad = presgrad.faceValue
Vf[0] = Vx.faceValue + Vcf / apx.faceValue * \
(presgrad[0].faceValue-facepresgrad[0])
Vf[1] = Vy.faceValue + Vcf / apx.faceValue * \
(presgrad[1].faceValue-facepresgrad[1])
边界条件
对于圆柱绕流,比较合适的边界条件组合是
- 进口固定速度,压力零梯度
- 出口速度零梯度,压力固定值
- 壁面速度为零,压力零梯度
相应的,代码为
inletFace = mesh.physicalFaces["inlet"]
outletFace = mesh.physicalFaces["outlet"]
cylinderFace = mesh.physicalFaces["cylinder"]
top_bottomFace = mesh.physicalFaces["top"] | mesh.physicalFaces["bottom"]
Vx.constrain(U, inletFace)
Vy.constrain(0., inletFace)
p.faceGrad.constrain(0., inletFace)
pc.faceGrad.constrain(0., inletFace)
Vx.faceGrad.constrain(0., outletFace)
Vy.faceGrad.constrain(0., outletFace)
p.constrain(0., outletFace)
pc.constrain(0., outletFace)
Vx.constrain(0., cylinderFace)
Vy.constrain(0., cylinderFace)
p.faceGrad.constrain(0., cylinderFace)
pc.faceGrad.constrain(0., cylinderFace)
Vx.faceGrad.constrain(0., top_bottomFace)
Vy.faceGrad.constrain(0., top_bottomFace)
p.constrain(0., top_bottomFace)
pc.constrain(0., top_bottomFace)
稳定性问题
雷诺数
雷诺数(Reynolds number)是描述流体运动状态的一个无量纲数。
其定义为
\]
其中,\(\rho\) 是流体密度,\(U\) 是流体速度,\(L\) 是特征长度,\(\mu\) 是粘度。
当雷诺数大于一定的临界值时,流体在管道中的流动状态将从稳定的层流转变为不稳定的湍流,这时候不存在稳态解。
因此,在求解稳态圆柱绕流时,如果雷诺数过大,则在物理上不应该存在稳态解,这在求解过程中,表现为残差收敛过慢或无法收敛,甚至发生残差爆炸。
当然,可以通过一系列手段,强行求出稳态解。
RuntimeError: Factor is exactly singular
发生这个错误是因为离散动量方程的系数矩阵是奇异的,想要降低该错误发生的概率,可以采取以下措施
- 使用更精细网格
- 降低 Rv
- 提高雷诺数
残差爆炸
主要是因为雷诺数过高。避免残差爆炸可以采取以下措施
- 使用更精细网格
- 降低 Rp
- 设置阈值,避免流场变量溢出,即
V_limit = 1e2
p_limit = 2e3
Vx[Vx.value > V_limit] = V_limit
Vx[Vx.value < -V_limit] = -V_limit
Vy[Vy.value > V_limit] = V_limit
Vy[Vy.value < -V_limit] = -V_limit
Vf[Vf.value > V_limit] = V_limit
Vf[Vf.value < -V_limit] = -V_limit
p[p.value > p_limit] = p_limit
p[p.value < -p_limit] = -p_limit
比较稳定的求解方法
尽可能使用更精细网格。
在迭代的开始阶段,调整雷诺数,使雷诺数较低;使 Rv, Rp
较低。从而确保迭代的稳定性。
在迭代过程中,逐渐提升雷诺数至目标值;提升 Rv, Rp
以加快求解速度,但确保 Rv, Rp
小于 1。
当残差稳定时,判断已经收敛,退出求解。
Gmsh 和 FiPy 求解稳态圆柱绕流的更多相关文章
- OpenFOAM&Gmsh&CFD圆柱绕流(两个圆柱)
问题: 圆柱绕流问题,模拟仿真有两个圆柱.一个源的流体变化情况. 解决步骤: 1.使用Gmsh画出网格,并保存cylindertwo.msh 2.以Cavity为基础创建新的Case:Cylinder ...
- LibTorch | 使用神经网络求解一维稳态对流扩散方程
0. 写在前面 本文将使用基于LibTorch(PyTorch C++接口)的神经网络求解器,对一维稳态对流扩散方程进行求解.研究问题参考自教科书\(^{[1]}\)示例 8.3. 目录 0. 写在前 ...
- 【小白的CFD之旅】24 稳态和瞬态
小白最近在练习案例的时候,对稳态和瞬态的问题,产生了一些疑问.譬如说,为什么有的案例用稳态,而有的案例用瞬态?有时候相同的案例既可以用稳态也可以用瞬态,而有的案例却只能用瞬态计算?小白决定找小牛师兄问 ...
- [家里蹲大学数学杂志]第033期稳态可压Navier-Stokes方程弱解的存在性
1. 方程 考虑 $\bbR^3$ 中有界区域 $\Omega$ 上如下的稳态流动: $$\bee\label{eq} \left\{\ba{ll} \Div(\varrho\bbu)=0,\\ \ ...
- ANSYS稳态热分析
目录 题目 APDL操作 温度云图 题目 管子内径外径为r1=4.125mm,r2=4.635mm,中间物体的产热功率为Q=8.73e8W/m3,管外有温度t=127℃的冷水流过,冷却水与管子外表面的 ...
- [Fundamental of Power Electronics]-PART I-2.稳态变换器原理分析-2.2 伏秒平衡/安秒平衡 小纹波近似
2.2 电感伏秒平衡.电容充放电平衡以及小纹波近似 让我们更加仔细地观察图2.6中的buck变换器的电感和电容的波形.我们是不可能设计一个滤波器能够只允许直流分量通过而完全滤除开关频率次谐波的.所以, ...
- [Fundamental of Power Electronics]-PART I-2.稳态变换器原理分析-2.3 Boost 变换器实例
2.3 Boost 变换器实例 图2.13(a)所示的Boost变换器器是另一个众所周知的开关模式变换器,其能够产生幅值大于直流输入电压的直流输出电压.图2.13(b)给出了使用MOSFET和二极管的 ...
- [Fundamental of Power Electronics]-PART I-2.稳态变换器原理分析-2.4 Cuk变换器实例
2.4 Cuk 变换器 作为第二个示例,考虑图2.20(a)的变换器.该变换器执行类似于降压-升压变换器的直流转换功能:它可以增加或减小直流电压的幅值,并且可以反转极性.使用晶体管和二极管的实际实现如 ...
- [Fundamental of Power Electronics]-PART I-2.稳态变换器原理分析-2.5/2.6 多极点滤波器电压纹波估计及要点小结
2.5 含两极点低通滤波器变换器的输出电压纹波估计 在分析包含两极点低通滤波器的变换器如Cuk变换器及Buck变换器(图2.25)输出时,小纹波近似将会失效.对于这些变换器而言,无论输出滤波电容的值是 ...
- [Fundamental of Power Electronics]-PART I-3.稳态等效电路建模,损耗和效率-3.1 直流变压器模型
3.1 直流变压器模型 如图3.1所示,任何开关变换器都包含三个部分:功率输入,功率输出以及控制输入.输入功率按控制输入进行特定的功率变换输出到负载.理想情况下,这些功能将以100%的效率完成,因此 ...
随机推荐
- SpringMVC学习四(文件上传/拦截器)
1.文件上传 1.1预备工作,需要两个jar包(Fileupload) jar包下载路径: [点击下载https://github.com/suyirulan/putao/tree/master/fi ...
- 九、ODBC External Table Of Doris
ODBC External Table Of Doris 提供了Doris通过数据库访问的标准接口(ODBC)来访问外部表 ODBC Driver的安装和配置: 要求所有的BE节点都安装上相同的Dri ...
- Linux 开启防火墙端口策略
1. 安装防火墙 yum install firewalld systemd -y 2. 手动开放防火墙端口 查看防火墙全部设置 firewall-cmd --list-all 若防火墙服务未启动可执 ...
- Gitee千Star优质项目解析: ng-form-element低开引擎解析
好家伙, 在写项目的时候,我发现自己的平台的组件写的实在是太难看了,于是想去gitee上偷点东西,于是我们本期的受害者出现了 gitee项目地址 https://gitee.com/jjxliu306 ...
- SR-IOV 网卡虚拟化技术
目录 文章目录 目录 PCI 与 PCIe 设备 SR-IOV 在 KVM 中启用 SR-IOV 网卡 手动挂载 VF 到虚拟机 指令方式挂载 SR-IOV 的数据包分发机制 PCI 与 PCIe 设 ...
- java学习之旅(day.08)
类与对象的关系 类是一种抽象的数据类型,是对某一类事物的描述,但并不代表具体的事物,如动物与狗的关系,类描述的是某一类事物具备的共同特点 对象是抽象概念的具体实例 能够展现出功能,体现出特点的是具体的 ...
- (二)Redis 数据类型与结构
1.值的数据类型 Redis "快"取决于两方面,一方面,它是内存数据库,另一方面,则是高效的数据结构.Redis 键值对中值的数据类型,也就是数据的保存形式有5种:String( ...
- C#利用win32API创建窗体
效果图 代码实现 1 using System; 2 using System.Runtime.InteropServices; 3 //using System.Windows.Forms; 4 5 ...
- 不关闭SELinux情况下使用ftp传输
在做搭建ftp服务器的作业时,整了一个活,在不关闭SELinux的情况下测试ftp服务器 使用的环境,虚拟机*2 (CentOS 7),Hyper-v,网卡已设为静态 需要安装的软件包: 服务器(下称 ...
- go语言开发的内网穿透工具,frp.
转载自:https://www.appinn.com/frp/ 什么是 Frp? 内网穿透工具有很多,其中 Frp (Fast Reverse Proxy) 是比较流行的一款.FRP 是一个免费开源的 ...