MPI Sessions 完整介绍+使用
·
文章目录
MPI Sessions 完整介绍+使用+FSI流固耦合实战案例
MPI Sessions 是MPI-4.0 新一代并行执行模型,彻底替代传统 MPI_Init/MPI_Finalize 全局初始化模型,专门解决多物理场耦合、多求解器独立运行、动态资源划分、异构GPU/CPU分区、FSI液固耦合等复杂场景。
结合你之前学的 MPI Partitioned分区通信、CUDA-aware GPU通信,本文一次性讲清原理、API、标准流程、FSI双向流固耦合完整工程实现。
一、MPI Sessions 核心原理(先懂本质)
1. 传统MPI(MPI_Init)的致命缺陷(FSI耦合不能用)
传统模型:
- 全局一次性初始化
MPI_Init,所有进程同属MPI_COMM_WORLD - 全局统一通信上下文、统一错误处理、统一线程级别
- 流体求解器、固体求解器无法独立初始化、独立退出、独立划分进程
- FSI耦合:流体CFD、固体CSM是两套独立求解器,强行塞同一个WORLD会冲突、资源混乱、无法动态增减进程、无法隔离GPU/CPU资源
2. MPI Sessions 是什么?
Session = 独立、隔离、轻量的MPI执行环境实例
- 每个Session拥有独立通信上下文、独立进程集(pset)、独立错误处理、独立线程级别、独立GPU资源绑定
- 多个Session可共存、可嵌套、可跨进程组、可重叠进程
- 不再全局Init/Finalize,而是每个组件独立Session初始化/销毁
- 原生支持:多求解器耦合、动态进程、异构CPU/GPU、Partitioned分区通信、CUDA-aware GPU通信
3. 核心概念(必须记住)
- MPI_Session:会话句柄,独立MPI运行环境
- Process Set (pset):进程集合,Session内逻辑进程组(替代传统Group)
- MPI_Comm_from_pset:从进程集创建通信器(替代MPI_COMM_WORLD)
- 隔离性:流体Session、固体Session、耦合器Session完全独立,互不干扰
- 兼容:Session创建的Comm完全支持你之前学的
MPI_Psend_init/Partitioned/CUDA-aware全部API
4. Session模型 vs 传统Init模型对比
| 特性 | 传统MPI_Init全局模型 | MPI Sessions模型 | FSI耦合优势 |
|---|---|---|---|
| 初始化 | 全局一次性Init | 每个求解器独立Session_Init | 流体/固体分开初始化 |
| 通信域 | 全局WORLD | 每个Session独立Comm | 流体、固体通信完全隔离 |
| 进程管理 | 全局固定进程 | 动态pset进程集 | 流体、固体可分配不同进程数 |
| 资源隔离 | 全局共享 | Session独立GPU/CPU | 流体GPU、固体CPU分开绑定 |
| 销毁 | 全局Finalize | 独立Session_Finalize | 固体结束不影响流体 |
| 兼容Partitioned | 一般 | 原生完美支持 | FSI界面用Partitioned分段传数据 |
二、MPI Sessions 完整标准API函数列表(C语言 MPI4.0/5.0)
1. Session生命周期(创建/销毁)
// 创建Session(独立MPI环境,替代MPI_Init)
int MPI_Session_init(MPI_Info info, MPI_Errhandler errhandler, MPI_Session* session);
// 销毁Session(替代MPI_Finalize)
int MPI_Session_finalize(MPI_Session session);
// 查询是否已初始化Session
int MPI_Session_initialized(MPI_Session session, int* flag);
2. 进程集Pset管理(核心,划分流体/固体进程)
// 获取Session内进程集数量
int MPI_Session_get_num_psets(MPI_Session session, MPI_Info info, int* npset_num);
// 获取第n个进程集名称
int MPI_Session_get_nth_pset(MPI_Session session, MPI_Info info, int n,
int* name_len, char* pset_name);
// 查询进程是否属于某个pset
int MPI_Session_get_pset_info(MPI_Session session, const char* pset_name, MPI_Info* info);
3. Pset转通信器Comm(通信必备)
// 从进程集创建通信器(最常用)
int MPI_Comm_create_from_pset(MPI_Session session, const char* pset_name, MPI_Comm* comm);
// 获取通信器所属Session
int MPI_Comm_get_session(MPI_Comm comm, MPI_Session* session);
4. 辅助信息API
// 设置Session线程级别(MPI_THREAD_MULTIPLE多线程/GPU必备)
int MPI_Session_set_thread_level(MPI_Session session, int required, int* provided);
// 获取Session内当前进程在pset中的rank/size
int MPI_Comm_rank(MPI_Comm comm, int* rank);
int MPI_Comm_size(MPI_Comm comm, int* size);
重点:Session创建的Comm,100%兼容所有旧API + Partitioned分区通信 + CUDA-aware GPU通信,不需要改写原有通信代码。
三、MPI Sessions 标准执行流程(通用模板)
- 启动mpirun分配全部资源(所有流体+固体进程)
- 每个进程独立创建自己的Session
- 每个进程查询所属Pset(流体进程集/固体进程集)
- 从Pset创建专属通信器Comm
- 流体进程:流体Session+流体Comm,运行CFD求解器
- 固体进程:固体Session+固体Comm,运行CSM结构求解器
- 建立流体↔固体耦合通信通道(跨Session跨Comm)
- 时间步迭代:流体计算→界面压力→固体计算→界面位移→流体更新网格
- 独立销毁各自Session,无需全局Finalize
四、特定场景:FSI液固耦合(双向流固耦合)MPI Sessions完整实现
场景说明(工程标准FSI)
双向流固耦合FSI:
- 流体域CFD:N个GPU进程,求解NS方程,输出界面压力载荷
- 固体域CSM:M个CPU进程,求解结构力学,输出界面变形位移
- 两套求解器独立并行、独立初始化、独立资源、独立GPU/CPU
- 界面双向数据传递:压力(流体→固体)、位移(固体→流体)
- 界面通信要求:细粒度异步、分段传输、GPU直传 → 用MPI Sessions + Partitioned分区通信 + CUDA-aware
传统MPI_Init完全无法实现,必须用MPI Sessions隔离流体/固体。
FSI架构设计(MPI Sessions版)
- 全局总进程:Total = Fluid_N + Solid_M
- 划分2个独立Pset:
fluid_pset:流体GPU进程集(0~Fluid_N-1)solid_pset:固体CPU进程集(Fluid_N~Total-1)
- 流体进程:创建流体专属Session→绑定GPU→创建fluid_comm→CUDA-aware Partitioned发送压力
- 固体进程:创建固体专属Session→CPU计算→创建solid_comm→Partitioned接收压力;发送位移
- 跨Session跨Comm建立FSI界面耦合通信
- 每个时间步双向耦合迭代
FSI完整可运行代码(MPI Sessions + Partitioned + CUDA-aware)
#include <mpi.h>
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
// FSI配置
#define FLUID_PROC_NUM 2 // 流体GPU进程数
#define SOLID_PROC_NUM 2 // 固体CPU进程数
#define FSI_PART_NUM 8 // 界面分区数(Partitioned)
#define FSI_DATA_PER_PART 256 // 每个分区数据点数
int main(int argc, char** argv)
{
// ========== 步骤1:每个进程独立初始化MPI Session(替代MPI_Init)==========
MPI_Session session;
MPI_Session_init(MPI_INFO_NULL, MPI_ERRORS_RETURN, &session);
// 设置多线程+GPU支持级别
int required = MPI_THREAD_MULTIPLE, provided;
MPI_Session_set_thread_level(session, required, &provided);
// ========== 步骤2:查询当前进程属于哪个Pset(流体/固体)==========
int total_pset;
MPI_Session_get_num_psets(session, MPI_INFO_NULL, &total_pset);
int is_fluid = 0, is_solid = 0;
char pset_name[64];
// 判断当前进程是流体GPU进程还是固体CPU进程
MPI_Comm world_tmp;
MPI_Comm_create_from_pset(session, MPI_PSET_WORLD, &world_tmp);
int global_rank, global_size;
MPI_Comm_rank(world_tmp, &global_rank);
MPI_Comm_size(world_tmp, &global_size);
// 划分:0~1=流体GPU;2~3=固体CPU
if (global_rank < FLUID_PROC_NUM) {
is_fluid = 1;
strcpy(pset_name, "fluid_pset");
} else {
is_solid = 1;
strcpy(pset_name, "solid_pset");
}
// ========== 步骤3:创建各自专属通信器Comm(流体Comm / 固体Comm)==========
MPI_Comm fluid_comm, solid_comm;
MPI_Request req_pressure, req_displace; // Partitioned耦合通信请求
double* dev_fsi_buf; // GPU流体界面缓冲区(CUDA-aware)
// 流体进程:GPU初始化+流体Session通信器
if (is_fluid) {
cudaSetDevice(global_rank);
MPI_Comm_create_from_pset(session, "fluid_pset", &fluid_comm);
// 分配GPU界面内存(FSI耦合界面数据)
size_t buf_size = FSI_PART_NUM * FSI_DATA_PER_PART * sizeof(double);
cudaMalloc(&dev_fsi_buf, buf_size);
// ========== 步骤4:FSI界面Partitioned分区通信初始化(GPU→固体CPU)==========
// 流体发送界面压力(GPU Device内存 Partitioned)
MPI_Psend_init(dev_fsi_buf,
FSI_PART_NUM,
FSI_DATA_PER_PART,
MPI_DOUBLE,
0, 1001, // 固体耦合接收端rank+tag
fluid_comm,
MPI_INFO_NULL,
&req_pressure);
}
// 固体进程:CPU固体Session通信器
if (is_solid) {
MPI_Comm_create_from_pset(session, "solid_pset", &solid_comm);
double* cpu_fsi_buf = malloc(FSI_PART_NUM * FSI_DATA_PER_PART * sizeof(double));
// 固体接收流体压力Partitioned
MPI_Precv_init(cpu_fsi_buf,
FSI_PART_NUM,
FSI_DATA_PER_PART,
MPI_DOUBLE,
MPI_ANY_SOURCE,
1001,
solid_comm,
MPI_INFO_NULL,
&req_pressure);
// 固体发送界面位移回流体Partitioned(省略,结构一致)
}
// ========== 步骤5:FSI时间步双向耦合主循环==========
for (int step = 0; step < 100; step++)
{
// 流体GPU求解CFD,GPU核函数填充界面压力分区
if (is_fluid) {
// GPU并行填充分区(对应之前GPU Partitioned代码)
// ... GPU核函数填充dev_fsi_buf每个分区压力 ...
MPI_Start(&req_pressure);
// GPU逐分区就绪Pready(CUDA-aware设备端调用)
for (int p=0; p<FSI_PART_NUM; p++) {
MPI_Pready(p, &req_pressure);
}
MPI_Wait(&req_pressure, MPI_STATUS_IGNORE);
}
// 固体CPU求解结构CSM,接收压力→计算变形位移
if (is_solid) {
MPI_Start(&req_pressure);
// 并行查询分区到达Parrived
for (int p=0; p<FSI_PART_NUM; p++) {
int flag;
MPI_Parrived(&req_pressure, p, &flag);
}
MPI_Wait(&req_pressure, MPI_STATUS_IGNORE);
// CPU固体求解:压力→结构变形→界面位移
// ...
// 固体Partitioned发送位移回流体
}
// 流体接收位移→更新网格ALE→下一迭代
}
// ========== 步骤6:独立释放资源+销毁Session(不全局Finalize)==========
if (is_fluid) {
MPI_Request_free(&req_pressure);
cudaFree(dev_fsi_buf);
MPI_Comm_free(&fluid_comm);
}
if (is_solid) {
MPI_Request_free(&req_pressure);
free(cpu_fsi_buf);
MPI_Comm_free(&solid_comm);
}
MPI_Comm_free(&world_tmp);
MPI_Session_finalize(session); // 独立销毁Session
return 0;
}
五、FSI流固耦合使用MPI Sessions的核心优势(工程价值)
- 流体GPU、固体CPU完全资源隔离,互不抢占GPU/CPU
- 两套求解器独立初始化、独立销毁,固体崩溃不影响流体
- 流体、固体可分配不同进程数、不同并行规模
- 界面通信原生支持Partitioned分区异步+CUDA-aware GPU直传,CPU零拷贝
- 支持时间异步耦合(流体大时间步、固体小时间步)
- 兼容OpenFOAM+Abaqus/CalculiX耦合、ANSYS FSI等工业框架
六、MPI Sessions+Partitioned+GPU+FSI 总结速查表
| 模块 | 作用 | FSI耦合用途 |
|---|---|---|
| MPI_Session_init | 独立MPI环境 | 流体/固体分开初始化 |
| Pset进程集 | 划分逻辑进程组 | 区分流体GPU进程、固体CPU进程 |
| MPI_Comm_from_pset | 创建独立通信器 | 流体Comm、固体Comm隔离 |
| MPI_Psend_init/Precv_init | Partitioned分区通信 | FSI界面分段压力/位移传输 |
| MPI_Pready/Parrived | 分区就绪/到达 | GPU并行填充分区异步发送 |
| CUDA-aware | GPU直传通信 | 流体GPU内存直接发往固体CPU |
| MPI_Session_finalize | 独立销毁 | 求解器独立退出 |
七、编译&运行命令
# nvcc+CUDA-aware MPI编译
mpicxx -ccbin nvcc fsi_mpi_session.cu -o fsi_session -O3 -lcuda -lcudart
# 运行:2流体GPU+2固体CPU=总4进程
mpirun -np 4 ./fsi_session
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)