资讯详情

资讯详情

Comsol四场耦合模拟煤层瓦斯抽采:动态渗透率与PDE自定义方程实战

前阵子接了个比较硬核的活儿用 Comsol 做煤层瓦斯抽采的“热–流–固”四场耦合模拟还要把动态渗透率、孔隙率演化、PDE 自定义方程全部揉进一个模型里。这类题目在论文里看别人做觉得也就那么回事真到自己上手建模型的时候坑是一个接一个。这篇文章我把整个建模思路、方程选择、Comsol 实操流程、以及我踩过的那些收敛和单位制的坑一次性梳理出来。适合正在做煤层气、瓦斯抽采、页岩气或者地热储层数值模拟的朋友尤其是那种“刚用 Comsol 三个月、需要从零搭多场耦合模型”的选手。哪怕你没做过瓦斯抽采只看 PDE 模块和动态渗透率的写法这套思路也是能直接搬走的。1. 模型怎么搭四场耦合的物理逻辑与方程体系1.1 四场到底耦合了哪些东西先说清楚这“四场”是哪四个。很多人一听“热–流–固四场”以为是温度、流动、变形三个再加一个凑数的。实际做起来才明白第四场不是凑数而是整个模型能不能反映“增透”效果的关键。我们通常说的四场是应力场煤体受地应力、瓦斯压力变化引起的变形与应力重分布。渗流场瓦斯在裂隙和孔隙中的流动受压力梯度控制。温度场抽采过程中的热交换尤其是注热增透或瓦斯解吸吸热导致的温度变化。损伤/增透场煤体在应力扰动下裂隙萌生、扩展宏观表现为渗透率提升。这一场最难用内置模块直接表达所以往往要用 PDE 模块自定义。这四场不是简单并列而是互相咬合的关系。应力场受孔隙压力和温度影响渗流场依赖渗透率而渗透率又随应力、孔隙率和损伤状态动态变化。温度场既影响煤体热膨胀又改变瓦斯吸附特性和气体黏度。最后这个损伤场直接把渗透率抬升也就是“增透”的物理根源。从工程角度看单纯做“流–固”耦合只能模拟负压抽采下的常规渗流但实际工程里经常要用水力压裂、注热、注气等手段增透。水力压裂带来的裂缝网络在模型里就是损伤区的扩展这部分必须通过一个能随应力状态演化的附加场来刻画。所以四场耦合不是追求方程数量多而是把“增透”这个核心机制真正闭环地表达出来。1.2 控制方程与控制参数我在模型里用了四套方程分别对应上面四个场。这里我按 Comsol 实际建模的顺序写每个方程只给关键形式参数就按典型煤体物性来。应力场我按准静态处理因为抽采过程相对缓慢惯性项可以忽略。方程是动量平衡方程∇·σ F 0其中有效应力 σ σ – α_B·p·Iα_B 是 Biot 系数p 是瓦斯压力。应变里除了力学应变还要叠加热应变 ε_T α_T(T – T₀)。在 Comsol 里这部分最省事直接用固体力学Solid Mechanics接口勾上热膨胀子节点就行。渗流场用的是达西定律Darcys Law接口。瓦斯在裂隙煤体中的质量守恒方程写成∂/∂t (φ·ρ_g (1–φ)·ρ_c·ρ_std·V_L·p/(p P_L)) ∇·(ρ_g·q) 0前一项是孔隙中游离气质量后一项是吸附气质量。q –(k/μ)·∇pk 就是我们要做动态变化的渗透率。这里的关键不是方程本身而是把吸附项写进去后源项会产生很强的非线性求解器经常要花很多功夫才能收敛。温度场我用固体传热Heat Transfer in Solids接口但加了一个对流传热项因为瓦斯在裂隙里流动会带走热量。方程形式为(ρ·C_p)_eff·∂T/∂t C_p,g·∇·(ρ_g·q·T) ∇·(λ_eff·∇T) Q_T其中 Q_T 是解吸热或者外加注热的热源。这里要注意 (ρ·C_p)_eff 必须按煤骨架和瓦斯各自的体积分数加权不能随便填一个常数。第四个场就是自定义 PDE 的损伤场。我用的损伤变量 d 是无量纲量0 代表完整煤体1 代表完全损伤。演化方程是一阶率形式∂d/∂t f(d, ε, σ)具体表达式我放在后面 PDE 模块章节里详细写。这里只说一点损伤驱动项我用的是等效应变和拉伸应变联合判据比单纯用应力更稳定因为应力在某些边界位置容易震荡。1.3 耦合关系与参数传递耦合关系用大白话讲就是一条链瓦斯压力下降 → 有效应力增加、煤体骨架压缩 → 裂隙开度变化 → 渗透率变化 → 反过来影响瓦斯流动。同时温度上升 → 煤体膨胀 → 裂隙受压闭合 → 渗透率下降但注热又会降低瓦斯吸附量、提高气体分子活跃度。在 Comsol 里这些耦合是通过“变量传递”实现的不需要手写全部的方程。具体来说固体力学给渗流场传的是体应变和应力用来更新孔隙率和渗透率。渗流场给固体力学传的是孔隙压力用来计算有效应力。温度场给固体力学传温度增量生成热应变给渗流场传温度用于更新气体密度和黏度。损伤场给渗流场传损伤变量以指数或线性方式叠加在渗透率增强系数上。一开始我做参数传递时习惯用“全局定义→变量”来写比如把渗透率表达式设为 k_eff k0 * exp(Ck * d)。但很快发现如果涉及大量随空间变化的物理量最好还是放在“定义→变量”里用局部坐标和因变量直接算。否则表达式一长查错非常痛苦。2. 动态渗透率与孔隙率模型选择的门道2.1 渗透率为什么是动态的很多初学者第一版模型喜欢给渗透率填个定值比如 k 1e–16 m²然后算完一看压力云图觉得挺合理。但抽采模拟里如果渗透率不变整个模型就是“负压驱动下的普通渗流”根本解释不了工程上的“增透”效果也解释不了抽采后期瓦斯流量衰减变慢的现象。实际上抽采过程中渗透率变化有两个相反方向的机制。一方面瓦斯解吸导致煤基质收缩matrix shrinkage裂隙变宽渗透率上升另一方面有效应力增大导致裂隙闭合渗透率下降。这两个机制竞争前期往往是应力压缩占主导渗透率下降后期基质收缩效应体现出来渗透率可能回升。动态渗透率模型要做的就是把这正负两股力量用数学表达出来。所以我强调动态渗透率不是“锦上添花”的精细修饰而是模型能不能真实反映瓦斯抽采过程的核心。如果你只想看个压力分布定值渗透率够用如果你想跟现场抽采流量数据做对比或者评价增透措施的效果不上动态模型基本没法交代。2.2 常用渗透率–孔隙率子模型对比我总结了三种在 Comsol 里好落地、也有物理依据的渗透率子模型做了一个对比表格方便你根据自己课题的需求选用模型类型核心表达式优点缺点Kozeny–Carmank k₀·(φ/φ₀)³·((1–φ₀)/(1–φ))²有明确物理背景孔隙率变化直接驱动渗透率对裂隙型煤体偏保守容易低估渗透率指数型k k₀·exp(C_k·(φ–φ₀))参数少数学上稳定不会出现负值C_k 需要实验拟合没有统一标准应力–渗透率型k k₀·exp(–3·C_f·(σ_eff–σ_eff,0))直接跟地应力挂钩适合模拟应力敏感储层没法直接表达损伤引起的渗透率跳升我自己最终用的是“指数型 损伤增强”的组合。因为是做增透主题纯 Kozeny–Carman 在损伤区渗透率提升幅度不够纯应力型又没考虑裂隙扩展。组合表达式我在 Comsol 里写成k_eff k0 * exp(Ck * (phi - phi0)) * (1 Cd * d / (1 - d eps))注意后面的 (1 Cd * d / (1 – d eps)) 里面我加了 eps 小量比如 1e–6避免 d 接近 1 时分母爆炸。这个写法在计算稳定性上非常关键很多初学者直接用 d/(1–d)一算就溢出。孔隙率变化模型我用了热–力–损伤联合形式。骨架应变、温度应变和损伤引起的孔隙率增量分别加权phi phi0 alpha_B * (eps_v - eps_v0) alpha_TT * (T - T0) Dd * d其中 Dd 是损伤对孔隙率的贡献系数。最后我还会套一个 tanh 有界变换保证孔隙率落在 0.03 到 0.08 这个合理区间。具体写法phi phi_min (phi_max - phi_min) * (0.5 0.5 * tanh((phi_raw - phi_ref) / width))加了这层“有界化”之后求解器稳定了很多而且后处理画出来孔隙率云图不会出现莫名其妙的极端值。2.3 在 Comsol 中通过变量定义动态演化在 Comsol 里做动态渗透率不需要额外写 PDE只要在“定义→变量”里把渗透率写成随因变量变化的表达式然后让达西定律的材料属性去引用它。我实际用的写法大概是这样的拿任意一个因变量举例k_eff k0*exp(Ck*(phi - phi0))*(1 Cd*dmg/(1 - dmg 1e-6)) phi_eff phi0 alphaB*(solid.epsl - eps_v0) alphaT*(T - T0) Dd*dmg然后在达西定律的材料属性里把渗透率从“用户定义”改成 k_eff。注意 Comsol 6.x 的达西定律界面里渗透率输入框支持直接填变量名不需要每次都去材料节点里改。这里有一个很容易犯的错孔隙率变化表达式里用到了solid.epsl也就是体应变。如果你没有在固体力学接口里开启“计算体积应变”的选项这个变量是不存在的模型会直接报“未定义变量”。所以建完物理场之后我习惯先检查变量列表把需要传递给其他场的变量确认一遍。3. PDE 模块怎么用自定义方程的正确姿势3.1 三种 PDE 形式与适用场景Comsol 的 PDE 模块一共有三种形式系数型 PDE、通用型 PDE、弱形式型 PDE。系数型 PDE 的通用模板是ea·∂²u/∂t² da·∂u/∂t ∇·(−c·∇u − α·u γ) β·∇u a·u f这个形式适合大多数标准扩散–反应方程系数填写直观像热传导、扩散方程都能直接套。通用型 PDE 更自由守恒通量 Γ 和源项 F 都写成向量的形式适合非线性很强的方程。弱形式型 PDE 最底层、最灵活但写起来门槛高调试也费劲非必要不建议新手碰。对于损伤演化这种“一阶时间微分 强非线性源项”的方程我用的是通用型 PDE。因为源项 F 可以直接写成分段函数或者带门槛的表达式比如损伤只在应变超临界时才增长这在系数型 PDE 里反而不容易写清楚。3.2 自定义一个损伤/增透场一步步来我在模型里加了一个因变量叫 dmg。在“通用型 PDE”节点的设置里主要填这几项守恒大通量的散度项 Γ因为损伤演化里没有扩散项Γ 设成 0。源项 F损伤驱动写成分段有界的形式。阻尼系数 da设成 1让方程变成 ∂d/∂t F。驱动项我用的表达式大致是这样F (eps_eff - eps_cr) * k_d / (1 k_d * (dmg)^2) * (dmg 1)拆开解释。(eps_eff – eps_cr)是超临界应变只有超过损伤阈值才起作用。k_d是损伤演化速率。分母里的(1 k_d * dmg²)是一个负反馈项防止损伤无限增长相当于材料应变软化效应。最后的(dmg 1)是布尔量保证损伤变量被硬截断在 0 和 1 之间。在 Comsol 里“比较运算符合法吗”这个问题常有人问其实是合法的。布尔表达式会被转换成 0 或 1作为乘数非常好用。边界条件方面损伤场一般不用刻意设置边界条件。如果边界上确实需要约束我用狄氏边界设定 dmg 0表示远场完好煤体不发生损伤。内边界也就是钻孔附近不设约束让损伤自由发展。3.3 与内置物理场接口的交互方式自定义 PDE 建好之后它不是孤立存在的需要从固体力学和温度场拿驱动量再反过去影响渗透率。这个过程在 Comsol 里的实现方式就是在源项里直接引用其他接口的变量。比如我要在损伤演化方程里用体应变就直接在 F 表达式中写solid.epsl。要引用温度直接写T前提是固体传热接口的因变量名是T。要引用压力写p这是达西定律接口的默认因变量名。反过来渗透率表达式里引用 dmg 也一样直接。这种双向引用在 Comsol 里不需要额外建耦合节点靠变量名“碰”就行了。但也正因如此变量命名冲突是一个巨大的隐患。比如我把损伤变量命名为d结果和达西定律里的某个默认变量冲突直接导致表达式被覆盖。所以我强烈建议自定义场用带前缀的变量名比如dmg、phi_d。在“变量”节点里命名因变量时别偷懒。吃过的亏太多了变量冲突查起错来真的让人头大。3.4 PDE 模块的常见报错与排查思路PDE 模块最容易出的问题有三类。第一类是“因变量在边界上未定义”。这个多是因为边界条件没设全。通用型 PDE 默认不带边界条件必须手动加。如果某条边界没加任何条件Comsol 会认为它无通量但有些版本在部分网格情况下会报错。我的习惯是给所有外边界统一加一个狄氏条件 dmg 0内边界不加省心。第二类是“源项单位不匹配”。通用型 PDE 默认单位是“1”如果你在源项里写了带物理量的表达式单位检查会弹出警告。这个警告不一定导致计算失败但会影响后处理单位所以我常在模型设定里把 PDE 因变量的单位改成“1”然后在源项里用纯无量纲组合。第三类是“求解器无法初始化”。经常是初始值没设好。损伤场初始值设成 0 是最安全的。如果设成某个非零值和边界条件冲突的话第一步迭代就容易发散。4. 实操流程从几何到后处理的完整路线4.1 几何建模与网格控制我做的是二维平面模型把抽采钻孔简化成一个圆形孔洞直径 0.1 m煤体范围取 30 m × 30 m。这个规模在二维模型里不算大但对瓦斯抽采模拟来说足够观察压力漏斗和损伤区扩展的规律了。几何很简单但网格是第一个坎。孔内边界压力梯度极大近孔区必须加密否则求解出来压力场和渗透率场会出现锯齿状振荡。我用的是自由三角形网格孔边最大单元尺寸取 0.01 m往外逐步放宽最外层取 1 m。整体单元数量大约 4 万到 6 万这个规模对个人电脑来说压力不大一分钟能算好几步。如果你后续要扩展到三维网格策略必须改钻孔附近用扫掠网格或边界层网格别再用自由三角形直接拉。三维的自由 tetrahedral 单元在孔边界附近会产生大量低质量单元收敛性会明显变差。4.2 物理场定义与耦合项设置物理场按这个顺序建立比较顺畅先用固体力学接口材料设成煤体线弹性弹性模量设 2.8 GPa泊松比 0.34Biot 系数 0.8。热膨胀子节点里填热膨胀系数 3e–5 /K。边界上外边界固定位移孔边界自由。接着加达西定律接口孔隙率引用前面写的 phi_eff渗透率引用 k_eff。初始瓦斯压力设 1 MPa这里注意用绝对压力钻孔内壁压力设 50 kPa模拟抽采负压。然后加固体传热接口初始温度 303 K孔边界给对流换热条件或者如果做注热增透直接给定温 373 K。我现在这个项目是模拟注热辅助抽采所以孔边界设成了高温热源。最后加通用型 PDE 放损伤场。四个物理场在“多物理场耦合”里不一定要显式添加耦合节点因为变量引用已经完成了耦合。但我还是会加一个“温度–固体力学”热膨胀耦合让界面清爽一些。这里有个心得多物理场耦合节点能加就加哪怕变量引用已经隐含了。因为 6.4 版本的物理场界面里耦合节点会生成一个清晰的依赖关系图后面给导师或者审稿人讲模型的时候这个图非常有用。4.3 时间步长与求解器策略抽采模拟的时间尺度是以天为单位但损伤演化刚开始的瞬间变化很快。所以我用瞬态求解器时间步长序列设为0, 1, 5, 10, 30, 60, 120, 600, 3600, 7200, 43200, 86400 秒也就是从秒级一直拉到一天。这样做的好处是前期损伤快速增长时能捕捉到细节后期稳定渗流时不会浪费算力。求解器我用的是全耦合的 MUMPS 直接求解器最大耦合迭代数设成 50阻尼因子初始值 0.9。如果模型规模超过大概 30 万自由度再考虑分离式求解器。直接求解器内存占用大一点但对强非线性问题比迭代法省心很多不容易莫名其妙地发散。不收敛的时候我第一个检查的是时间步是不是太大。把初始时间步缩到 0.1 s多半能救回来。第二个检查的是损伤源项的量级。如果 k_d 取值太大比如超过 1e–2源项会非常刚硬一步跨过去就震荡。建议先把 k_d 调小两个数量级试试等模型跑通再逐步放大。4.4 结果解读怎么判断增透效果算完之后我最关心的不是漂亮的压力云图而是四类结果第一是渗透率比值的空间分布也就是 k_eff/k₀ 的云图。这个直接反映了增透区域的范围和强度如果损伤区边缘渗透率比达到 3 到 5 倍说明模型里增透机制是有效的。第二是钻孔瓦斯流量随时间的变化曲线。做法是对孔边界做通量积分。流量初期高、后期衰减快是正常现象如果导入现场数据这条曲线就是模型校准的核心目标。第三是损伤区半径的演化。我通常在结果里画 dmg 等值线比如 dmg 0.3 对应的半径看它随时间的扩展距离。这可以跟现场压裂裂缝半长做对比。第四是孔隙率变化云图。前面那个有界化处理保证了云图看起来平滑如果看到局部出现孔隙率跳变到极值大概率是 tanh 里 width 参数调太小或者驱动项有数值振荡。5. 常见问题与避坑指南5.1 收敛问题振荡、发散与假收敛我遇到的第一个大坑是最开始用定渗透率跑一切正常换成动态渗透率之后第 10 步开始残差曲线就像心电图一样上下跳。查到最后是孔隙率表达式里solid.epsl的数值噪声被放大了。体应变在孔边界附近有集中微小的应力震荡传到渗透率再传到气压形成一个正反馈环。解决办法是给应变做局部平滑。具体做法是在“定义”里用smoothstep或者加一个高斯滤波的积分算子但 Comsol 里最直接的办法其实是控制网格的畸变度和时间步长。把孔边单元尺寸从 0.005 m 放大到 0.01 m反而收敛更好。很多人以为网格越密越好其实在多场耦合里过度加密会让局部高频振荡放大导致整体收敛变差。另一个经验是如果残差一直降不到预设阈值别死磕容差。把求解器容差从 1e–6 放宽到 1e–4在工程模拟里完全可以接受算出来的流量曲线几乎没差别。5.2 渗透率负值、孔隙率溢出我见过别人的模拟结果里渗透率云图出现负值物理上这完全说不通。原因往往是孔隙率变化模型里用了线性外推没有任何约束体应变一大孔隙率算出来就小于零了。渗透率指数模型虽然本身不会为负但 Kozeny–Carman 形式在孔隙率接近零时会出现剧烈的非物理解。我的做法是在渗透率和孔隙率表达式外面各套一层有界函数。比如k_safe if(k_eff k_min, k_min, if(k_eff k_max, k_max, k_eff))Comsol 里if语句是支持的嵌套使用没问题。k_min 我设 1e–18 m²k_max 设 1e–12 m²保证计算鲁棒性。虽然加了截断但正常情况下表达式根本不会触到上下界所以不影响物理正确性只是给求解器上了一道保险。5.3 单位制与变量命名冲突Comsol 的单位制看起来是全自动的但自定义 PDE 和自定义变量会悄悄破坏这个自动机制。比如达西定律里渗透率的国际单位是 m²但很多教材给的是 mD1 mD 约等于 9.87e–16 m²。填数值时一旦搞错整个压力场都会失真。更隐蔽的是自定义变量导致单位不一致。比如我在“变量”节点写了一个表达式k_enhance 1 dmg * 5这个 5 没有物理单位但后处理时 Comsol 会用默认单位去寻找量纲结果经常弹出一堆单位警告。我的建议是在“模型设定→单位”里把自定义因变量的单位明确写成“1”自定义变量的单位也显式指定。别嫌麻烦后面省下的查错时间绝对值得。5.4 版本差异与性能优化建议Comsol 6.4 在 PDE 模块的界面和求解器上有一些改进但核心操作跟 6.0 基本一致。一个值得注意的变化是 6.x 里物理场节点的图标和右键菜单重新整理过刚升级的时候很多人找不到“通用型 PDE”入口。实际上在模型树里添加物理场时筛选框输入“PDE”就能看到通用、系数、弱解三类。性能优化方面如果你的模型算到三维而且单元数超过 50 万强烈建议开分离式求解器先算渗流场和温度场再算损伤场每个场单独迭代。全耦合在这个规模下内存吃得太厉害普通 16G 内存的机器很容易算到一半直接崩掉。我自己还试过用 Matlab 控制 Comsol 批量修改参数这对参数扫描特别有用。脚本里改一下渗透率系数或者抽采负压循环提交比在 GUI 里手动点一套时间步省太多时间。官方有 Livelink for MATLAB接口很成熟热词里频繁出现的“用 MATLAB 控制 Comsol”就是这个路子。6. 一点个人体会这个模型我前后改了大概三周最后跑通的那一刻最让我感慨的不是四场耦合有多复杂而是所有物理量之间的互动远比直觉上预想得更敏感。比如温度场加进来之后近孔区的渗透率变化比单纯流–固耦合的结果要平缓得多原因是热膨胀抵消了一部分压降引起的压缩。这在工程上是有实际意义的注热增透不是“高温把煤烤裂”这么简单而是温度和应力两个机制相互平衡后的净效果。我个人的建议是从少场耦合开始搭模型先用“流–固”两场验证网格和参数再把温度场挂上最后才加 PDE 损伤场。一次把四场全上出问题的时候你根本分不清是哪个环节在捣乱。我现在养成了每加一个物理场就保存一个版本的习惯版本号从 v1 排到 v8每个版本都能跑出合理结果这样后续改参数做敏感性分析也有据可查。最后再分享一个小技巧做四场耦合之前一定先做一遍“手动量纲核对”。用最简单的工况恒定温度、恒定渗透率算出来钻孔流量大概是多少然后用达西公式手算一遍对比。如果这一步能对上后面所有动态耦合都是在有物理意义的基准之上做文章。算不准这一步模型再花哨其结果也没有工程价值。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →