之前听同事说了这个情况,现在找到了争取,记录一下。

原网页:https://bugs.openfoam.org/view.php?id=3299

View Issue Details

ID Project Category View Status Date Submitted Last Update
0003299 OpenFOAM Bug public 2019-06-28 08:53 2019-06-28 12:27
Reporter pantelis Assigned To
Priority normal Severity minor Reproducibility always
Status new Resolution open
Platform Linux OS Centos OS Version 6.5
Summary 0003299: Incorrect particle-wall interaction in OpenFOAM 6
Description I am working on particle filtering in a bend pipe geometry. I recently switch from version OF2.2x to OF6. I found out that the interaction of particles with the walls in not correct in OF6. I observed that a particle sticks on the wall only when it’s center touches on the wall. However the particle must stick on the wall when it’s surface touches the wall. In other words, it’s diameter should be taken into account to check whether there is contact to the wall. I have tested this in OF2.2x and it was working properly. I attach two relevant images. I observe the same behavior in OF6 compiled on Centos with Intel compiler and on macOS using Docker for Mac. I suspect something doesn’t work properly in p.hitFace(s, cloud, ttd); member function (line 361 in /src/lagrangian/intermediate/parcels/Templates/KinematicParcel/KinematicParcel.C)
Steps To Reproduce Find the case files to reproduce the case in this dropbox link: https://www.dropbox.com/sh/budrftdp2smq9ld/AADiGiY0LZOw8iuYgs6azFbGa?dl=0 Run icoUncoupledKinematicParcelFoam from 0-5s. Under a uniform velocity field, a particle with diameter 0.003088m is injected at the inlet of the bent, very near to the upper wall. The particle is deposited on the wall at x=2.28156. It should be deposited a bit upstream when it’s diameter is taken into account (x=2.19506)
Tags No tags attached.

Activities

pantelis 2019-06-28 08:53reporter img

img
will 2019-06-28 11:12manager ~0010535 The behaviour in OF 4 and earlier was to search the current cell for wall-interactions at every tracking step. This was inefficient for the vast majority of usage cases that do not need particles to interact with boundaries at their radius, and it was unreliable in that if a particle was positioned such that it’s radius should intersect a patch face not in the current cell that interaction would be ignored. For these reasons the functionality was removed and (most) particles from version 5 onwards are considered as point masses with respect to patch interaction. The only Lagrangian element that retains the ability to interact with a wall at it’s radius is the colliding parcel. As such, the only way of representing collisions in this way at present is to use a colliding-cloud-type solver (which you are, icoUncoupledKinematicParcelFoam) and switch on the pairCollision model. This is expensive to do as it will calculate all the particle-particle interactions, too. We have some funding for, and are working on, splitting up the pair collision model so that the particle-wall collisions can be used independently from the the particle-particle collisions. That would allow you to model these collisions reliably and efficiently, though it is still likely to be more expensive than before. Watch this space.
pantelis 2019-06-28 12:27reporter ~0010536 Thanks for the clarification Will.

Issue History

Date Modified Username Field Change
2019-06-28 08:53 pantelis New Issue
2019-06-28 08:53 pantelis File Added: OF6.png
2019-06-28 08:53 pantelis File Added: OF22x.png
2019-06-28 11:12 will Note Added: 0010535
2019-06-28 12:27 pantelis Note Added: 0010536

OpenFOAM粒子-壁面碰撞检测机制详解 OF4.1 由Claude 4.5分析得出

1. 核心检测流程

碰撞检测发生在粒子追踪过程中,主要在 particleTemplates.C 的 trackToFace 函数中:

第一步:调用 hitWallFaces 检测壁面碰撞

在particleTemplates.C#L402-L409:

1
2
3
4
5
6
7
8
9
// Sets a value for lambdaMin and facei_ if a wall face is hit by the track.
hitWallFaces
(
cloud,
position_, // 当前位置
endPosition, // 目标位置
lambdaMin, // 输出:最小lambda值
faceHitTetIs // 输出:碰撞的四面体索引
);

2. hitWallFaces 函数详细逻辑

在particleTemplates.C#L719-L935:

步骤1:遍历当前单元的所有面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
forAll(thisCell, cFI)
{
label fI = thisCell[cFI];

if (internalFace(fI)) // 跳过内部面
{
continue;
}

label patchi = patches.patchID()[fI - mesh_.nInternalFaces()];

if (isA<wallPolyPatch>(patches[patchi])) // 只检测壁面
{
// 进行碰撞检测
}
}

步骤2:考虑粒子半径(wallImpactDistance)

在particleTemplates.C#L775-L777:

1
2
3
4
5
6
vector nHat = n/mag(n);  // 壁面法向量

// 粒子相对于壁面的有效半径
scalar r = p.wallImpactDistance(nHat);

vector toPlusRNHat = to + r*nHat; // 考虑半径后的目标位置

这是关键:粒子不是点,而是有体积的! 碰撞检测时将粒子轨迹向外偏移一个半径距离。

步骤3:使用 tetLambda 计算交点参数

在particleTemplates.C#L783-L795和#L810-L820:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 第一次检测:目标位置是否在壁面外侧
scalar tetClambda = tetLambda(
tetIs.tet(mesh_).centre(),
toPlusRNHat,
0, n, f[tetIs.faceBasePt()],
celli_, fI, tetIs.tetPt(),
lambdaDistanceTolerance
);

if ((tetClambda <= 0.0) || (tetClambda >= 1.0))
{
continue; // 不会碰到这个三角形
}

// 第二次检测:实际轨迹与壁面的交点
vector fromPlusRNHat = from + r*nHat;
scalar lambda = tetLambda(
fromPlusRNHat, toPlusRNHat,
0, n, f[tetIs.faceBasePt()],
celli_, fI, tetIs.tetPt(),
lambdaDistanceTolerance
);

3. tetLambda 函数:计算射线-平面交点

在particleI.H#L68-L134:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
inline Foam::scalar Foam::particle::tetLambda(
const vector& from,
const vector& to,
const label triI,
const vector& n, // 平面法向量(带面积)
const label tetPlaneBasePtI,
...
) const
{
const point& base = pPts[tetPlaneBasePtI];

// 射线-平面交点的参数方程
// 交点 = from + lambda*(to - from)
scalar lambdaNumerator = (base - from) & n;
scalar lambdaDenominator = (to - from) & n;

if (mag(lambdaDenominator) < tol)
{
// 轨迹与平面平行或几乎平行
// 返回特殊值处理
}

return lambdaNumerator/lambdaDenominator;
}

lambda 的物理意义

  • lambda = 0: 交点在起点
  • lambda = 1: 交点在终点
  • 0 < lambda < 1: 交点在轨迹中间(发生碰撞
  • lambda < 0lambda > 1: 不碰撞

步骤4:三角形内点判定

在particleTemplates.C#L893-L927:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 使用三角形的intersection函数判断交点是否在三角形内
hitInfo = tri.intersection(
fromPlusRNHat,
(to - from),
intersection::FULL_RAY,
SMALL
);

if (hitInfo.hit())
{
if (lambda < lambdaMin)
{
lambdaMin = lambda; // 记录最近的碰撞点
facei_ = fI; // 记录碰撞的面
closestTetIs = tetIs; // 记录碰撞的四面体
}
}

4. 碰撞后的处理

在检测到碰撞后(facei_ >= 0),在particleTemplates.C#L560-L620会调用相应的处理函数:

1
2
3
4
5
6
7
8
if (isA<wallPolyPatch>(patch))
{
p.hitWallPatch(
static_cast<const wallPolyPatch&>(patch),
td,
faceHitTetIs
);
}

然后通过 PatchInteractionModel 执行具体的相互作用(反弹、粘附、逃逸等)。

5. 关键总结

碰撞检测方法:射线-三角形相交测试
关键参数lambda = 轨迹参数(0到1之间表示碰撞)
考虑粒子大小:通过 wallImpactDistance(nHat) 获取有效半径
检测对象:单元中的所有壁面边界面
选择最近碰撞:通过比较lambda值找到最先碰撞的面

这就是OpenFOAM中完整的粒子-壁面碰撞检测机制!然后通过 PatchInteractionModel 执行具体的相互作用(反弹、粘附、逃逸等)。

5. 关键总结

碰撞检测方法:射线-三角形相交测试
关键参数lambda = 轨迹参数(0到1之间表示碰撞)
考虑粒子大小:通过 wallImpactDistance(nHat) 获取有效半径
检测对象:单元中的所有壁面边界面
选择最近碰撞:通过比较lambda值找到最先碰撞的面

这就是OpenFOAM中完整的粒子-壁面碰撞检测机制!