wedge 边界条件调研
Begin
关键词:Axisymmetric
I don’t have any documented reference about how wedges work in OpenFOAM, but as far as I know, the concept is that the wedge boundary is a special type of cyclic boundary condition.
The difference is that:
- Cyclic boundaries assume that the adjacent cell to the boundary will be part of a domain and not part of the other corresponding cyclic boundary (that’s one of the reasons why “empty” exists).
- Wedges act as a one-to-one cyclic boundary that only has to care about a single cell for each wedge-face-pair.
This also means that a wedge can allow rotational flow around the axis, which would explain why a 90 degree cylinder with symmetry boundaries would not give the same results as with the wedge.
However, there are considerable limitations when using wedges: the cells near the axis can have extremely small volumes (OpenFOAM usually only works in 3D, so cell volumes always count), which can result in considerable numerical problems, given that the data is not handled as a 2D case that only accounts for face area.
Furthermore, there have been a few cases that I’ve seen that the wedge face pairs are too close to each other, that it’s not possible to numerically have a significance difference between the centers of those faces. For example, a worst case scenario would be to have a distance smaller than the diameter of a single molecule of water… which is reaaaally small and something that only specialized CFD solvers can handle.
Therein, it’s concluded that the OpenFoam solver requires a 5 degree wedge
OpenFOAM v11 User Guide - 5.3 Mesh boundary (cfd.direct) 中给出了 wedge 几何示意图。本文不直接热链该图片。
PDF 素材:Master_Thesis_Giacomo_Quattrucci_4820428.pdf(原本机路径不可供站点访客访问)
for RANS simulation the approach is based on exploiting the small computational effort required by the solver. Therefore, since the problem and associated physical averaged quantities are axis-symmetric, the pipe was simplified by two-dimensional wedge geometry that represents only a slice of the total cylinder.
openfoam中cyclic周期性边界的问题 (cfd-china.com)
这里面谈及的之前遇到的`internalCoeffs_`与`boundaryCoeffs_`。讨论了这两个的含义。这个回答很有意思,感觉可以回答之前的”Why using LDU in OpenFOAM”的问题。
原帖还讨论了 `internalCoeffs_` 与 `boundaryCoeffs_` 的含义。本文不嵌入论坛截图,结论需要回到固定版本源码验证。
NOTE:在`MULESTemplates.C`中,还发现MULES算法对`wedge`边界条件做了单独的分支判断。
相关分支应直接引用对应版本的 `MULESTemplates.C` 行号;截图已移除。
Versteeg 的有限体积教材讨论了边界条件如何通过取消边界侧连接并修改源项进入离散方程。这里保留转述,不嵌入教材截图。
In Chapters 4 and 5 we saw that boundary conditions enter the discretised equations by suppression of the link to the boundary side and modification of the source terms.
“在这里,“suppression of the link to the boundary”意味着在离散方程中通过取消与边界侧的链接来处理边界条件。这可以理解为在边界处将与边界相关的项或链接移除,以确保在边界处正确处理边界条件。通过这种方式,可以有效地将边界条件纳入离散方程中,确保数值模拟的准确性和稳定性。”
Jasak_five_basic_classes_in_OF
其中有一页是关于边界条件的论述:
Finite Volume Boundary Conditions
• Implementation of boundary conditions is a perfect example of a virtual class hierarchy
• Consider implementation of a boundary condition
◦ Evaluate function: calculate new boundary values depending on behaviour:
fixed value, zero gradient etc.
◦ Enforce boundary type constraint based on matrix coefficients
◦ Multiple if-then-else statements throughout the code: asking for trouble
◦ Virtual function interface: run-time polymorphic dispatch
• Base class: fvPatchField
◦ Derived from a field container
◦ Reference to fvPatch: easy data access
◦ Reference to internal field
• Types of fvPatchField
◦ Basic: fixed value, zero gradient, mixed, coupled, default
◦ Constraint: enforced on all fields by the patch: cyclic, empty, processor, symmetry, wedge, GGI
◦ Derived: wrapping basic type for physics functionality
【翻译】
• 边界条件的实现是虚类层次结构的完美示例
• 考虑边界条件的实现
◦ `Evaluate`函数:根据行为计算新的边界值:
固定值、零梯度等
◦ 根据矩阵系数强制边界类型约束
◦ 代码中遍布多个 if-then-else 语句:自找麻烦
◦ 虚函数接口:运行时多态分发
• 基类:`fvPatchField`
◦ 派生自场`Field`容器
◦ 引用 `fvPatch`:轻松访问数据
◦ 引用内部场
• fvPatchField 的类型
◦ Basic:固定值、零梯度、混合、耦合、默认
◦ Constrain:由补丁对所有字段强制执行:循环、空、处理器、对称、楔形、GGI
◦ Derived:为物理功能包装基本类型
【阅读补充】
在C++中,”virtual class hierarchy” 意味着使用虚拟函数实现的类层次结构。当一个基类中的函数被声明为虚函数时,在派生类中可以通过重写(override)这个函数来实现多态性。这使得在运行时能够根据对象的实际类型来调用对应的函数,而不是根据引用或指针的类型来确定。通过使用虚拟函数和多态性,可以更灵活地设计和实现类之间的关系,实现更高级的抽象和封装,提高代码的可维护性和可扩展性。
Intermediate
网上讨论
这个关于边界条件的讨论很好,有Jasak的回答:
- on correctBoundaryConditions() for a field
- on updateCoeffs() at matrix creationcorrectBoundaryConditions is also called after the linear solver call automatically.
If you want to specify J at the boundary, you will need to create it given a list of boundary patch types. If you give nothing (this is what happens now), you will get a calculated type for the boundary patch field, which is a default choice.
OpenFOAM also has boundaries whoe type is constrained by the mesh definition, e.g. empty, processor, symmetry, cyclic and wedge. This will be handled automatically, i.e. the code won’t let you specify a fixed value patch type on the symmetry boundary.
OpenFOAM矩阵组装的系统介绍(全) - 知乎 (zhihu.com)
这篇帖子里对 `::New` 函数的说明可作为检索线索;运行时选择机制应以对应 OpenFOAM 版本源码为准,不嵌入帖子截图。
从网上的讨论内容来看,边界条件对OpenFOAM求解过程的影响需要单独整理分析。
算例测试
tttt:经测试,使用wedge边界条件,监测两个wedge边界处的面face area vector。`mesh.boundary()[patchI].Sf()[cellI]`,大小相等,方向相反。
wedge相关类
版本:OpenFOAM-v2106。从后面的类图来看(对比了OpenFOAM-v2106和OpenFOAM-7的`wedge`相关类的继承关系图),OpenFOAM-v2106和OpenFOAM-7的`wedge`相关类类似。
wedgeFvPatchField
类描述:`This boundary condition is similar to the cyclic condition, except that it is applied to 2-D geometries.`
在OpenFOAM代码的类描述中谈到`wedge`边界条件:这个类除了在2D情况下,与周期性边界条件类似。
Public member function
1 | // 运行时选择相关 |
1 | // 该函数返回一个tmp指针,该指针指向一个new出来的wedgeFvPatch对象(new的时候的wedgeFvPatch对象掉用拷贝构造,以达到克隆的效果)。 |
1 | // 返回边界处的梯度 |
假设我们有一个函数$F(x)$,其中$x$表示空间中的位置坐标。那么,这段代码可以抽象为以下数学公式:
$$ \text{snGrad}(F(x)) = \left( \text{transform}(T(x), F_{\text{internal}}(x)) - F_{\text{internal}}(x) \right) \times \left(0.5 \times \Delta(x)\right) $$
其中,
- $\text{snGrad}(F(x))$ 表示函数$F(x)$在边界面上的梯度;
- $\text{transform}(T(x), F_{\text{internal}}(x))$ 表示将边界类型$T(x)$和内部场量$F_{\text{internal}}(x)$进行转换操作;
- $F_{\text{internal}}(x)$ 表示边界面的内部场量;
- $\Delta(x)$ 表示边界的delta系数。
`evaluate()`函数中涉及到对矩阵系数的修改`this->updateCoeffs()`以及坐标变换`transform()`
1 | virtual void evaluate (const Pstream::commsTypes commsType=Pstream::commsTypes::blocking) |
1 |
|
其中函数`snGrad()`以及`evaluate()`涉及到旋转函数`transform`的使用。`transform(T,a)`表示用张量`T`来变换张量`a`。例如`snGrad()`函数,通过`this->patchInternalField()`获取靠近边界处的内部场,将该内部场返回为patch场`pif`。该patch场通过旋转函数`transform()`,通过计算得到的旋转张量,将其转到某个地方。该函数的旋转数学表达式含义还不清楚。但可以猜测其是从一个patch处旋转到另外一个patch。其中的`this->patch().deltaCoeffs()`会返回face - cell的距离系数。
1 | template<class Type> |
函数`transform()`定义在文件`transformField()`中。其中包含多种接口的transform函数,其底层会调用`FieldM.H`中的宏函数,从而完成坐标变换。
构造函数
`wedgeFvPatchField`类的构造函数,都会委托给它的父类`transformFvPatchField`进行构造,如代码:
1 | template<class Type> |
提供的多种参数的构造,拷贝构造,均委托给父类`transformFvPatchField`构造。
1 | wedgeFvPatchField (const fvPatch &, const DimensionedField< Type, volMesh > &) |
wedgeFvPatch
该类继承自`fvPatch`以及`wedgePolyPatch`,能够用父类的很多成员函数。
其中的公有成员函数`faceT()`和`cellT()`分别为面的旋转张量以及cell的旋转张量。其实现是通过private的`wedgePolyPatch`对象`wedgePolyPatch_`调用`wedgePolyPatch`的成员函数完成。所以,`faceT()`及`cellT()`的具体实现要看其父类`wedgePolyPatch`。
1 | //- Return face transformation tensor |
wedegePolyPatch
该类下涉及`wedge`相关的一系列计算几何。涉及到对称轴计算,`wedge`边界中心点处的法向量,壁面法向计算,两`wedge`边界条件之间角度的`cos`值,以及`face`和`Neighbour-cell`转动张量
1 |
|
该类下`faceT()`,`cellT()`,角度`cosAngle_`等成员变量均在其中成员函数`calcGeometry`中计算。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19void Foam::wedgePolyPatch::calcGeometry(PstreamBuffers&)
{
//...
n_ = gAverage(nf);
//...
centreNormal_ =
vector
(
sign(n_.x())*(max(mag(n_.x()), 0.5) - 0.5),
sign(n_.y())*(max(mag(n_.y()), 0.5) - 0.5),
sign(n_.z())*(max(mag(n_.z()), 0.5) - 0.5)
);
centreNormal_.normalise();
cosAngle_ = centreNormal_ & n_;
//...
faceT_ = rotationTensor(centreNormal_, n_);
cellT_ = faceT_ & faceT_;
}其中的函数 `rotationTensor` 构造把一个方向旋转到另一个方向的张量。具体公式应以对应版本的函数实现和退化情况处理为准。
类图
调研OpenFOAM-7以及OpenFOAM-v2106中`wedge`相关类的继承层级关系
OpenFOAM-7
1 | classDiagram |
OpenFOAM-v2106
1 | classDiagram |
路径:`/src/finiteVolume/fvMesh/fvPatches/constrint/wedge/wedgeFvPatch*`
路径:`/src/finiteVolume/fields/fvPatchFields/constraint/wedge/wedgeFvPatchField*`
Sum
- `OpenFOAM-7`与`OpenFOAM-v2106`的继承关系相同。 在`OpenFOAM-v2106`的header中看到版权归属于`OpenFOAM Foundation`。所以这两个版本的`OpenFOAM`的wedge实现应该类似。
- `wedgeFvPatch`通过头文件形式在`wedgeFvPatchField`中被引用。
wedge边界条件与旋转周期边界条件
目标:`wedgeFvPatchField`代码内有其与`cyclicFvPatchField`的相似说明(”This boundary condition is similar to the cyclic condition, except that it is applied to 2-D geometries.”)。可以猜想,wedge边界条件和旋转周期性边界条件非常相似。
注:之前使用的周期性边界条件场景为平移边界条件,旋转周期边界在OpenFOAM中,是否在同一个类中?
cylic相关类
`cyclic`与`wedge`的继承链相似的地方在于,其顶层父类都有`fvPatchField`。
1 | classDiagram |
补充`fvPatchField`类的描述:
Abstract base class with a fat-interface to all derived classes covering all possible ways in which they might be used.
The first level of derivation is to basic patchFields which cover zero-gradient, fixed-gradient, fixed-value and mixed conditions.
The next level of derivation covers all the specialised types with specific evaluation procedures, particularly with respect to specific fields.
cyclicFvPatchField
该类下有几个值得注意的成员函数:
1 | //- 判断patch场是否需要进行transform操作 |
这些成员函数功能与`wedgeFvPatch`中`faceT()`以及`cellT()`类似,也是通过调用函数`rotationTensor`计算得到一个旋转张量。这些函数的实现也是在其父类`coupledPolyPatch`中实现
1 |
|
但是,其与`wedge`相关实现存在差别,见图。更加深入的差别待调研,可以先通过同一个算例的`cyclic`和`wedge`边界条件的计算结果对比来明确其差距。

coupledPolyPatch
关于旋转的选择是在该类下定义一个枚举类`transformType`
1 | const Foam::Enum |
如在OpenFOAM-7中的`OpenFOAM-7/tutorials/incompressible/SRFSimpleFoam/mixer/system/blockMeshDict`。可以设置为旋转周期边界。
1 | 121 cyclic_half0 |
而OpenFOAM在实际使用的该边界条件时,一般只需要在初始场中设置为`type cyclic`或加上初始值,并不会在场文件中指定旋转轴。
猜想
矩阵求解的过程中包含边界条件的影响。例如,在求解器中的`solve()`中,可能包含边界条件对矩阵系数影响的修正。
例如之前做的在一维导热情况下的:
1 | // Assigning contribution from BC |
总结
- `wedge`边界条件和`cyclic`边界条件存在很多相似的地方。相同之处在于都采用`transform`函数进行坐标变换。较大的差别在于`wedge`边界涉及到角度计算
- `wedge`边界条件和`cyclic`旋转边界的旋转(坐标变换)数学意义不确定相同
- 旋转周期边界和`wedge`是否能通用需要进一步调研与测试
- `wedge`用于轴对称和球对称,需要对wedge的角度进行坐标变换,而不是简单的镜像对应的patch。
