油藏数值模型ReservoirSim 系统设计分析

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 交互流程

网格粗化流程

  1. 用户选择粗化方法和参数
  2. 点击 "Run Coarsening"
  3. QtConcurrent::run() 启动后台线程
  4. ProgressCallback 通过 QMetaObject::invokeMethod 更新进度条
  5. 粗化完成后更新渲染器

数值模拟流程

  1. 用户设置模拟参数
  2. 点击 "Run Simulation"
  3. QtConcurrent::run() 启动后台线程
  4. 进度回调更新进度条
  5. 模拟完成后更新渲染器和时间步控件

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 新增粗化方法

  1. ReservoirTypes.hCoarseningMethod 枚举中添加新项
  2. MeshCoarsener.h/cpp 中添加对应私有方法
  3. MeshCoarsener::coarsen()switch 语句中分支处理

10.2 新增渲染字段

  1. ReservoirTypes.hRenderField 枚举中添加新项
  2. MeshRenderer.cppgetCellFieldValue() 中添加取值逻辑
  3. 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. 参考文献

  1. Durlofsky, L.J. (1991). Numerical calculation of equivalent grid block permeability tensors for heterogeneous porous media. Water Resources Research.
  2. Christie, M.A. (1996). Upscaling for reservoir simulation. Journal of Petroleum Technology.
  3. Peaceman, D.W. (1978). Interpretation of well-block pressures in numerical reservoir simulation. SPE Journal.
  4. 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×

相关推荐
计算机安禾2 小时前
【数据结构与算法】第13篇:栈(三):中缀表达式转后缀表达式及计算
c语言·开发语言·数据结构·c++·算法·链表
简单~2 小时前
C++ 函数模板完全指南
c++·函数模板
·心猿意码·2 小时前
C++ 线程安全单例模式的底层源码级解析
c++·单例模式
故事和你912 小时前
洛谷-入门4-数组3
开发语言·数据结构·c++·算法·动态规划·图论
Yu_Lijing2 小时前
基于C++的《Head First设计模式》笔记——原型模式
c++·笔记·设计模式
玉树临风ives2 小时前
atcoder ABC 451 题解
c++·算法·atcoder
南境十里·墨染春水3 小时前
C++传记 详解单例模式(面向对象)
开发语言·c++·单例模式
扶摇接北海1763 小时前
洛谷:B4488 [语言月赛 202602] 甜品食用
数据结构·c++·算法
cui_ruicheng3 小时前
C++智能指针:从 RAII 到 shared_ptr 源码实现
开发语言·c++