COMSOL分形粗糙裂隙建模:从几何到渗流力学仿真
2026/9/15 2:27:08 网站建设 项目流程

裂隙岩体里的渗流、力学和传热问题,搞数值模拟的同行应该都有体会:最难的不是求解器和方程设置,而是几何模型怎么建。天然裂隙表面不是两块光滑平板,它带有明显的粗糙起伏,而正是这些起伏直接控制了裂隙的渗流开度、接触刚度和剪切强度。以前很多人为了省事直接画两个平行平面来模拟裂隙,结果算出来的渗透率、开度变化跟室内试验数据差了好几个量级,这就是几何失真带来的误差。COMSOL Multiphysics 加上分形理论,可以在这个问题上给出一个比较靠谱的解法,用分形系数控制粗糙面的生成,既贴合天然裂隙的自仿射特征,又能方便地做参数化扫描,研究粗糙度对渗流和力学行为的影响。这篇文章就把我从几何生成到仿真计算完整梳理一遍,供做岩石力学、渗流模拟和水力压裂的朋友参考。

1. 内容整体设计与思路拆解

1.1 为什么天然裂隙必须用粗糙面建模

先聊一个基本问题:我们为什么要在意裂隙的粗糙度。

天然岩体中的裂隙,无论是节理、层理还是剪切裂缝,其表面在微观到宏观尺度上都存在不规则的起伏。这种起伏不是随机噪声,它有一个非常重要的统计学特征——自仿射性。通俗地说,裂隙表面的起伏在放大后看起来跟放大前“长得差不多”,但水平和垂直方向的放大倍数不一样。这个特性用分形几何来描述非常合适,而描述自仿射性的核心参数,就是分形维数 D 或者与之等价的 Hurst 指数 H。

如果不考虑粗糙度,把裂隙简化为两光滑平行板,那流动规律就是经典的立方定律,流速是开度的三次方关系;但现实中裂隙表面是粗糙的,实际流动通道是弯曲、变截面的,局部甚至会因为表面凸起发生直接接触堵死流动路径。结果就是:真实裂隙的流量远低于光滑平行板理论值,并且存在明显的非线性渗流特征(Forchheimer效应),尤其在流速较高时。把粗糙面纳入模型,不是追求几何上的花哨,而是因为物理过程本身就被几何强烈控制。

1.2 分形系数在粗糙裂隙生成中的角色

在很多软件里生成裂隙,最常见也最粗糙的做法是用伪随机函数直接产生一个随机高度场。但纯粹的白噪声没有空间相关性,第 i 个点跟第 i+1 个点之间完全独立,生成出来的表面根本不是天然裂隙的形状,更像噪声雪花。天然裂隙表面的高度起伏在空间上是相关的:局部看可能是尖锐的,但整体上又有一定的连续性和趋势。

分形系数(在多数文献里表现为分形维数 D 或 Hurst 指数 H)正是控制这种“相关关系”的关键指标。D 的取值通常在 1~2 之间(对应三维表面则为 2~3),D 越大,表面起伏越剧烈,高频成分越多,裂隙面越“碎”;D 越接近下限,表面越平滑,起伏更平缓,更像单一尺度的凹凸。通过调节这个系数,我们可以定量生成从“平缓波纹”到“剧烈粗糙”的任意过渡形态的裂隙面,而且这些形态在统计上都符合真实岩石裂隙的自仿射特征。

这套思路的好处是:它把“粗糙程度”从一个模糊的形容词变成了一个定量可控的参数。你做参数研究的时候,可以固定其他条件,只扫描 D 值,观察粗糙度对裂隙渗流或力学指标的影响趋势。

2. 核心细节解析与实操要点

2.1 分形理论:从 W-M 函数到裂隙高度场

生成粗糙裂隙面,目前工程中最常用的数学工具是 Weierstrass-Mandelbrot 函数(简称 W-M 函数)。这个函数的厉害之处在于它本身就是分形的:在任何尺度下都有细节,无限可微但又处处不规则。它的一般形式为:

z(x) = G^(D-1) * Σ [cos(2π·γ^n·x) / γ^((2-D)·n)]

其中:

  • z(x) 是剖面高度;
  • G 是尺度系数,控制整体幅值大小;
  • D 是分形维数,控制表面粗糙度;
  • γ 是频率密度参数,通常取 1.5,代表谱密度之间的间距;
  • n 是空间频率的序号,从 n_min 取到 n_max;
  • x 是沿裂隙方向的坐标。

这里最关键的分形维数 D 直接决定了谱密度随频率衰减的快慢。D 越大,则高频率成分的权重越高,表现在剖面上就是细微裂纹和尖角更多,面更粗糙。反之,D 越小则剖面更“圆润”。尺度系数 G 也很好理解,它相当于给整个高度场定一个“音量”——同样 D 值下,G 越大,起伏幅度越大。

对三维裂隙面,可以沿着两个水平方向 x 和 y 做各向同性的叠加,或者分别给两个方向不同的 D_x 和 D_y 得到各向异性的粗糙面,这个在 COMSOL 里实现起来并不困难,后面我会说到。

2.2 COMSOL 里生成粗糙裂隙的三种技术路线

在 COMSOL Multiphysics 中实现粗糙裂隙的方式,我梳理下来有三大类,按实现难度和适用范围排个序:

第一类:解析函数直接生成剖面线(最简单,适合二维模型)——直接在“全局定义”里定义 W-M 函数,利用 COMSOL 内置的求和函数或者直接写解析式,然后用“几何”里的“参数曲线”功能生成裂隙剖面轮廓。这个方法调试方便,参数化也直观,适合二维裂隙渗流或者二维接触模型。

第二类:外部数据点导入生成曲面(最通用,适合三维模型)——先用 MATLAB、Python 或其它工具按分形算法生成裂隙面的离散点云坐标,以文本文件格式(csv、txt)导入 COMSOL,通过“插值函数”读入,再通过“参数曲面”几何节点生成裂隙面。这个方法最灵活,因为你可以用任何成熟的分形算法生成更贴近真实岩芯数据的表面,不受 COMSOL 内置函数表达能力限制。

第三类:借助 COMSOL 事件/随机函数 + 功率谱密度滤波(较高级)——COMSOL 内置了一些随机函数和滤波算子,你可以生成白噪声场然后按目标功率谱进行滤波重构,间接得到分形表面。这个方法的好处是全流程在 COMSOL 里完成,自动化程度高,但需要注意谱密度与分形维数的换算关系必须算对,否则生成的表面统计特性会出偏差。

我个人的建议是:如果你是做二维参数研究,直接走第一类;如果模型要拓展到三维,踏踏实实用第二类,点云导入方式最可靠,可控性也最强。第三类适合已经对分形和信号处理非常熟悉的老手,不太建议新手一上来就这么干。

2.3 W-M 函数在 COMSOL 中的直接落地方法

这里给出一个我在二维裂隙模型里常用的 W-M 函数写法,可以直接粘贴到 COMSOL 的解析函数定义里:

Z_WM(x) = Gmp^(D-1) * sum(cos(2pigam^n*x + phi_n) / gam^((2-D)*n), n, n_min, n_max)

注意这里的 phi_n 是每个频率分量对应的随机相位——这是很多人在 COMSOL 里实现时忽略的一个细节。如果所有频率分量的相位都取同一个值(比如都取 0),生成出来的剖面会非常有“规律感”,看起来像周期性波纹而不是天然裂隙,这在统计上也不满足随机性要求。实际做法是在外部脚本里预生成一组均匀分布随机相位,然后以向量的形式带入 COMSOL,或者在 COMSOL 里再用一个随机函数对相位做调制。

W-M 函数的频率范围要覆盖你的模型尺度。假设裂隙长度是 L,那么最小空间频率对应的波长要大于 L(通常取 n_min 对应的波长是 2L 左右),最大频率对应的波长要小于最小网格尺寸的一段(否则就会出现欠采样,导致生成细节比网格还细,白白增加计算量)。用一个具体例子来说:裂隙长度 0.1 m,最小网格尺寸 1e-4 m,那 n_min 大约从 1 开始,n_max 取到 20~30 基本足够,再多频率项对几何细节的贡献已经低于网格分辨率了。

2.4 参数选择:D、G、γ 怎么搭配才合理

这部分常有人问:分形维数 D 取值多少合适?G 取多少?

从实测数据看,天然岩石裂隙的分形维数 D 大多集中在 1.1 到 1.5 之间(剖面线维数),极少超过 1.6。如果你取 1.8、1.9,生成出来的表面会非常尖锐,甚至出现很多倒钩状的结构,这种结构在真实裂隙中几乎不存在,也容易在网格划分的时候引起极大困难。因此我强烈建议在做参数研究时,D 的扫描范围设置在 1.1 到 1.5,步长取 0.1,这就足够覆盖绝大多数天然裂隙的情况了。

G 的取值跟实际裂隙面的起伏幅度有关。假设你要模拟的裂隙粗糙度 JRC(粗糙度系数)大概在 10~15 之间,对应的起伏幅度大约在 1~2 mm(对于 100 mm 长的裂隙)。那么 G 可以设成 1e-4 到 1e-3 这个量级,再根据生成的表面最大起伏值做一次反向标定。简单来说,你可以先生成一批剖面,量一下最大峰谷差,如果跟实测或目标 JRC 对不上,就线性缩放 G 重新生成。这个标定过程最好做一个独立的脚本或表格,不要每次手动 zoom in 肉眼估计。

γ 一般固定取 1.5,这是一个被广泛接受的经验值,控制的是频谱密度的疏密程度。你可以把它当作一个固定的超参数,默认不用动。

3. 实操过程与核心环节实现

3.1 外部生成分形点云:MATLAB / Python 脚本方案

为了做到三维裂隙面,我通常走 MATLAB 或 Python 生成点云再导入 COMSOL 的路线。这里用 Python 给出一个可运行的示例框架,核心算法就是随机相位 W-M 函数在二维网格上的求值:

import numpy as np def generate_fracture_surface(Lx, Ly, nx, ny, D, G, gam=1.5, n_min=1, n_max=30): x = np.linspace(0, Lx, nx) y = np.linspace(0, Ly, ny) X, Y = np.meshgrid(x, y) Z = np.zeros_like(X) rng = np.random.default_rng(42) for n in range(n_min, n_max + 1): kx = gam ** n ky = gam ** n phi = rng.uniform(0, 2 * np.pi) # 二维各向同性叠加,两个方向频率一致 Z += (G ** (D - 1)) * np.cos(2 * np.pi * (kx * X + ky * Y) / Lx + phi) / (gam ** ((2 - D) * n)) # 减去均值并缩放 Z -= np.mean(Z) Z /= np.std(Z) # 根据需要线性缩放到目标起伏幅值 A A = 0.002 # 目标峰谷差 2 mm Z = Z / (np.max(Z) - np.min(Z)) * A # 输出为 csv:x, y, z points = np.column_stack([X.ravel(), Y.ravel(), Z.ravel()]) np.savetxt('fracture_surface.csv', points, delimiter=',', header='x,y,z', comments='')

这个脚本生成的是一张采样高度图,你只需要控制 nx、ny 的采样密度,保证跟后续网格尺寸匹配即可。采样过密会造成文件过大和导入缓慢,采样过稀又会丢失细节。经验值是每毫米 5~10 个点,即采样间距 0.1~0.2 mm,对常规 100 mm 左右尺度裂隙比较平衡。

3.2 COMSOL 导入点云并重建几何曲面

得到点云文件以后,COMSOL 里的操作流程如下:

  • 全局定义 → 插值函数,加载fracture_surface.csv,插值类型选“三次样条”或“线性”,坐标轴选 x、y,值选 z。这里要特别注意,如果 CSV 文件过大(比如几十万行),建议先用 MATLAB 或 Python 抽稀到三五千个点以内,否则 COMSOL 插值函数构建会非常卡。
  • 几何 → 参数曲面,需要把插值函数引用进去。这里给出一个操作口诀:参数曲面本质上是让 COMSOL 从参数域 (s,t) 到空间坐标 (x,y,z) 做一个映射。因为我们的高度图是 z=f(x,y),所以参数曲面设置里需要把 x=s、y=t、z=funct(s,t) 填进去:
    • x = s
    • y = t
    • z = int1(s,t)
  • 几何 → 拉伸或移动,把曲面复制一层放在下面,中间留出期望的平均开度。比如目标平均开度是 0.5 mm,就把下表面 z 方向平移 -0.0005 m,两个粗糙面对立放置。
  • 最后在几何节点里做布尔并集或装配(Assembly),生成完整的裂隙域。

这里有一个很重要的几何细节:COMSOL 的“参数曲面”生成出来的是一个理想化的薄层曲面,默认不带厚度。如果你做的是裂隙渗流模型,后续需要用“薄层”或“裂隙流”接口把这个面当作流通域;如果做接触力学,则需要把面闭合为体(比如做一个小厚度的挤出)。不同物理场对几何的要求不一样,一定要提前想清楚。

3.3 网格划分策略:粗糙面模型的核心痛点

粗糙裂隙模型的网格划分是重灾区。粗糙面高起伏、局部尖锐的特征很容易产生极小面单元,直接拉爆网格数量。

我的划分策略是三层递进:

  • 粗分区:先用自由四面体对整个裂隙域生成一次粗略网格,目的是检查几何有没有异常交叉或退化。粗糙度较大的情况下,两个粗糙面可能局部直接穿透了,这一步就必须回几何里把平均开度加大或者重新标定 G 值。
  • 边界层加密:对裂隙上下面设置边界层网格,第一层厚度要覆盖到你关心的渗流边界层或接触区域。裂隙流模型里,开度方向至少要保证 3~5 层网格单元,否则流速分布算不准。
  • 局部细化:对裂隙面凹凸起伏陡峭的区域手动添加“大小”节点做局部加密。用曲率因子控制——把“曲率分辨率”从默认的 0.2 提高到 0.4~0.5,能让粗糙面的尖角处生成更多单元,避免稀网格过度平滑掉几何细节。

3.4 裂隙渗流仿真的关键边界条件设置

以一个粗糙单裂隙稳态渗流模型为例,物理场用“达西定律”(Darcy's Law)或“裂隙流”(Fracture Flow)接口。入口定压力、出口定压力,两侧壁面无流。如果你的裂隙面开度变化非常大,流动会产生明显的沟槽效应,局部流速可能相差几个数量级。

这里有一个很多人会踩的坑:COMSOL 里裂隙流接口的默认“开度”是一个常数。如果是你自己导入的粗糙裂隙几何,一定要把开度改成“随空间变化”——在裂隙流接口里选“裂隙开度”为“用户定义”,然后填一个表达式,比如0.0005 + int1(x,y)(对下表面)或者直接基于几何厚度函数。否则你辛苦做的粗糙几何就白费了,软件还是按光滑平行板算。

求解器选择方面,纯达西流默认的迭代求解器就行;如果把雷诺数拉高做非线性渗流,需要启用 P 非线性或添加 Forchheimer 修正项,此时要切换成全耦合求解器并适当缩减步长。

3.5 结果后处理:粗糙度影响的可视化与定量提取

算完之后,除了看压力云图和流线分布,建议重点提取两个指标:

  • 等效水力开度 e_h:根据达西流流量结果反向换算 e_h = (12·μ·L·Q / (ΔP·W))^(1/3),其中 L 是裂隙长度,W 是宽度,Q 是总流量。把 e_h 跟平均力学开度 e_m 做对比,就能定量得到粗糙度对渗流能力的削弱程度。大量文献的规律是:e_h/e_m 随分形维数 D 的增大而明显下降,这个趋势你用参数扫描一下就出来了。
  • 裂隙接触面积比:如果开度设得很小,粗糙面会有局部接触,COMSOL 可以直接后处理导出开度小于某个阈值的区域面积占总面积的比例。这个指标对应力学加载下的接触刚度,非常有用。

4. 常见问题与排查技巧实录

4.1 生成的面“看起来不对”:频率范围与相位问题

这是频率最高的反馈:“我按 W-M 函数生成了面,但看起来好像是波浪板,不像岩石裂隙。”出现这个问题,十有八九是频率项 n 太少或者随机相位没有加进去。n 太少,表面的多尺度特征没有体现出来,看起来就是平滑波纹;没有随机相位,则生成的面呈周期性排列。解决办法是增加到 n_min=1、n_max=30,检查相位是否逐项不同。另外,维度选择也需要注意:二维剖面和三维曲面的分形维数取值范围不同,一定要在生成前明确你想模拟的是剖面线还是整个表面。

4.2 网格划分失败或质量过低

粗糙面局部斜度太大,四面体网格切分时会产生大量退化单元。我的经验是先在“几何”里做一个“细化”操作,把尖锐的边界稍微圆滑一些,然后网格序列改用“边界层 + 自由四面体”而不是“扫描”。如果你发现几何交叉穿透,优先检查平均开度是否大于两侧粗糙面的最大峰谷值之和的一半。这个判断很简单:两个粗糙面相对放置时,平均开度一定要大于上下表面各自的最大峰谷差之和的一半,否则必然穿透。

4.3 渗流结果不收敛

达西流接口本身线性度很好,一般不会不收敛;但如果发现迭代不降残差,大概率是局部区域开度过小甚至为负值。这时候到结果里画一个开度分布图,看哪里出现负值,回几何修正。还有一种情况是边界条件设置跟裂隙流接口不兼容——比如入口用“压力”边界,出口也用“压力”,但初始值给得不合理,导致迭代初始两步就发散。建议先用一个光滑平行板模型测试同样的边界条件,确认物理场设置没问题,再转到粗糙裂隙模型上算。

4.4 点云导入后曲线/曲面出现“毛刺”

插值函数默认的线性插值在数据点稀疏时会产生折线效果,看起来像锯齿。解决方法是改用“三次样条”插值,并且在插值函数设置里把“平滑”因子往上调一点。不过要注意,过度平滑会抹掉分形表面的小尺度特征,所以一般设置“平滑”范围为局部网格尺寸的 1/2 以内即可,不要追求过度的视觉光滑。

4.5 如何快速验证分形生成结果是否统计正确

这是一个容易被忽视但值得做的工作:批量生成 10 条不同随机种子但相同 D 的剖面,分别计算每条剖面的功率谱密度。把功率谱在双对数坐标下拟合成一条直线,直线的斜率 α 跟分形维数的关系为 α = 5 - 2D(一维剖面线情形)。如果拟合得到的斜率跟理论预期偏差超过 10%,说明你脚本里的频率项或相位生成有问题,需要回查。

这个方法本质上是做“生成-验证”闭环,不要省这一下功夫,因为你后边所有的参数研究结论都建立在“几何正确”的假设之上。如果分形统计本身是错的,后边算的每个数据点都是空中楼阁。

5. 三维粗糙裂隙拓展与流-固耦合方向

前面的内容主要围绕二维剖面和三维曲面几何展开,下面说说这个模型还能往哪个方向扩展。

5.1 三维粗糙裂隙的几何生成与仿真要点

真正的三维裂隙在 COMSOL 里建模,几何上跟二维的区别不只是多一个维度,更重要的是面与面之间的接触区会形成复杂的“岛屿状”分布,这对网格划分和求解效率提出了很高的要求。我的建议是不要一次性生成整块巨大的粗糙面,先按裂隙走向分段生成局部尺寸较小的粗糙面,再用“装配”拼起来,降低单个几何体的复杂度。物理场方面,三维裂隙流建议直接用“裂隙流”接口,它可以定义沿裂隙面的切向流动,同时考虑法向开度变化,计算效率远高于用完整的三维多孔介质域去模拟薄层流动。算完之后提取整个面上的流量分布,可以分析沟槽效应和优势通道,结果非常直观。

5.2 分形粗糙度对水力-力学耦合的影响规律

当裂隙承受法向应力时,粗糙表面会逐渐闭合,真实接触面积从零开始增长,渗流通道随之被压缩甚至截断。这种水力-力学耦合行为本身就是分形几何最直接的应用场景。你可以在 COMSOL 里用“固体力学”接口给裂隙面施加法向位移边界,计算每个位移步下的接触面积比和流量变化,最终得到一条“法向应力-渗透率”关系曲线。这条曲线用光滑平行板模型是永远算不出来的,因为平行板要么完全接触要么完全脱开,没有一个连续的“部分接触”状态。通过扫描分形维数 D,你会发现 D 越大,接触面积随位移增长越快,渗透率衰减也越剧烈——这就是粗糙度对裂隙压缩性的定量影响,如果做工程报告或论文,这组曲线非常有说服力。

5.3 参数化扫描与 App 封装

COMSOL 的“参数化扫描”功能做分形维数 D 的扫描非常方便。你把 D、G、平均开度都设成全局参数,在“研究”设置里添加 D 扫描列表,一次跑完 1.1~1.5 的五个值,后处理里直接用“全局评估”抽取每个 D 下的流量和等效水力开度,一次性生成对比表格。更进阶一点,还可以用 COMSOL App 开发器把几何生成和仿真流程封装成一个小工具,外面设一个 D 的滑杆,点击生成就出新结果。团队里做工程的人不用碰底层几何代码,直接面对参数界面就能完成日常的裂隙渗流评估,效率提升非常明显。

6. 实操心得与后续扩展

最后说几点我自己实际做下来最有价值的体会。

第一,COMSOL 做粗糙裂隙,几何阶段花的时间通常占到整个项目的一半以上。很多人把这个阶段想简单了,直接画个粗糙面就急于设置物理场,结果后边网格和求解不断报错,不得不回头改几何。正确做法是:先把几何单独拆成一个小模型,把网格划完、质量检查通过,再叠加物理场。几何不稳定,后边全白搭。

第二,分形维数 D 不是随便取的,建议脑子里始终绷着一根弦:D 的取值要跟实测数据的统计结果对应。如果你手头有天然裂隙表面轮廓仪扫描数据,可以先对实测剖面做功率谱分析,拟合出实际的 D 值,再把它作为 COMSOL 模型里的输入。这样做出来的仿真结果才有实际工程参考意义,而不是纯理论演示。

第三,COMSOL 的插值函数和参数化能力是这套方案最核心的桥梁。点云数据本身不稀奇,但把它平滑、可控地从外部文件变成几何、再映射成物理场里随空间变化的开度,这中间每一步都有坑。如果你打算长期做这个方向,建议把点云生成、导入、开度赋值、后处理指标提取这一套流程做成自己的模板,避免每次从零开始操作。

我自己目前还在做的一件后续工作,是把不同分形维数下的粗糙裂隙渗透率和接触刚度数据累积起来,形成一个简单的经验公式,后面做工程评估时不用每次都跑完整仿真。这个过程离不开 COMSOL 批量参数扫描和后处理自动化。对于刚开始接触这个方向的朋友,我建议还是从二维单裂隙模型开始,把一个参数研究做完整,比一上来就上三维模型磨一个月要划算得多。

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

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

立即咨询