ReservoirSim 系统设计分析
1. 系统概述

1.1 项目简介
ReservoirSim 是一款基于 C++17 的单机版油藏数值模拟前后处理可视化软件,主要功能包括:
- 高保真网格粗化
- 有限体积油藏求解器
- Remapping 渲染引擎
- Qt5 交互界面
- OpenMP 并行加速
1.2 技术栈
| 组件 | 版本要求 | 用途 |
|---|---|---|
| C++ | C++17 | 核心开发语言 |
| Qt5 | ≥ 5.12 | 界面、OpenGL Widget、并发 |
| OpenMP | ≥ 4.5 | 多核并行加速 |
| OpenGL | ≥ 3.3 | 网格渲染 |
| CMake | ≥ 3.16 | 构建系统 |

2. 系统架构
2.1 分层架构
ReservoirSim 采用经典的分层架构,共分为四层:
┌─────────────────────────────────────────────────────────────┐
│ UI Layer(Qt5 Widgets) │
│ MainWindow ── 控制面板 ── OpenGL Viewport ── 状态栏/日志 │
├─────────────────────────────────────────────────────────────┤
│ Algorithm Layer(算法层) │
│ MeshCoarsener ReservoirSolver MeshRenderer │
│ (网格粗化) (数值模拟求解器) (OpenGL渲染) │
├─────────────────────────────────────────────────────────────┤
│ Core Layer(核心层) │
│ ReservoirMesh MeshIO ReservoirTypes │
│ (网格容器) (IO) (基础数据类型) │
├─────────────────────────────────────────────────────────────┤
│ Runtime Layer(运行时层) │
│ OpenMP 并行线程池 Qt Concurrent 异步任务池 │
└─────────────────────────────────────────────────────────────┘
2.2 模块职责
UI Layer(界面层)
MainWindow:主界面,负责:- 用户交互(菜单、工具栏、参数面板
- 进度反馈、日志显示
- 渲染区域管理
- 异步任务调度
Algorithm Layer(算法层)
MeshCoarsener:网格粗化算法,提供三种策略:- UNIFORM_RATIO:等比例粗化
- ADAPTIVE_ERROR:自适应误差控制
- FEATURE_PRESERVING:特征保持高保真
ReservoirSolver:油藏数值求解器MeshRenderer:OpenGL 渲染引擎
Core Layer(核心层)
ReservoirTypes:核心数据类型定义ReservoirMesh:网格容器MeshIO:网格导入/导出
Runtime Layer(运行时层)
- OpenMP 数据并行
- Qt Concurrent 任务并行
3. 核心数据模型
3.1 基础几何类型
Vec3d(三维坐标点)
cpp
struct Vec3d {
double x, y, z;
// 支持向量运算、点积、叉积、归一化等
};
BBox3d(轴对齐包围盒)
cpp
struct BBox3d {
Vec3d minPt, maxPt;
// 支持扩展、中心、体积计算等
};
3.2 网格数据结构
Node(网格节点)
cpp
struct Node {
int id;
Vec3d pos; // 空间坐标
bool onBoundary;
};
HexCell(六面体单元)
油藏模拟主流单元类型,遵循 VTK_HEXAHEDRON(12) 节点约定
cpp
struct HexCell {
int id;
std::array<int,8> nodeIds; // 8个顶点索引
// 各向异性渗透率张量 (mD)
double Kx, Ky, Kz;
// 孔隙度
double porosity;
// 流体饱和度
double Sw, So, Sg;
// 压力 (MPa)
double pressure;
// 温度 (℃)
double temperature;
// 粗化后引用的精细单元列表
std::vector<int> fineCellIds;
};
ReservoirMesh(油藏网格容器)
cpp
struct ReservoirMesh {
std::string name;
std::vector<Node> nodes;
std::vector<HexCell> cells;
BBox3d bbox;
// 结构化网格尺寸
int nx, ny, nz;
};
3.3 油藏物理属性
FluidPVT(流体 PVT 属性)
cpp
struct FluidPVT {
double viscosityOil, viscosityWater, viscosityGas;
double FVF_oil, FVF_water, FVF_gas;
double GOR; // 气油比
};
RelPermTable(相对渗透率表)
cpp
struct RelPermTable {
std::vector<double> Sw; // 水饱和度离散点
std::vector<double> Kro; // 油相相对渗透率
std::vector<double> Krw; // 水相相对渗透率
};
3.4 网格粗化参数
CoarseningMethod(粗化方法枚举)
cpp
enum class CoarseningMethod {
UNIFORM_RATIO, // 等比例粗化
ADAPTIVE_ERROR, // 自适应误差控制
FEATURE_PRESERVING, // 特征保持粗化
RENORMALIZATION // 归一化渗透率升尺度
};
CoarseningParams(粗化参数)
cpp
struct CoarseningParams {
CoarseningMethod method;
double ratioX, ratioY, ratioZ; // 各方向粗化比
double maxError; // 允许最大相对误差
int minCells; // 最小保留单元数
bool preserveFaults; // 保持断层几何
bool preserveWells; // 保持井周精细网格
double wellInfluenceR; // 井影响半径
int numThreads; // OpenMP 线程数
};
3.5 渲染与可视化配置
ColorMap(颜色映射枚举)
cpp
enum class ColorMap {
VIRIDIS,
JET,
RAINBOW,
HOT_COLD, // 蓝→白→红
GRAYSCALE
};
RenderField(渲染字段枚举)
cpp
enum class RenderField {
PRESSURE,
SATURATION_OIL,
SATURATION_WATER,
POROSITY,
PERMEABILITY_X,
PERMEABILITY_Z,
TEMPERATURE
};
RenderConfig(渲染配置)
cpp
struct RenderConfig {
RenderField field;
ColorMap colorMap;
double dataMin, dataMax;
bool autoRange;
bool showWireframe;
bool showAxes;
bool showColorBar;
float opacity;
bool clipping;
double clipZ;
};
3.6 模拟结果
SimulationStep(单个时间步结果)
cpp
struct SimulationStep {
double time;
std::vector<double> pressure;
std::vector<double> Sw, So, Sg;
};
SimulationResult(完整模拟结果)
cpp
struct SimulationResult {
std::string name;
std::shared_ptr<ReservoirMesh> mesh;
std::vector<SimulationStep> steps;
FluidPVT pvt;
RelPermTable relPerm;
};
4. 核心模块设计
4.1 MeshIO(网格导入/导出)
职责:
- 导入 ECLIPSE GRDECL 格式
- 导入/导出 VTK .vtu 格式
- 生成合成测试网格
- 导出模拟结果为 CSV
主要接口:
cpp
class MeshIO {
public:
static std::shared_ptr<ReservoirMesh> loadGRDECL(const std::string& filePath,
ProgressCallback progress);
static std::shared_ptr<ReservoirMesh> loadVTU(const std::string& filePath,
ProgressCallback progress);
static std::shared_ptr<ReservoirMesh> generateSynthetic(int nx, int ny, int nz,
double dx, double dy, double dz,
bool addHeterogeneity);
static bool exportVTU(const ReservoirMesh& mesh,
const std::string& filePath);
static bool exportCSV(const SimulationResult& result,
const std::string& filePath);
};
4.2 MeshCoarsener(网格粗化)
职责:
- 提供三种粗化策略
- 属性升尺度计算
- 误差分析与质量报告
主要接口:
cpp
class MeshCoarsener {
public:
explicit MeshCoarsener(const CoarseningParams& params);
std::shared_ptr<ReservoirMesh> coarsen(const ReservoirMesh& fineMesh,
ProgressCallback progress);
double computeCoarseningError(const ReservoirMesh& fine,
const ReservoirMesh& coarse) const;
std::string qualityReport(const ReservoirMesh& fine,
const ReservoirMesh& coarse) const;
};
内部实现:
uniformRatioCoarsen():等比例合并adaptiveErrorCoarsen():基于误差控制自适应featurePreservingCoarsen():特征保持upscalePermeability():渗透率升尺度upscalePorosity():孔隙度升尺度
4.3 ReservoirSolver(油藏求解器)
职责:
- 有限体积离散(TPFA)
- 隐式 Euler 时间推进
- ILU(0)-PCG 线性求解
- 两相流饱和度更新
主要接口:
cpp
class ReservoirSolver {
public:
explicit ReservoirSolver(const SolverParams& params);
SimulationResult solve(const ReservoirMesh& mesh,
const FluidPVT& pvt,
const RelPermTable& relPerm,
ProgressCallback progress);
};
内部实现:
assemblePressureMatrix():装配压力系数矩阵updateSaturation():饱和度更新pcgSolve():ILU(0)-PCG 求解computeAdaptiveDt():自适应时间步计算
稀疏矩阵(CSR格式):
cpp
struct CSRMatrix {
int rows, cols, nnz;
std::vector<int> rowPtr;
std::vector<int> colInd;
std::vector<double> values;
void matvec(const std::vector<double>& x,
std::vector<double>& y) const;
};
4.4 MeshRenderer(OpenGL渲染器)
职责:
- 六面体网格渲染
- Remapping 颜色映射
- 颜色条绘制
- 鼠标交互(旋转、缩放、平移)
- 动画播放
- 截图导出
主要接口:
cpp
class MeshRenderer : public QOpenGLWidget {
public:
void setMesh(std::shared_ptr<ReservoirMesh> mesh);
void setSimulationResult(std::shared_ptr<SimulationResult> result);
void setRenderConfig(const RenderConfig& cfg);
void setCurrentStep(int step);
void playAnimation(bool play);
bool saveScreenshot(const QString& filePath);
};
颜色映射:
cpp
class ColorMapper {
public:
static RGBA map(double value, double vMin, double vMax, ColorMap cm);
static RGBA viridis(double t);
static RGBA jet(double t);
static RGBA hotCold(double t);
};
4.5 MainWindow(主界面)
职责:
- 用户交互管理
- 参数面板
- 进度反馈
- 异步任务调度
布局结构:
┌────────────────────────────────────────────────┐
│ 菜单栏 工具栏 │
├──────────┬─────────────────────────────────────┤
│ 左侧 │ │
│ 控制面板 │ OpenGL 渲染区 │
│ (参数/ │ │
│ 属性树) ├─────────────────────────────────────┤
│ │ 时间步滑块 + 播放控制 │
├──────────┴─────────────────────────────────────┤
│ 状态栏(进度条 + 日志) │
└────────────────────────────────────────────────┘
5. 数据流设计
5.1 主数据流
GRDECL/合成网格
│
▼
[MeshIO]
导入 & 预处理
│
▼
[ReservoirMesh] ◄─── fineMesh_(精细网格)
精细网格
│
▼
[MeshCoarsener]
网格粗化
├─ uniformRatioCoarsen()
├─ adaptiveErrorCoarsen()
└─ featurePreservingCoarsen()
│
▼
[ReservoirMesh] ◄─── coarseMesh_(粗化网格)
粗化网格
│
├──────────────────────────────► [MeshRenderer]
│ 渲染粗化网格
▼
[ReservoirSolver]
数值模拟
├─ assemblePressureMatrix() [OpenMP]
├─ pcgSolve() [OpenMP matvec]
└─ updateSaturation() [OpenMP]
│
▼
[SimulationResult]
时间步序列结果
│
▼
[MeshRenderer]
Remapping 可视化
├─ 颜色映射 (ColorMapper)
├─ 颜色条 (ColorBar)
├─ 剖切面
└─ 动画播放
5.2 交互流程
网格粗化流程:
- 用户选择粗化方法和参数
- 点击 "Run Coarsening"
- QtConcurrent::run() 启动后台线程
- ProgressCallback 通过 QMetaObject::invokeMethod 更新进度条
- 粗化完成后更新渲染器
数值模拟流程:
- 用户设置模拟参数
- 点击 "Run Simulation"
- QtConcurrent::run() 启动后台线程
- 进度回调更新进度条
- 模拟完成后更新渲染器和时间步控件
6. 并行计算架构
6.1 OpenMP 数据并行
网格粗化(MeshCoarsener):
cpp
#pragma omp parallel for schedule(dynamic)
for (每个粗化单元组)
属性升尺度计算
求解器(ReservoirSolver):
cpp
// 矩阵装配:
#pragma omp parallel for
for (每个单元 i)
计算 T_ij,累加到 A[i][*]
// 矩阵-向量乘:
#pragma omp parallel for schedule(static)
for (行 i = 0..n)
y[i] = sum(A[i][*] * x[*])
// 饱和度更新:
#pragma omp parallel for
for (每个单元 i)
Sw[i] += ...
6.2 Qt Concurrent 任务并行
主线程(UI线程)
│
├── 用户点击"Run Coarsening"
│ └── QtConcurrent::run(coarsenTask)
│ └── 后台线程执行粗化
│ └── ProgressCallback → QMetaObject::invokeMethod → 更新进度条
│
└── 用户点击"Run Simulation"
└── QtConcurrent::run(simulationTask)
└── 后台线程执行求解
└── ProgressCallback → QMetaObject::invokeMethod → 更新进度条
7. 线程安全
| 组件 | 线程安全性 |
|---|---|
| ReservoirMesh | 只读线程安全;写操作需外部加锁 |
| MeshCoarsener | 每次调用独立实例,内部 OpenMP 自管理 |
| ReservoirSolver | 每次调用独立实例,内部 OpenMP 自管理 |
| MeshRenderer | 只能在 OpenGL 渲染线程(主线程)中调用 |
| ProgressCallback | 通过 QMetaObject::invokeMethod 转发到主线程 |
8. 内存模型
- 精细网格 :
shared_ptr<ReservoirMesh>由 MainWindow 持有 - 粗化网格 :
shared_ptr<ReservoirMesh>由 MainWindow 持有 - 模拟结果 :
shared_ptr<SimulationResult>持有所有时间步,避免数组复制 - 渲染 VBO:GPU 缓冲生命周期由 MeshRenderer 管理
内存估算(100万单元网格):
- ReservoirMesh ≈ 200 MB
- SimulationResult (365步 × 1M × 4字段 × 8字节) ≈ 11.7 GB
建议先粗化(减少到 1~5 万单元),再运行模拟,内存占用可控制在 1 GB 以内
9. 核心算法
9.1 网格粗化算法
等比例粗化(Uniform Ratio)
将结构化网格中每 (rx × ry × rz) 个精细单元合并为一个粗化单元
时间复杂度 :O(N)
空间复杂度:O(N/rx/ry/rz)
自适应误差控制粗化(Adaptive Error)
基于局部非均质性指数动态决定粗化比,高非均质区域保持较细网格
非均质性指数(Dykstra-Parsons 系数):
VDP = 1 - exp(-σ_logK / μ_logK)
特征保持粗化(Feature Preserving)
识别并保留关键地质特征(断层、高渗通道、井附近区域)
渗透率升尺度:
- X, Y 方向:算术平均
- Z 方向:调和平均
9.2 有限体积求解器
数学模型:
∂(φρ)/∂t + ∇·(ρ·K/μ·∇P) = q
空间离散:两点通量近似(TPFA)
时间离散:隐式 Euler(无条件稳定)
线性求解:ILU(0)-PCG
10. 扩展性设计
10.1 新增粗化方法
- 在
ReservoirTypes.h的CoarseningMethod枚举中添加新项 - 在
MeshCoarsener.h/cpp中添加对应私有方法 - 在
MeshCoarsener::coarsen()的switch语句中分支处理
10.2 新增渲染字段
- 在
ReservoirTypes.h的RenderField枚举中添加新项 - 在
MeshRenderer.cpp的getCellFieldValue()中添加取值逻辑 - 在
MainWindow.cpp的字段下拉框中添加选项
10.3 对接 GPU 加速
cpp
// 在 ReservoirSolver.cpp 中替换 pcgSolve() 为 cuSolver:
#ifdef USE_CUDA
#include <cusolver_sp.h>
// 调用 cusolverSpDcsrlsvqr() 求解稀疏系统
#endif
11. 代码规范
- C++17 标准,禁用裸指针(使用
std::shared_ptr/std::unique_ptr) - 命名空间:全部代码置于
RSim::命名空间 - 并行:网格循环使用
#pragma omp parallel for schedule(dynamic) - 注释:Doxygen 风格,英文函数注释,中文说明注释

12. 参考文献
- Durlofsky, L.J. (1991). Numerical calculation of equivalent grid block permeability tensors for heterogeneous porous media. Water Resources Research.
- Christie, M.A. (1996). Upscaling for reservoir simulation. Journal of Petroleum Technology.
- Peaceman, D.W. (1978). Interpretation of well-block pressures in numerical reservoir simulation. SPE Journal.
- Aziz, K. & Settari, A. (1979). Petroleum Reservoir Simulation. Applied Science Publishers.
附录
A. 目录结构
ReservoirSim/
├── CMakeLists.txt # 主构建文件
├── include/ # 公共头文件
│ ├── ReservoirTypes.h # 核心数据类型
│ ├── MeshIO.h # 网格 IO
│ ├── MeshCoarsener.h # 网格粗化算法
│ ├── ReservoirSolver.h # 油藏求解器
│ ├── MeshRenderer.h # OpenGL 渲染器
│ └── MainWindow.h # Qt 主界面
├── src/
│ ├── core/ # 核心数据结构
│ ├── coarsening/ # 网格粗化算法
│ ├── solver/ # 油藏数值模拟求解器
│ ├── rendering/ # OpenGL 渲染引擎
│ ├── ui/ # Qt 界面
│ └── main.cpp # 程序入口
├── tests/ # 单元测试
├── resources/ # Qt 资源
└── docs/ # 技术文档
B. 性能基准
测试环境:Intel Core i7-12700H (14核),32GB RAM,Windows 11
| 精细网格规模 | 粗化比 | 粗化方法 | 粗化耗时 | 误差 |
|---|---|---|---|---|
| 60×60×20 (72K) | 4×4×2 | Feature Preserving | 0.8s | 1.8% |
| 120×120×30 (432K) | 4×4×3 | Adaptive Error | 4.2s | 2.3% |
| 200×200×50 (2M) | 5×5×5 | Uniform Ratio | 1.1s | 5.1% |
| 粗化网格规模 | 模拟时长 | 时间步数 | 求解耗时 |
|---|---|---|---|
| 15×15×10 (2.25K) | 365天 | 13步 | 0.3s |
| 30×30×10 (9K) | 365天 | 13步 | 1.2s |
| 40×40×10 (16K) | 365天 | 13步 | 2.1s |
OpenMP 并行加速比(14核):粗化约 8.5× ,矩阵运算约 6.2×