☰
多孔介质达西两相流模拟:COMSOL水驱油建模与数值实践
2026/10/6 5:31:58 网站建设 项目流程

多孔介质里的油水流动,看着像“水进去把油顶出来”一句话就能讲完的物理过程,真要落地到数值仿真里,坑比想象中多得多。做油田开发、CO2埋存、地下水污染修复的同行,迟早会碰到“多孔介质多相流”这块硬骨头。Comsol里的达西两相流模型,算是兼顾工程实用和物理直觉的一个好入口,但也是很多人用起来觉得“怎么老不收敛”“为什么水和油混在一起”的重灾区。这篇东西,我打算把模型背后的物理逻辑、方程结构、Comsol里的实操细节,还有我踩过的那些数值坑,系统地摊开来聊一聊。适合刚准备用水驱油模型算第一轮岩心尺度的项目、以及在油藏尺度和实验数据反复对不上的同学参考。

1. 不是玄学:多孔介质两相流的物理背景与工程需求

1.1 为什么“水驱油”不能拿简单扩散来糊弄

先想一个最朴素的问题:把水倒进一块吸饱油的砂岩里,水是不是真的“匀速推进”把油挤出来?现实里完全不是这么回事。水走的是孔隙通道,油占着的是部分孔隙空间,两者互相竞争又互相让路,水突破时油可能才采出一半。这就是水驱油的真实场景——推进前缘不稳定、指进、剩余油被困在微观孔隙里。

如果用纯粹的扩散方程描述这种过程,把油水浓度差当成扩散驱动力,那就错了。多孔介质里的两相流动,每一相的驱动力来自压力梯度,而这个压力梯度同时受到毛细压力、相对渗透率、黏度差异的共同控制。打个比方:地下油藏更像挤满了海绵块的洗碗池,水要绕过油泡、挤过细喉道,而不是在碗里匀开。达西两相流模型的核心价值,就在于用“相压力差 + 相对渗透率 + 饱和度”这套框架,把这种复杂的竞争关系压缩成一组可求解的偏微分方程。

1.2 油藏工程师到底想要这个模型算出什么

现实工程里,模型不是用来发论文的,是用来回答几个有严格量化要求的问题:第一,注入多少倍孔隙体积的水,油井开始见水;第二,累积产油量随注入量变化曲线长什么样;第三,提高注入速度后,是产出更多油还是更早水突破。这三个问题背后,对应的是模型的三个核心输出:含水饱和度场、各相压力场、以及从井点提取的产水率/产油率曲线。

Comsol里的达西两相流模型(以Darcy's Law模块为基础扩展)提供的正是这套能力。它能在一维岩心柱、二维平面径向流、甚至三维非均质地质体里求解饱和度随时间的演化。和油藏工程里传统的Buckley-Leverett解析方法相比,这种数值模型不需要假设互不相溶的活塞式驱替,能捕捉到指进、毛管力引起的饱和度拖尾、以及边界效应。

就我接触过的实际项目来看,刚入手的同学最容易犯的认知错误,是把“两相流的相”理解成“两种物质的浓度”。在Comsol中,相是指液相和气相,或者不互溶的油相与水相。每一相都拥有自己独立的速度场,而这两个速度场不是自由流动的,是通过毛细压力关系和相对渗透率耦合在一块的。想通这一层,才知道模型里饱和度变量的物理意义。

2. 达西两相流模型:从“定律”到“控制方程”的正确打开方式

2.1 达西速度方程的“三相”拆解

先写达西定律最基础的形态:整体流速与压力梯度、流体黏度、渗透率的关系。在单相情况下,这个定律干净利落。到了两相,麻烦来了——每一相都在流动,可孔隙空间只有一套;所以引入了“相渗透率”的概念:

[ u_w = -\frac{k k_{rw}(S_w)}{\mu_w} \nabla p_w ] [ u_o = -\frac{k k_{ro}(S_w)}{\mu_o} \nabla p_o ]

这里下标 w 和 o 分别代表水相和油相,u 是各相的达西流速(不是孔隙里的真实流速,要除以孔隙度才能换算平均真实流速),k 是绝对渗透率,k_rw 和 k_ro 是相对渗透率,它们是含水饱和度 S_w 的强非线性函数。

很多人第一次看到这套式子会问:为什么不用统一的压力 p,而每个相要有自己的压力?因为在孔隙尺度上,油水界面是弯曲的,曲面两侧的压力不相等,这个压力差就是毛细压力:

[ p_c(S_w) = p_o - p_w = p_{c,entry} \cdot (S_e)^{-1/\lambda} ]

毛细压力函数是一条随含水饱和度变化的曲线。饱和度越低,水相越难挤进小孔隙,油水界面弯曲越剧烈,压差越大。理解了毛细压力,才能理解为什么油藏不是简单的“水进油退”,而是在油水前缘附近有一大片饱和度过渡带。

2.2 相对渗透率曲线:整个模型的“性格”

相对渗透率曲线就是多孔介质两相流的“性格参数”。油藏里常用的Corey型表达式,形式很简单,物理意义却很扎实:

[ k_{rw} = k_{rw,ro} \cdot (S_e)^{n_w}, \quad k_{ro} = k_{ro,iw} \cdot (1 - S_e)^{n_o} ]

其中 (S_e) 是归一化饱和度,把束缚水饱和度和残余油饱和度之间的范围压缩到 0 到 1 之间:

[ S_e = \frac{S_w - S_{wr}}{1 - S_{wor} - S_{wr}} ]

为什么这个归一化特别重要?因为如果不做归一化,边界上很容易出现饱和度过界:算着算着 S_w 小于束缚水饱和度,或者超过 1 - 残余油饱和度,然后出现负数渗透率,求解器直接崩掉。Corey指数 n_w 和 n_o 实验上通常在 2 到 4 之间。n 越大,相渗透率下降得越陡峭,前缘推进越呈现“活塞式”,模型收敛难度也越高。

我记得有个还不错的做法是先用 n_w = n_o = 2 跑通全局,再逐步调整到实验测得的指数。这样能区分“数值不收敛”和“物理参数导致的前缘剧烈变化”两类问题,别一上来就用极陡峭曲线。

2.3 饱和度方程:从“局域守恒”到“宏观流动”

两相流的第二个核心方程是饱和度方程,本质上是从质量守恒出发:

[ \phi \frac{\partial S_w}{\partial t} + \nabla \cdot u_w = Q_w ]

这里 (\phi) 是孔隙度,Q_w 是源汇项(注水井和采油井通常以这种点源形式出现)。把达西速度代入,就得到一个关于含水饱和度的对流-扩散型方程。对流项来自宏观压差驱动,扩散项来自毛细压力梯度引起的自发渗吸。

这里的关键认知是:饱和度方程不是一个独立的“纯传输”方程,它跟压力方程紧紧咬合。整个系统可以表述成“压力场决定速度,速度决定饱和度演化,饱和度演化又反过来改变相对渗透率”。这个耦合循环是数值求解中最难啃的硬骨头——每走一个时间步,都要把非线性迭代收敛到指定容差,否则很容易出现饱和度非物理振荡。

3. Comsol建模实操:从几何到求解器的一步步展开

3.1 几何选型:一维岩心柱和二维平板模型怎么选

刚开始做水驱油模拟,我认为最简单的验证场景就是“一维岩心柱”。几何是一根长条,左边入口注水,右边出口定压,网格密度均匀。虽然一维模型看着寒酸,但它能极其准确地验证饱和度前缘推进速度是否和Buckley-Leverett半解析解一致。这一步做对了,我再建议升级到二维或者三维。

二维模型通常对应“一块水平油藏切片”,可以是矩形均质体,也可以加上低渗透条带、裂缝。注意不要把几何建得太复杂,要理解网格分辨率对饱和度前缘的数值弥散影响非常大。如果目的只是验证模型物理,均质二维矩形就够了;只有当目标转移到非均质性效应时,再引入复杂的物性分区。

三维模型的代价不只是网格数量,更重要的是非线性迭代负担。我见过不少人一上来就是一口注水井一口采油井的三维模型,最后在含油饱和度场里看到一大片“均匀的油水混合相”,这其实往往是数值弥散掩盖了真实的前缘推进过程。

3.2 模块选择和物理场接口:一个容易被忽略的关键点

Comsol 6.x 的“Subsurface Flow Module”里提供了Darcy定律接口。两相流的做法不是直接选现成按钮,而是在Darcy定律接口里定义两个域(水相和油相),或者使用用户定义的多物理场耦合。实际操作中,我更倾向于用“PDE + Darcy定律”的组合,内核仍然是系数型偏微分方程,界面更透明,方便排查问题。

如果追求效率,可以直接用 Subsurface Flow Module 里的“Two-Phase Darcy Flow”接口,省去手动耦合的麻烦。但这个接口有个特点,它的主变量是“含水饱和度和压力”,对初值条件非常敏感。务必注意,初值里不能出现 S_w = 0 或 S_w = 1 这种端值,否则相对渗透率计算会遇到奇异。

几何建立时,需要为油相和水相分别指定初始饱和度的空间函数。通常做法是:岩心初始为束缚水饱和度 (S_{wr}),其余空间被油相占据,这个初值应该作为“初始值”设定,而不是设成某个边界条件。很多人喜欢把整个域的初始饱和度设成纯油,这在数学上没有问题,但数值上会在初始瞬间产生压力突变,紧跟着就是时间步进失败。

3.3 材料属性:不只是填几个数字,要理解它们之间的耦合

材料节点里需要输入孔隙度、绝对渗透率、流体密度、黏度、相对渗透率曲线和毛细压力曲线。最容易翻车的地方在于“孔隙度和渗透率的关系”——如果滥用平方关系,会强行制造出与实验不符的压降。

我给一个简单可复现的案例参数:孔隙度 0.25,绝对渗透率 500 mD(换算成国际单位约为 (5 \times 10^{-13} , \mathrm{m^2})),水相黏度 0.001 Pa·s,油相黏度 0.01 Pa·s,束缚水饱和度 0.2,残余油饱和度 0.2,Corey指数都取 2。这套参数下,油水黏度比 10:1,水驱前缘的不稳定性已经可以看出来了,但又不至于让收敛性直接爆炸。

实测下来,密度影响很小,真正主导的是黏度和相对渗透率曲线。因此模型初调时把密度全设为常数,没有多大问题。但如果你做的项目里重力效应同样重要(比如三维模型中油水上倾运移),密度的设置就必须按层位的温度压力量级仔细核查。

3.4 边界条件:入口、出口、封闭边界的三板斧

入口边界最常见的选择是“通量/速度”或者“压力”。如果边界设为水相饱和度为 1,这基本就是“活塞式”注水假设。这样做是可行的,但要注意入口处会因为饱和度跳变形成一个非常陡的锋面,网格稍微粗一点就能看到数值振荡。一个缓解技巧:入口边界饱和度不用 1,而是 (1 - \varepsilon),通常是 0.95,这样给前缘留一点缓冲。

出口边界可以设为定压:比如 (p_o = 0)(参考压力)。但要小心,出口处如果不做额外处理,饱和度和压力会同时被指定,这其实是一个过约束条件,容易造成局部饱和度异常。合理的做法是让出口自由流出,压力固定,饱和度由内部方程自动决定。

封闭边界自然就是通量为零,但要注意重力和毛细压力的影响。如果模型考虑重力,边界的通量表达式里不仅仅有压力梯度项,还可能包含重力项,如果直接设零通量,实际上切断了重力平衡,局部会逐渐累积非物理的压力。

3.5 求解器配置:时间步进、非线性迭代和两个求解策略

水驱油强烈推荐瞬态求解。稳态解法在这里没有实际意义——水驱油的本质就是一个推进过程,你关心的核心动态是“饱和度前沿到哪了”。

求解器选择上,我通常先用“分离式”求解(segregated solver),把压力方程和饱和度方程分开迭代,好处是单次迭代成本低,内存占用小,适合第一轮试算。但它对强非线性问题容易发散。如果分离式失败,切换到“全耦合”求解器,凭借更完整的雅可比矩阵获得收敛性,代价是内存占用大幅上升。

时间步进上要注意:不要一开始就用固定的超大时间步。推荐“初始步长 1e-4 秒,最大步长不会太离谱”的自由时间步进。为什么?因为注入刚开始时,入口附近的饱和度变化极其剧烈,前缘在很短的时间里形成。如果你一上来就大步长,前缘直接被抹平了,往后想剧烈都剧烈不起来。要让求解器在初期用多个小步长去捕捉锋面形成,之后再自动放大时间步。

求解器日志里最容易出现的一行字是“非线性迭代不收敛”,这时候最不该做的是盲目减小时间步,而是先检查初始条件、边界饱和度突变、相对渗透率曲线是否光滑。

4. 水驱油动态:从注入突破到饱和度分布的完整解读

4.1 模拟一维岩心水驱过程:从稳定推进到前缘突破

跑通一维岩心柱模型之后,你会在结果中看到一个清晰的饱和度波前沿推进。在初期,注入水以相对平缓的梯度从入口向出口推进,这是因为毛细压力带来的扩散效应让前缘有一定程度的“涂抹”。随着时间推移,一旦注入量达到足够大,饱和度前缘变陡,最终在出口出现“水突破”。

突破时刻就是产油的高峰转向点。突破之前,出口采出的几乎全是油;突破之后,油产量迅速下降,水产量上升。这就是油田开发指标里最关心的“无水采油期”。用Comsol的后处理功能,可以在全局计算里定义 (Q_w = \int U_w , dS),得到产水率随时间曲线,这个曲线的形状对相对渗透率曲线极其敏感。

我跑完的基本规律是:Corey指数越大,油水互驱的过渡带越窄,突破时间越延后,但突破后的产油衰减也更剧烈。两条不同的相对渗透率曲线,可能给出完全相同的累计产油量,却给出差异极大的产水率曲线形状。所以如果你在拟合实验数据,不要只看最终采收率,一定要盯住产水率的整体形状。

4.2 二维模型的非均质性效应:如何让前缘“歪掉”

二维模型真正的教学价值,在于让前缘从“一根笔直的线”变成“歪歪扭扭的形态”。当你在中间放入一条低渗透条带,相当于设置了一个流道屏障,水流会绕弯,饱和度前缘被拉伸,局部区域还会出现残余油封堵。

实操上,可以通过“域内材料不同渗透率”来处理,不需要对每个尺度都去细解剖,重点是让水绕过障碍。这种情况下,网格质量直接决定前缘形态。我用过好的做法是“自适应网格细化”,在饱和度梯度大的区域自动加密网格。Comsol里可以在求解器里打开自适应网格;但我更常做的是在计算过程中手动暂停,看一眼渐变区的网格分布,再有针对性细化。因为自适应网格的判据很多时候会捕捉所有高梯度区,包括一些并不关键的边界,导致网格数量暴增。

4.3 三维扩展:重力分异和黏性指进的正面交锋

三维模型里最经典的视觉就是“Viscous fingering”——水沿着高渗透层快速突破,低渗透区域却有大量剩余油。效果很像在一盘奶油里滴入咖啡,丝状的混合前缘不均匀地向前伸展。这种指进在二维模型里也能看到,但三维里更明显更复杂,因为水流同时受重力影响,上下分层流动不同步。

三维模型的工程价值在于评估“垂向非均质性”的影响。比如渗透率随深度变化,水通常优先进入高渗透层,从下部快速推进,油则从上部慢慢被驱动。这就导致整体采收率低于均质假设的预测。

转向三维之前,我建议先完整跑通二维,并且认认真真看一张“饱和度分布图 + 流线图”的组合图。流线能直观告诉你水是从哪条路径流过去的,饱和度图告诉你水有没有把沿途的油洗干净。两者结合,几乎能一眼发现问题:要么是网格不够细导致流线寄生,要么是边界条件导致“死角”太多。

4.4 水驱油模型与变形介质/裂缝的耦合:一个加分技能

很多人做到这一步就想更进一步:油藏里的多孔介质不是刚性骨架,长期注水之后压力变化会引起局部压实,裂缝在注水压力下也会张开或闭合。Comsol里可以利用“移动网格”耦合达西两相流和固体力学。

我的经验是,这种多物理场耦合需要小心两个时间尺度。流动的时间尺度可能是几个月到几年,而固体变形的响应可能是准静态。如果直接用瞬态整体推进,计算量极其惊人,往往几天跑不出结果。更现实的简化处理:在不同的时间节点上,把压力场和饱和度场映射到固体力学模块做准静态变形分析,再把更新的孔隙度和渗透率传递回流动场。这种做法能节省大量时间,结果精度在工程上完全够用。

工程上常见的裂缝(比如水力压裂缝),也可以看作超高渗透率的“局部条带”,用等效渗透率来近似,不需要在几何里把裂缝宽度真实地画出来。裂缝宽度毫米级,如果画真实几何,网格尺度要小到微米级,计算代价高到没有实际意义。用等效渗透率近似后,裂缝路径的流量和压差都能保持在一个合理量级。

5. 常见问题排查与数值稳定性实录

5.1 饱和度过冲:水相饱和度“破1”的根源与破解

如果后处理里看到含水饱和度出现大于 1 或小于 0 的“色斑”,第一反应不要怀疑方程错了,而是检查三个东西:网格质量、对流项迎风效应、相对渗透率曲线是否过于陡峭。

Comsol的默认离散格式通常是拉各朗日一次形函数,对饱和度这类强非线性未知量来说,一阶格式带来的数值耗散较大,但稳定性好。若换成二次形函数,精度提升了,但过冲(overshoot)概率也上来了。我的维修策略是:先把最高阶次降下来跑通,保证物理结果合理,再试探性升阶并观察是否出现负饱和度。

一旦出现局部过冲,不要试图用人工扩散掩盖——那样会把饱和度前缘抹得一塌糊涂。正确的处理是从网格入手,尤其在前缘梯度大的位置密化网格。另外,检查入口绑定的边界饱和度是不是太高,我此前把入口饱和度从1改为0.99,就奇迹般地解决了初期的振荡问题。

5.2 非线性不收敛:求解器一轮又一轮迭代却不跳出来

这是所有做强非线性问题的人共同的伤。水驱油模型的不收敛,多半集中在“时间步进太大导致初值离解太远”,或者“相对渗透率曲线的一阶导数不连续”。

我的排查顺序是:先重新设置更小的时间步;如果没效果,检查相对渗透率和毛细压力曲线在跨饱和度区间是否足够光滑,中间点是否够多;如果还没效果,把入口初始饱和度设为相对渗透率曲线端点附近,而不是绝对的极限值;最后一步才是把分离式切换成全耦合。

还有一个非常好用的手段:打开求解器的“自适应时间步长”功能,并设置合理的最小步长上限。注意不要给它设置一个过于疯狂的最大时间步,否则求解器觉得自己可以使用任意大步长,结果每个大步长内部非线性迭代需要大量子迭代,算下来反而更慢。

5.3 网格敏感度:为什么岩心出口含水率随网格加密而摇摆

如果同一套物理参数下,把网格加密一倍,突破时间提前或延后了20%以上,说明你的解高度依赖网格——这就是数值弥散在作祟。对流主导问题的经典痛点:网格越疏,数值弥散越大,前缘被抹平,突破看着变早了。

检验网格敏感度的正规方法是“网格收敛性测试”:跑三套网格,分别记为粗、中、细,观察出口含水率曲线。如果三者的差异在可接受范围内(比如小于4%),那当前网格就算合格;如果细网格和粗网格差异巨大,恭喜你,还得继续加密或者换成更高阶离散。

工程上为了控制网格规模,我推荐“边界层网格”技巧。在入口和出口边界附近,饱和度梯度变化剧烈,布置较薄的网格层;在内部相对均匀的区域,使用较粗网格过渡。注意不要在入口边界上设置过薄的层以后,却忽略了第一层网格的高度与相邻网格的比例要连续,否则长宽比会很离谱。

5.4 边界压力异常:入口压力“冲出天际”的数学根源

新手最容易碰到的一种情况:入口给定了通量,但跑了几步后入口压力单调上升,最后解到几千万Pa。这种情况多半是边界上的“相对渗透率被锁死了”——入口边界饱和度恒定为设计值,但边界内部的饱和度上升之后,边界层内产生了淤积效果,实际流动阻力陡增。

一个稳健的处理方法是改用“部分渗透”边界,或者将入口通量以分布式源项施加到一个很薄进口缓冲区。这样既能保持流入总量,又不会强制指定边界饱和度。另一个简单粗暴的办法:入口边界直接给定压力,把出口压力压得低一点,形成稳定压差,让流量自己去发展。选择哪种方式,取决于你模拟的是“定流量注水”还是“定压差注水”的现场工况。

5.5 常见问题速查表

症状根本原因首选处理方法
饱和度出现负值或超过1网格太粗/高阶形函数过冲在饱和度前缘加密网格;降低离散阶次
非线性迭代不收敛时间步过大/曲线不光滑减小时间步;检查相对渗透率输入点
入口压力持续暴涨边界饱和度被强制固定改通量边界或用缓冲区弱化约束
含水率曲线随网格剧烈变化数值弥散主导做网格收敛性测试;加密前缘区域
水突破时间偏早数值弥散/网格太粗加密网格;检查入口边界饱和度是否过高
出口附近饱和度异常压力和饱和度边界过约束出口只保留压力边界,让饱和度自动发展
高黏度比条件下严重振荡油水黏度差导致锋面过陡先用低黏度比跑通,再逐步提高
三维模型内存爆炸全耦合雅可比矩阵过大改用分离式求解器,并使用迭代线性求解器

5.6 实验数据与模拟结果的匹配技巧

很多人把实验数据直接丢进Comsol去“硬拟合”,最后哪哪都对不上。我的习惯是,先拿压力降落曲线(岩心两端压差随时间变化)来约束整体渗透率和黏度;再拿出口含水率曲线来校准相对渗透率端点值;最后用产油曲线调整Corey指数。这个顺序不能乱,因为每一层参数对曲线的不同区段具有不同的敏感度。

有一词提醒:实验岩心里往往存在端部效应(capillary end effect),出口附近饱和度会急剧累积,导致实验的突破时间比理论预测晚。这其实是毛细压力边界效应的真实物理表现,不是模型错误。模拟中可以通过在出口加一个“虚拟无毛细效应区域”来处理,或者直接用五点测试法忽略最早期的数据。

说实话,把这两张曲线对上只是一个好的开始。真正验证模型价值的标准是“预测下一轮实验”。比如用模型预测一个不同注水速度下的采收率,如果实验结果和预测趋势吻合,你才可以说自己对这套物理过程真正理解了。

做水驱油仿真这几年,我有一个深切的体会:模型收敛只是及格线,理解指标才能加分。饱和度场、压力场、流速场永远只是工具,真正让工程师认可的,是你能否准确回答“这个方案能多采出多少油”。Comsol里的达西两相流模型,只是把物理方程变成可交互的可视化界面,真正的物理判断力,来自你对相对渗透率曲线的敏感度、对网格依赖性的警觉、以及对边界条件背后物理意义的尊重。

如果你刚开始做,建议先从一个极度简化的均质一维模型入手,把每个步骤的数值表现都看明白,再一步步叠加非均质、重力、裂缝这些复杂度。每一步加进来的时候都做一轮网格敏感性测试,保证你看到的每一个前缘形态都是物理主导而不是数值幻影。把这个流程跑熟了,后面遇到畸形的饱和度场和发散的求解器日志,你能一眼判断问题出在哪层,再也不会因为一个“不收敛”卡掉整个星期的进度。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询