ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

多孔介质水驱油模拟:Comsol两相达西建模与验证

多孔介质水驱油模拟:Comsol两相达西建模与验证 多孔介质里的水驱油问题我见过太多人第一步就走错了方向。上个月一个做三次采油方案的朋友发来一张饱和度云图说他在Comsol里用达西定律接口算水驱油跑了十几个小时出来的含水率曲线怎么看怎么怪。我让他把模型文件发过来一看果不其然——用的是单相达西接口油和水共用一个压力场饱和度这个变量压根就没被求解。这是论坛和工程交流群里出现频率最高的典型误区多孔介质多相流和水驱油模拟的核心是用两相达西模型同时求解压力场和饱和度场而不是在单相流计算结果后面硬凑一个含水率。这篇就把这件事彻底讲透。达西两相流模型在Comsol里怎么搭、控制方程是怎么回事、油水物性和相渗曲线怎么给、边界条件如何选、收敛问题怎么排查以及最后怎么用经典的Buckley-Leverett解析解给数值模型验货。目标读者是正在接触水驱油、化学驱、储层渗流数值模拟的研究生和工程师也包括想用Comsol做多孔介质多相流但还没理清接口逻辑的小白。照着这个工作流走一遍你至少能避开我踩过的大部分坑。1. 水驱油到底在算什么先搞清楚饱和度场和压力场的耦合关系1.1 一个注采周期里的四个连续过程水驱油不是把水灌进去那么简单。从工程视角看注入井向储层注水水在孔隙介质中向前推进把孔隙里的原油往生产井方向赶整个过程可以拆成四个连续阶段第一注入水从井筒出发在近井地带形成径向驱替逐步扩大波及范围第二油水两种流体在孔隙中同时流动由于黏度差异和相对渗透率的作用前缘并不是一个干净的活塞面而是形成一段饱和度逐渐过渡的混合带第三水前缘推进到生产井之前这段时间产出的几乎全是原油工程上叫无水采油期第四前缘突破生产井水开始随原油一起产出含水率快速上升产量递减直到经济极限含水率后关井。这四个阶段里真正决定模型好坏的是第二个。非活塞式驱替意味着在任何时刻、任何空间位置油水两相都同时存在于孔隙中各自占据一部分孔隙体积。这就引出了全文最核心的一个概念——饱和度。含水饱和度s_w水占孔隙体积的百分比和含油饱和度s_o加起来等于1正是这个饱和度场的空间分布和时间演化决定了注入水从哪条路径推进、推进多快、最终波及到多大范围。1.2 为什么要用两相达西模型而不是单相流单相达西定律接口只求解一个压力变量它描述的是一种流体在孔隙介质中的流动。水驱油虽然看起来也是水在流、油在被推动但孔隙里同时存在两种互不相溶的流体时事情的性质变了油和水的流动互相阻碍、互相挤占空间。用一个类比来说单相流像一根水管里只通一种液体而两相流像一块海绵里同时吸了水和油——你要知道的不只是压力梯度是多少还要知道水和油各自占据了多少孔隙、在哪些孔隙通路里更容易流动。因此两相达西模型里出现了单相流没有的变量组合除了压力场p还有一个饱和度场s_w。更重要的是每个相的实际流动能力不再是绝对渗透率k那个常数而是绝对渗透率乘以一个随饱和度变化的相对渗透率k_rw(s_w)、k_ro(s_w)。油相和水相抢通道的程度完全靠相渗曲线来描述。没有这个耦合关系你在单相流结果里后处理出来的含水率实际上只是根据某种简单比例推算的值缺乏物理依据而且地下真实过程中的前缘推进、剩余油分布、见水时间都算不出来。这就是为什么标准的做法是使用多孔介质流模块下的**两相达西流Two-Phase Darcys Law**物理场接口而不是达西定律接口。2. 控制方程与接口选择的对应关系Comsol里那套数学符号的来龙去脉2.1 质量守恒与达西速度油、水两相各自的运动方程两相达西模型的数学骨架不复杂就是对每一相写质量守恒然后把达西速度代进去。对油相下标o和水相下标w各自满足∂(φρᵢsᵢ)/∂t ∇·(ρᵢuᵢ) ρᵢqᵢ, i w, o其中φ是孔隙度ρᵢ是相的密度sᵢ是相的饱和度qᵢ是源汇项注入或采出。每相的速度由达西定律给出uᵢ -(k_abs · k_ri(sᵢ) / μᵢ) · ∇(pᵢ ρᵢgz)注意这里的k_ri是相对渗透率它强烈依赖于饱和度而不是常数。两个相的速度不相等也不成简单的比例关系——这正是油水前缘能够形成非活塞式推进的数学根源。在Comsol的两相达西流接口里默认的处理方式是把油相压力p作为求解变量水相压力通过毛管压力换算得到p_w p_o - p_c(s_w)饱和度方面只求解水相饱和度s_w油相饱和度用s_o 1 - s_w补出来。这样未知量是两个方程也是两个水相质量守恒和总质量守恒或油相质量守恒方程组恰好封闭。这个方程体系让我想起不少刚开始接触的人容易犯的迷糊他们以为多相流就得多加几个达西速度方程。其实在多孔介质里边惯性项通常被忽略宏观速度直接用达西定律给出不需要求解动量方程。这和自由流动中的N-S方程完全是两套逻辑千万不要把CFD里那套思路直接搬过来。2.2 相对渗透率与毛管压力模型能否跑通的关键两件套有了守恒方程还不够方程里的k_rw、k_ro、p_c必须给定为饱和度的函数这些函数关系决定了模型的物理行为。这三件套是全模型最关键的非线性输入。相对渗透率曲线可以用实验数据插值也可以用解析模型。工程上最常见的两种Corey型相渗模型每个相给一个端点相对渗透率和一个幂指数。Van Genuchten-Mualem模型由毛管压力曲线积分推导相渗曲线适合孔隙结构较均匀、以毛管力为主导的介质。毛管压力p_c(s_w)描述的是油水界面上两相的压力差。在亲水岩石里水相倾向于占据小孔隙油相占据大孔隙两项压力并不相等而这个差值会随饱和度升高而降低。Comsol里毛管压力可以给经验公式也可以用查表函数。做水驱油模拟时如果忽略毛管压力模型的压力场会出现系统性偏差尤其是低渗透储层毛管力对前缘形态的影响非常大。我个人的习惯是正式计算前先单独画一下三件套曲线检查端点饱和度和端点渗透率是否合理。如果k_rw在残余油饱和度处不为0或者p_c在束缚水饱和度处没有趋近一个有限值后面求解器不收敛基本是板上钉钉的事。2.3 从偏微分方程到Comsol接口的映射关系在Comsol 6.x版本里打开模型向导选择多孔介质流模块Porous Media and Subsurface Flow在流体流动类别下能看到达西定律、理查兹方程、两相达西流等接口。做水驱油一定要选两相达西流Two-Phase Darcys Law。这个接口打开后因变量是孔隙压力p和水相饱和度s_w两个标量场。接口内部已经帮你写好了上面那组偏微分方程你要做的只是输入物性参数、相渗函数和边界条件。换句话说Comsol把推导过程藏在了背后但如果你不理解前面那套方程就不知道它为什么有些地方叫你填油相压力而另一个地方又叫你填毛管压力曲线。顺便区分一下相邻接口的使用场景理查兹方程是单变量方程适合气-液两相中气压恒定的非饱和渗流比如土壤水运动但严格说不能直接用于油水两相都显著流动的水驱油问题。如果非要在理查兹方程里做水驱油本质上是把油相当成了不动的背景相这只在气驱或极低含水饱和度阶段才近似成立一般不建议用在常规水驱油动态预测里。3. 物性参数处理孔隙度、渗透率、相渗曲线的工程化赋值3.1 非均质渗透率的插值与平滑处理真实储层的孔隙度和渗透率不是常数。测井解释得到的渗透率剖面通常沿井深逐点给出用测井曲线、地质建模结果或者岩心实验数据都能驱动Comsol模型。在Comsol里给这种空间分布参数赋值常用做法是定义插值函数把坐标-渗透率数据点做二维或三维插值然后在物理场的渗透率输入框里引用这个插值函数。需要注意三点数据坐标匹配几何坐标和测井深度坐标必须统一基准面搞错的话整个压力场都是扭曲的。平滑处理原始测井数据噪声很大直接插值会在局部产生渗透率尖峰导致该处流速异常。建议先做滑动平均或者高斯滤波保留大尺度非均质性、滤掉小尺度噪声。我一般用组数较少的样条拟合代替逐点插值效果比直接加载原始数据稳得多。各向异性渗透率是张量水平渗透率和垂向渗透率通常不同比例从几倍到几十倍不等。二维模型里要用张量形式填三维模型尤其要仔细否则重力分异和层间窜流会被严重低估。3.2 Corey相渗模型和Van Genuchten模型的参数标定Corey相渗模型的形式如下k_rw k_rw⁰ · (S*) ^ N_w k_ro k_ro⁰ · (1 - S*) ^ N_o S* (s_w - s_wr) / (1 - s_wr - s_or)其中s_wr是束缚水饱和度s_or是残余油饱和度k_rw⁰、k_ro⁰是端点相对渗透率N_w、N_o是幂指数。典型砂岩油藏的经验范围可以参考下表参数常见范围说明s_wr0.15~0.30束缚水饱和度来自岩电或相渗实验s_or0.20~0.35残余油饱和度水驱后残余油多少k_rw⁰0.1~0.6水相端点相渗反映水在残余油条件下的流动能力k_ro⁰0.8~1.0油相端点相渗N_w2~4水相Corey指数N_o1.5~3油相Corey指数这些参数最好从岩心驱替实验里拟合没有实验数据时用上表的常见范围做敏感性分析也可以。Van Genuchten模型在Comsol里可以直接选它和毛管压力曲线共用一套参数m、α好处是曲线光滑、处处可导对求解器的非线性处理友好。Corey模型虽然简单但在端点处导数不连续有时候会引发边界附近的迭代振荡这时候需要稍微把端点区域处理得圆滑一点。3.3 初始状态与平衡条件不要让模型从一场灾难开始初始条件对瞬态模型的收敛影响往往被新手忽略。水驱油模型的初始饱和度通常是束缚水饱和度s_wr油相饱和度相应为1 - s_wr这意味着初始状态下水相相对渗透率为0模型里存在不连续。如果你直接把初始值设成s_w s_wr然后把求解器默认的从初始值开始跑瞬态很多情况下第一步就会报找不到一致的初始解。原因在于注入边界上水饱和度为1而体内部饱和度是s_wr这个间断在t0时刻就存在全隐式求解器需要在一个时间步内处理一个极陡的前缘数值上非常吃力。稳妥的做法是分两步走第一步做一个稳态计算只求压力场把初始压力分布定为油相压力饱和度初始值用一个光滑过渡的表达式比如在注水井附近给一个很小的过渡带而不是让边界上直接跳变。实际建模中我发现把初始饱和度设成s_wr 0.001这种小偏移并配合初始值里的一致性初始化选项收敛效果明显好于死磕s_wr的精确值。模型物理上当然要精确但数值上留一点余量属于常规操作。4. 建模实操一维水驱油模型的完整搭建流程4.1 几何与物理接口设置我的建议永远是从一维模型开始。一维水驱油虽然看起来简单却是验证整个物理概念、方程耦合、数值稳定性和解析解对照的最廉价载体。等一维算通了再往二维、三维扩。几何就是一个长度L的线段比如L1000 mx0是注入端xL是生产端。全局参数先定义好L 1000 [m] % 储层长度 phi 0.25 % 孔隙度 K 100 [mD] % 绝对渗透率注意单位换算 mu_w 1 [mPa*s] % 水相黏度 mu_o 10 [mPa*s] % 油相黏度 rho_w 1000 [kg/m^3] rho_o 850 [kg/m^3] p_out 1 [MPa] % 生产井压力 q_inj 0.5 [m/day] % 注入速率折算到截面积Comsol里填渗透率时注意渗透率单位1 D ≈ 0.9869e-12 m²100 mD就是约0.1e-12 m²。我见过不少模型跑出来的结果差了几个数量级追根溯源都是单位换算出了问题。建议在参数表里直接用 [mD] 这种具有明确单位的写法Comsol会自动换算尽量别手算。物理场选两相达西流几何是1D域上不需要额外操作直接设置孔隙度φ、绝对渗透率K、油水两相的密度黏度、相对渗透率模型和毛管压力模型即可。4.2 注入端与产出端的三种边界方案边界条件的选取直接决定你模拟的是注采井网里的哪一口井。常用方案有三种方案注入端生产端适用场景定流量-定压力给定水相通量注入速率定压力最常见模拟一口注水井对一口生产井定压-定压给注入压力较高值定压力较低值模拟恒定井底压力差更接近实际配注混合控制水相通量与饱和度约束定压力出流模拟实际井控条件或复杂井网无论选哪种方案都必须给水相饱和度一个边界条件注入端是水所以s_w 1或者说水相饱和度固定为1注入的是纯水生产端如果压力固定饱和度通常选出流Outflow条件让饱和度自由流出不强制赋值。指定注入速率时注意是表观速度达西速度还是注入量折算速度。一维模型里如果q_inj 0.5 m/day是真实推进速度的话边界的通量应该是φ · q_inj因为孔隙体积才是水能占据的空间。这个混淆导致的错误和上面单位换算错误一样常见。4.3 瞬态研究的配置与求解器选择研究类型选瞬态。时间范围建议从0到100天左右步长先给粗略的比如每天输出一个点等模型稳定了再加密。更关键的是求解器设置。我推荐先从默认的全耦合求解器开始线性求解器用PARDISO或者MUMPS两者的鲁棒性在这个问题上都够用。如果默认配置能算通就别乱动。但如果出现不收敛优先做两件事第一在求解器配置→时间步进里把BDF阶数默认值改为1一阶向后差分虽然精度会略降但稳定性大幅提升尤其适合饱和度前缘这种陡峭移动问题。第二把最大时间步长限制在可接受范围内避免求解器为了冲目标时间而跨过前缘导致振荡。用默认自适应用步长最省心但初始步长最好给一个很小的值比如1e-3天让第一轮迭代从平滑状态起步。物理场接口里的流线扩散Streamline Diffusion稳定化建议打开。这个稳定化项给饱和度方程加一点数值扩散会把前缘抹圆一点但换来的是迭代稳定。后面再靠网格细化来补偿弥散。5. 网格细化、数值稳定性和收敛调试实录5.1 饱和度前锋的数值弥散现象与根源算完第一次瞬态后你大概率会看到饱和度前缘不像教科书上的陡峭台阶而是一条平滑的过渡带。这个抹平叫数值弥散根源在于空间离散产生了虚假扩散和物理上的毛管力作用叠加在一起,让你分不清到底是数值误差还是真实物理。判断方法很简单把网格加密一倍重新算如果前缘位置和过渡带宽度明显变化说明之前的结果被数值弥散主导反过来如果加密后结果基本不变那过渡带是真实的物理现象。我在实际中确认了一维水驱油前缘这类陡峭移动波前用均匀网格要得到可接受的结果每个网格单元长度最好满足局部Courant条件也就是时间步长Δt和网格尺寸Δx与真实流速的关系大致满足Δt ≤ φ · Δx / u_totu_tot是总的达西流速。Courant数控制在1以下比较稳妥超过2~3时前缘会出现明显的阶梯状振荡。更精细的做法是利用Comsol的自适应网格细化或网格重划分功能让前缘附近始终保持高分辨率。一维问题计算量小可以直接给均匀细网格但二维三维必须考虑局部加密尤其是注入井附近和前缘待通过的路径上。5.2 从振荡到收敛阻尼因子和时间步长的配合饱和度越界出现负值或者大于1是最常见的失败模式根源往往是全耦合牛顿迭代在你给出的初始猜测下震荡过度。多孔介质两相流是非线性很强的双曲型方程前缘附近雅可比矩阵变化剧烈牛顿法如果不加约束第一次迭代就可能跑飞出物理范围。修复思路我按有效程度排序降低时间步长把初始时间步和最大时间步都调小让前缘在每个步长内只移动不到一个网格这是最直接有效的手段。打开阻尼在全耦合求解器的设置里有一个阻尼因子选项默认是自动如果振荡严重手动把阻尼因子上限限制在0.7左右牺牲一点速度换稳定性。降低相对容差默认1e-3可以收紧到1e-4但别低于这个太多否则时间步长会被压缩到难以接受的短。换分离式求解器把压力和饱和度分开求解每个子步只处理一个场虽然整体迭代次数会变多但对于非线性强烈的多相流问题往往意外地稳。我自己调试时有个固定的排查链路先看第一个时间步是否收敛很多问题其实在第一步就暴露了然后看饱和度场有没有负值有负值就回到网格和稳定化设置再对比时间输出点的含水率曲线是否平滑出现锯齿说明时间步长过大或阻尼不足。这个顺序能省掉大量盲目调参的时间。5.3 一阶到二阶格式精度与稳定性的取舍Comsol里两相达西流默认采用线性拉格朗日单元P1无论是压力场还是饱和度场。P1格式耗散偏大前缘会被抹得更宽但极其稳定适合新手起步。如果你追求精度可以把压力场升级到P2饱和度保持P1。压力场用二阶单元能改善压力梯度的计算精度而饱和度本身是个强对流问题二阶格式在没有流线扩散的情况下容易产生寄生振荡。折中方案是压力P2、饱和度P1配合流线扩散稳定化。我在自己的二维模型中一直用这个组合效果比全P1好也比全P2稳定。另外一个容易被忽视的精度点是毛管压力项的离散。如果毛管压力在饱和度低端变化极陡即dpc/ds_w数值很大那么即使空间格式没问题饱和度的微小误差也会被毛管压力项放大。这时候可以在毛管压力函数两端做截断或平滑处理避免导数尖峰。6. 结果验证用Buckley-Leverett解析解给数值解照镜子6.1 见水时间和无因次产液量的快速校核数值模型建立起来后第一个要回答的问题不是结果漂不漂亮而是结果对不对。对水驱油一维问题最权威的对照就是Buckley-LeverettB-L理论解。B-L解基于五个假设一维流动、不可压缩流体、忽略毛管压力、油水性质恒定、驱替为活塞式的极限情形。由分流量函数f_w(s_w)的概念出发可以推导出饱和度波前的传播速度v_s (u_tot / φ) · (df_w/ds_w)也就是说饱和度等于某个值的点以恒定速度向前推进。由此可以算出前缘突破时间。在Comsol里算完模型后把生产端含水率突然上升的时间点t_bt和按B-L公式计算的突破时间对比。如果两者误差在10%以内说明数值模型抓住了核心物理误差超过30%基本可以断定相渗曲线输入、绝对渗透率或边界通量某个环节出了问题。实际中B-L和无毛管压力数值解的区别只在于毛管压力项因此一维对比时可以把毛管压力设成0跑一版数值解这是最严格的对照。我通常的做法是跑三个版本含毛管压力、不含毛管压力、B-L解析解三者放在同一张图上物理含义一目了然。6.2 含水率曲线的工程解读含水率曲线f_w随时间变化是水驱油工程上最关心的输出之一。标准曲线形态分三段无水采油段含水率接近0产量稳定对应前缘未突破阶段。突破点含水率陡然上升这是注采管理的关键节点。高含水段含水率缓慢爬升趋近90%以上剩余油采收率提升进入递减阶段。在Comsol的后处理里可以直接对生产端边界做边界积分求水相达西速度占总通量的比例得到含水率对时间的关系。我建议把含水率、累产油量、累注水量三条曲线放在同一张图上一起解读。单看含水率容易忽略产量递减的速率单看累产油又容易看不到突破时刻。6.3 从一维到二维/三维扩展建模的注意点一维算通之后二维模型会带来三个新麻烦。第一个是井的处理。真实井在二维模型里是个点点源处的达西速度趋近无穷必须用等效井半径来正则化或者把井区域附近的网格做极度细化。第二个是重力效应。二维纵剖面模型里油水密度差会导致水在底部舌进油在顶部被优先驱替这时初始压力必须按静水压力梯度设置否则重力和毛管力不平衡会导致非物理的初始流动。第三个是网格量。二维模型哪怕只有几百米见方前缘追踪所需的局部细网格也可能让自由度达到几十万这时候前面说的分离式求解器和自适应时间步就显得更重要了。水合物相关的模拟也值得提一嘴水合物分解过程的渗流通常涉及气、水、水合物三相甚至四相两相达西模型不能直接处理需要在质量守恒方程里加入分解反应源项或升级到多组分多相流接口。基础的两相水驱油建模是理解这些复杂问题绕不开的第一步。7. 参数化扫描与批量计算让Comsol真正成为产能预测工具7.1 参数化扫描注入速率与地层渗透率的影响单次算完只是入门真正的工程价值在于批量分析注入速率多大时见水时间最长渗透率下降对累产油量影响多少在Comsol里把注入速率、渗透率、残余油饱和度等定义为全局参数后可以在研究→参数化扫描里一次性扫描多个取值。我通常扫描的参数组合包括注入速率0.2~1.0 m/day、绝对渗透率10~500 mD、油水黏度比5~50。扫描完成后用结果→一维绘图组把不同参数下的含水率曲线叠在一起就能快速看出哪个参数对见水时间最敏感。这种敏感性分析在写方案汇报时特别有用你能直接告诉领导注入速率提高一倍无水采油期缩短了约40%而不是给对方看一堆模棱两可的云图。7.2 Python/Matlab控制Comsol批处理的工作流当你需要在几十组参数间反复运算或者想把Comsol的模拟嵌入到自己的优化脚本里时就该考虑批量控制。Comsol官方提供了两个路径LiveLink for MATLAB在MATLAB命令窗口里用mphstart、model mphopen(...)、model.study(std1).run()这类命令控制模型运行适合已经把核心计算流程搭在MATLAB里的团队。Python控制Comsol 6.x至少可以用Java API或外部接口社区里也有成熟的mph库例如基于MPh来加载模型、修改参数、运行研究和导出数据。在Linux服务器上跑无界面批量算例通常用Comsol Server加上客户端脚本的方式模型文件提前构建好脚本只负责改参数、提交计算、收集结果。无论是MATLAB还是Python我建议的协作模式是先在图形界面里把模型搭通确认所有要改的参数都已经定义为全局参数再导出模型文件或保留.mph模型然后写脚本循环修改参数运行。千万不要在Python里写一大段几何建模代码从头搭建模型——调试成本高而且Comsol的几何内核在无界面环境下有时会很别扭。7.3 常见的模型验证陷阱与经验建议最后把我的血泪经验集中列一下每条都是我实际遇到过并花了不少时间解决的单位体系混乱是最隐蔽的坑。压力用MPa/s还是Pa/s、时间用day还是s、渗透率用mD还是m²混用后结果会让人完全摸不到头脑。建议所有全局参数统一用Comsol自带单位系统输出时再转换不要自己手动换算。毛管压力方向。毛管压力定义p_c p_o - p_w的时候亲水岩石的p_c随含水率上升而下降。方向填反了模型会表现出水被油吸走这种完全不物理的行为而且往往不会直接报错只会在结果里露出一丝诡异。初始饱和度不均衡。一维水平模型忽略重力时这个问题不大但二维/三维里初始饱和度至少要做重力平衡让p_o和p_w满足静水压力梯度这样模型一开始就处于准平衡态不容易在首步产生虚假流动。不检查通量平衡。算完后可以用后处理求整个边界上的水相通量积分和理论注入量对照。如果守恒误差超过几个百分点多半是网格在边界附近太粗不是物理方程有问题。水驱油模拟这件事难的不是Comsol操作本身而是对饱和度-压力-物性非线性耦合的理解。你一旦把一维两相达西模型在Comsol里跑通并和解析解对上了后面二维三维复杂的井网模拟、聚合物驱、表面活性剂驱本质上都是在这个骨架上增加源项和附加物理思路一脉相承。按照上面的工作流走一遍你大概能省下我当年自己摸索的两周到一个月时间。
返回列表