文章目录
- OpenFOAM里区域分解后polymesh文件解释
- 🔹 1. What is `polyMesh`?
- 🔹 2. Domain Decomposition Overview
- 🔹 3. How `decomposePar` Works with `polyMesh`
- Key Output Files in `processorX/polyMesh/`:
- 🔹 4. Types of Decomposition
- 🔹 5. Handling Processor Boundaries
- 🔹 6. Communication & Field Reconstruction
- 🔹 7. Summary: Role of `polyMesh` in Domain Decomposition
- 🔹 8. Tips
- ✅ Conclusion
- 进程边界底层通信实现
- 一、并行分区与 processor patch
- 二、场在并行环境中的存储
- 三、进程间数据交换机制
- 1. **显式通信:`send` / `receive`**
- 2. **非阻塞通信(推荐)**
- 3. **OpenFOAM 的通信封装**
- 四、典型应用场景:梯度计算
- 五、数据一致性与更新时机
- 六、优化:面映射与共享点处理
- 七、代码示例:手动触发通信
- 总结
- 参考资料
- OpenFOAM lduMatrix::Amul()核心参数说明
- 1. `interfaceBouCoeffs`
- 类型:
- 含义:
- 举例:
- 公式示意:
- 2. `interfaceIntCoeffs`
- 类型:
- 含义:
- 公式示意:
- 物理意义:
- 3. `interfaces`
- 类型:
- 含义:
- 使用方式:
- 三者协同工作流程(在 `lduMatrix::Amul` 中)
- 总结表格
- 应用场景举例
- 参考源码
- 补充说明
OpenFOAM里区域分解后polymesh文件解释
In OpenFOAM, domain decomposition is a crucial technique used in parallel computing to divide a large computational domain into smaller subdomains, each handled by a separate processor. This enables efficient simulation of complex fluid dynamics problems by distributing the computational load across multiple cores or machines.
One of the key components involved in this process is the polyMesh
directory and its associated files, which define the mesh structure. Understanding how domain decomposition works in OpenFOAM requires knowledge of how the mesh is split and how the polyMesh
files are used during this process.
🔹 1. What is polyMesh
?
The polyMesh
directory (located in constant/polyMesh/
) contains all the files that define the unstructured polyhedral mesh used by OpenFOAM. These files include:
points
– Coordinates of all mesh vertices.faces
– List of faces, each defined by a list of point indices.owner
– For each face, the index of the cell that owns it.neighbour
– For internal faces, the index of the neighboring cell.cells
– List of cells, each defined by a list of face indices.boundary
– Definition of boundary patches (name, type, startFace, nFaces, etc.).
This structure is used to represent arbitrary polyhedral meshes and is central to OpenFOAM’s finite volume method.
🔹 2. Domain Decomposition Overview
When running a simulation in parallel, OpenFOAM uses decomposed versions of the mesh and field data. The process involves:
- Decompose the domain into subdomains.
- Distribute each subdomain to a processor.
- Solve equations on each subdomain in parallel.
- Communicate data across processor boundaries as needed.
The tool used to split the mesh is decomposePar
, which reads the original polyMesh
and creates separate mesh data for each processor.
🔹 3. How decomposePar
Works with polyMesh
When you run decomposePar
, it:
- Reads the global mesh from
constant/polyMesh
. - Splits the mesh into N subdomains (based on the number of processors).
- Creates a
processorX/
directory for each subdomain (where X = 0 to N-1). - Each
processorX/
directory contains its ownpolyMesh
folder with modified mesh files.
Key Output Files in processorX/polyMesh/
:
points
,faces
,cells
,owner
,neighbour
,boundary
– Subset of the original mesh.- Additional files:
cellProcAddressing
– Mapping from local cell indices to global cell indices.faceProcAddressing
– Mapping for faces.pointProcAddressing
– Mapping for points.
These addressing files are essential for reconstructing the solution after the simulation (reconstructPar
) and for mapping field values between global and local numbering.
🔹 4. Types of Decomposition
OpenFOAM supports several decomposition methods, defined in system/decomposeParDict
:
- simple: Splits the domain geometrically (e.g., Cartesian slicing).
- hierarchical: Successively divides domain along x, y, z.
- scotch or metis: Graph-based partitioning minimizing communication.
- manual: User-defined assignment of cells to processors.
Example decomposeParDict
:
numberOfSubdomains 4;method scotch;scotchCoeffs
{processorWeights (1 1 1 1);
}
🔹 5. Handling Processor Boundaries
After decomposition, new processor-processor interfaces are created where subdomains meet. These are treated as special boundary types:
processor
,processorCyclic
, orcyclicAMIPolyPatch
(for non-conformal interfaces).- Each processor stores:
- Internal faces (within subdomain).
- Boundary faces on physical boundaries.
- Processor boundary faces – adjacent to another processor’s subdomain.
Communication between processors occurs across these processor patches during the solution process using MPI.
🔹 6. Communication & Field Reconstruction
During simulation:
- Field values on processor boundaries are exchanged via MPI.
- The
fvMesh
class handles communication using the addressing arrays.
After simulation:
reconstructPar
uses thecellProcAddressing
etc. to map solution fields back to the global mesh.
🔹 7. Summary: Role of polyMesh
in Domain Decomposition
Step | Role of polyMesh |
---|---|
1. Original Mesh | constant/polyMesh/ holds the full domain mesh. |
2. Decomposition | decomposePar splits mesh into processorX/polyMesh/ . |
3. Parallel Run | Each processor uses its local polyMesh + addressing files. |
4. Communication | Processor patches in boundary file define MPI interfaces. |
5. Reconstruction | Addressing files map local → global for post-processing. |
🔹 8. Tips
- Always run
decomposePar
beforempirun
for parallel runs. - Use
scotch
ormetis
for better load balancing on complex geometries. - Check decomposition quality with
paraFoam -builtin -case .
and visualizeprocessor
patches. - Clean up with
decomposePar -copyZero
if initial conditions are in0/
.
✅ Conclusion
The polyMesh
files are the foundation of mesh representation in OpenFOAM. During domain decomposition, these files are split and augmented with processor-specific addressing to enable efficient parallel computation. Understanding how polyMesh
evolves during decomposition is key to mastering parallel simulations in OpenFOAM.
Let me know if you’d like a visual example or a step-by-step decomposition demo!
进程边界底层通信实现
在 OpenFOAM 中,当使用并行计算(如通过 decomposePar
将网格划分为多个子域)时,多分区的 polyMesh
网格会被分配到不同的 MPI 进程上。每个进程拥有一个子域(subdomain)的局部网格和相关场(如 U
、p
等)。为了保证数值计算的正确性(尤其是涉及梯度、散度等操作时),必须在进程边界(processor patches)上交换数据。以下是 OpenFOAM 如何处理进程边界数据以及实现进程间场数据交换的机制详解:
一、并行分区与 processor patch
-
网格划分
使用decomposePar
工具将全局网格划分为多个子域,每个子域分配给一个 MPI 进程。划分后,原本内部的面(internal faces)被切割,形成 processor patches(如processor0to1
、processor1to0
等)。 -
processor patch 的作用
- 这些 patch 是虚拟边界,表示两个子域之间的接口。
- 每个 processor patch 包含:
- 本地进程上的面列表(
faceCells
) - 对应的远端进程上的面列表(通过
neighbProcNo
和neighbFaceCells
映射) - 通信所需的数据结构(如共享点、面映射等)
- 本地进程上的面列表(
二、场在并行环境中的存储
- 每个进程只存储其子域内的体心场(如
volScalarField
、volVectorField
)。 - 边界条件中,
processor
类型的 patch 存储了:- 本地侧的面值(
patchInternalField()
) - 需要从远端接收的对面值(通过通信获取)
- 本地侧的面值(
三、进程间数据交换机制
OpenFOAM 使用 MPI(Message Passing Interface) 实现进程间通信。数据交换主要发生在以下场景:
1. 显式通信:send
/ receive
- OpenFOAM 在
processorFvPatchField
类中实现了updateCoeffs()
和evaluate()
方法。 - 当需要获取相邻进程的场值时(如梯度计算),会触发通信。
2. 非阻塞通信(推荐)
- 使用
MPI_Isend
和MPI_Irecv
实现异步通信,提高效率。 - 示例流程:
// 发送本地 patch 上的场值到远端 MPI_Isend(localField.data(), localField.size(), MPI_FLOAT, destProc, tag, MPI_COMM_WORLD, &request);// 接收远端发来的对面场值 MPI_Irecv(receivedField.data(), receivedField.size(), MPI_FLOAT, srcProc, tag, MPI_COMM_WORLD, &request);
- 之后调用
MPI_Waitall()
等待所有通信完成。
3. OpenFOAM 的通信封装
-
OpenFOAM 提供了高层接口,如:
OPwrite
/OPread
:用于全局归约操作reduce()
、sum()
、max()
等并行归约函数send()
/receive()
封装在IPstream
/OPstream
中
-
对于
processorFvPatchField
,其evaluate()
方法会自动触发通信:template<class Type> void processorFvPatchField<Type>::evaluate(const Pstream::commsTypes commsType) {// 发送本地值this->send(this->patchInternalField(), commsType);// 接收远端值Field<Type> receivedValues;this->receive(receivedValues, commsType);// 设置对面值(用于边界条件)this->patch().patchField() = receivedValues; }
四、典型应用场景:梯度计算
当计算 grad(U)
时,需要相邻单元的 U
值。对于位于 processor patch 上的单元,其邻居在远端进程上。因此:
- 每个进程计算本地
U
场在 processor patch 上的值(即U.boundaryField()[patchID]
)。 - 调用
U.boundaryField()[patchID].evaluate()
,触发与远端进程的通信。 - 获取远端
U
值后,用于插值或梯度重构。
五、数据一致性与更新时机
- 通信时机:通常在每个时间步或迭代步开始前,调用
field.correctBoundaryConditions()
,这会触发所有边界条件的更新,包括 processor patch 的数据交换。 - 数据一致性:OpenFOAM 保证在
evaluate()
后,processor patch 上的patchField()
包含最新的远端数据。
六、优化:面映射与共享点处理
- OpenFOAM 支持多种面映射策略(如
direct
、cyclic
、processor
),确保面之间的数据对齐。 - 对于非共形网格,使用
processorCyclic
或插值方法。 - 在
decomposePar
时,可通过sharedPointSync
确保顶点数据一致性(如用于几何操作)。
七、代码示例:手动触发通信
// 假设 U 是 volVectorField
U.correctBoundaryConditions(); // 触发所有边界更新// 或者对特定 patch 手动 evaluate
label patchID = mesh.boundary().findPatchID("processor0to1");
U.boundaryFieldRef()[patchID].evaluate();
总结
机制 | 说明 |
---|---|
processor patch | 表示子域间接口,存储通信映射 |
MPI 通信 | 使用非阻塞 Isend /Irecv 实现高效数据交换 |
boundaryField::evaluate() | 触发通信,获取远端场值 |
correctBoundaryConditions() | 全局更新所有边界,包括 processor 边界 |
数据一致性 | 通信后确保边界值最新,支持梯度、通量等计算 |
参考资料
- OpenFOAM 源码:
src/finiteVolume/fields/fvPatchFields/constraint/processor/
processorFvPatchField.C
和processorFvPatch.C
decomposePar
工具文档- OpenFOAM Programmer’s Guide
通过上述机制,OpenFOAM 实现了高效的并行场数据交换,确保了分布式内存环境下计算的正确性和可扩展性。
OpenFOAM lduMatrix::Amul()核心参数说明
在 OpenFOAM 中,lduMatrix::Amul()
是用于计算矩阵-向量乘法的核心函数之一,其形式为:
psiA = A & psi
即:psiA = A * psi
,其中 A
是稀疏的 lduMatrix
(对角、上对角、下对角存储),psi
是一个场变量(如速度、压力等),psiA
是结果。
在 Amul
的计算过程中,会涉及内部(internal)和边界(boundary)部分。对于并行计算或存在耦合边界条件(如 processor、cyclic、AMI 等)的情况,OpenFOAM 使用 interface 机制来处理这些边界上的耦合项。
以下是 Amul
调用中涉及的三个关键参数的详细说明:
1. interfaceBouCoeffs
类型:
FieldField<Field, scalar>
或更具体地,是 PtrList<Field<Type>>
的包装形式,存储每个边界接口的“边界系数”。
含义:
interfaceBouCoeffs
表示 从相邻域传递到当前域的修正系数,用于处理耦合边界条件中的非对角项。- 在矩阵乘法中,它乘以 相邻进程(或相邻边界)的场值(即
psi
在邻居侧的值),然后贡献到当前域的psiA
。 - 数学上,它对应于矩阵中“从邻居到当前”的耦合项系数。
举例:
对于一个 processor 边界,interfaceBouCoeffs
包含了从其他处理器发送过来的 psi
值所乘的权重(通常与非正交修正、梯度项、离散格式有关)。
公式示意:
在 Amul
中,接口部分贡献为:
psiA += interfaceBouCoeffs[patchI] * (psi received from neighbor)
注意:
bouCoeffs
通常用于隐式项的“边界侧”系数,与intCoeffs
配对使用。
2. interfaceIntCoeffs
类型:
同上,FieldField<Field, scalar>
,每个接口一个场。
含义:
interfaceIntCoeffs
表示 当前域内部场值的修正系数,用于处理耦合边界上的“当前侧”贡献。- 它乘以当前域的
psi
值,并作用于当前域的残差或结果psiA
。 - 通常用于保证矩阵对称性或满足守恒性。
公式示意:
psiA -= interfaceIntCoeffs[patchI] * psi_local
注意:
intCoeffs
和bouCoeffs
通常成对出现,分别处理当前侧和边界侧的贡献。
物理意义:
- 在非正交网格修正、梯度计算、或隐式边界条件(如 zeroGradient)中,
intCoeffs
用于将当前单元的值“推出去”参与界面通量计算。 - 在
fvMatrix
的构造中,这些系数由fvPatchField::initMatrixUpdate()
或类似函数生成。
3. interfaces
类型:
UPtrList<const lduInterfaceField>
,是一个接口字段的列表,每个元素对应一个耦合边界(如 processorLduInterface、cyclicLduInterface 等)。
含义:
interfaces
提供了所有耦合边界上的 通信和数据交换机制。- 它负责在并行计算中:
- 发送当前域的
psi
值到邻居; - 接收邻居的
psi
值; - 执行必要的插值(如 AMI)或变换(如 cyclic 旋转)。
- 发送当前域的
- 在
Amul
中,interfaces
用于获取邻居侧的psi
值,供interfaceBouCoeffs
使用。
使用方式:
forAll(interfaces, patchi)
{if (interfaces.set(patchi)){// 交换数据interfaces[patchi].initInterfaceMatrixUpdate(// ...);}
}
三者协同工作流程(在 lduMatrix::Amul
中)
-
初始化通信:
- 调用
interfaces.initInterfaceMatrixUpdate(...)
开始非阻塞通信,发送当前psi
到邻居。
- 调用
-
计算内部贡献:
- 计算标准的
lduMatrix
内部乘法:diag * psi + upper * psi + lower * psi
。
- 计算标准的
-
处理接口贡献:
- 等待通信完成,接收邻居的
psi
值。 - 对每个接口:
psiA -= interfaceIntCoeffs[patchi] * psi_internal; psiA += interfaceBouCoeffs[patchi] * psi_received_from_neighbor;
- 这些操作通过
interfaces[patchi].updateInterfaceMatrix(...)
完成。
- 等待通信完成,接收邻居的
总结表格
参数 | 类型 | 含义 | 乘以的变量 | 作用方向 |
---|---|---|---|---|
interfaceIntCoeffs | FieldField | 当前域的接口系数 | psi (当前域) | 从当前域“推出” |
interfaceBouCoeffs | FieldField | 邻居域的接口系数 | psi (邻居域,接收到的) | 从邻居“拉入” |
interfaces | UPtrList | 接口通信/插值机制 | 无(提供数据交换) | 实现数据传输 |
应用场景举例
- 并行计算:processor 接口使用这三个参数交换
psi
并计算耦合项。 - 循环边界(cyclic):
intCoeffs
和bouCoeffs
可能相等,interfaces
处理周期性映射。 - AMI(Arbitrary Mesh Interface):
interfaces
执行插值,bouCoeffs
包含插值权重。
参考源码
lduMatrix::Amul
fvMatrix::solveSegregated
processorFvPatchField::updateInterfaceMatrix
lduInterfaceField::updateInterfaceMatrix
补充说明
这些系数通常在 fvMatrix
构造时由 fvMatrix::addBoundaryDiag
和 fvMatrix::addBoundarySource
等函数生成,具体值取决于:
- 离散格式(如
Gauss linear
) - 非正交修正
- 边界条件类型(如
processor
,cyclicAMI
)
如果你正在开发自定义求解器或边界条件,理解这三个参数对于正确实现隐式/显式耦合至关重要。