G函数曲线分析:从压降数据诊断裂缝复杂性并优化压裂设计
2026/9/17 19:12:12 网站建设 项目流程

简介:面向石油工程、地质工程研究人员的页岩储层压后裂缝复杂性评估资料,以G函数曲线分析为核心,提供了修正经典G函数理论、建立考虑天然裂缝开启压降模型的完整思路与Python复现代码。资源共1个文件,为PDF格式,压缩包大小469KB,内容涵盖数据模拟、曲线对比、叠加导数计算以及涪陵气田三口井实例分析,配有可运行代码与详细中文解释,便于理解简单主裂缝、沟通单条及多条天然裂缝形态下G函数一阶导数与叠加导数的差异。已有99人学习。读者可借此掌握通过G函数波动幅度和叠加导数波峰数量量化裂缝复杂性的方法,进而优化压裂施工参数与开发部署,并可作为替代微地震监测的低成本分析手段。实际应用时需结合真实压裂数据进行参数拟合与模型校正,以提升评估准确性。

1. 为什么压裂曲线里藏着裂缝复杂性的答案

压裂井产量高低,不一定取决于加砂量,而可能藏在停泵后压降曲线的一次微小波动里。页岩储层压后评估裂缝复杂性,最直接的手段是微地震监测,但费用高、井网密集时难以全覆盖。G函数曲线分析是一条低成本路径:仅用压力计的关井压降数据,通过修正后的G函数理论识别天然裂缝的开启和闭合,就能判断裂缝网络是否复杂。

这里要复现的研究正是基于G函数曲线分析的压后裂缝复杂性评估:先修正经典G函数,再引入天然裂缝开启导致的滤失系数动态变化,用一阶导数和叠加导数的波动形态区分简单主裂缝、单条天然裂缝和多条天然裂缝,最后用涪陵气田三口井数据验证波动幅度与产量的正相关,并据此优化压裂施工参数。适合做压裂设计的油藏工程师、负责投产数据分析的工程师,以及想用低成本替代微地震监测的团队。

2. 从经典G函数到考虑天然裂缝开启的修正模型

2.1 经典G函数的一阶导数是裂缝形态的基线

在均质无限大储层中,压裂井关井后压降压力对G函数作图,简单主裂缝对应一条过原点的直线,一阶导数 g′ = d(Δp)/dG 是常数。原因在于主裂缝只有一个固定的滤失面积,滤失系数恒定,压降速率随时间的变化只受地层线性流控制,G函数在时间维度上把这种线性关系展平。任何对这个常数的偏离,都说明有额外流动路径参与滤失,比如天然裂缝开启、微裂缝扩展或者裂缝穿过应力隔层。

实际处理中,G函数不是直接测出来的,而是由停泵后的压力-时间数据转换而来。常见做法是以5秒或10秒为间隔采集压力,先做Savitzky-Golay滤波平滑,再对无因次时间计算G值,最后用中心差分求导数。直接对原始压力差分会得到大量毛刺,导致导数曲线完全没法读。所以后续所有代码都在理想函数上演示,真实数据要多一步平滑。

有人习惯用压力导数 dp/d(ln Δt) 替代G函数分析,但G函数在信噪比上更优:压力导数在对数时间轴上会放大晚期噪声,而G函数由于做了无因次化和积分变换,能把线性流信号集中在一条直线上,天然滤失的干扰也更容易被识别。这也是为什么G函数曲线分析在压裂诊断里一直没被淘汰。

2.2 天然裂缝开启后滤失系数的分段变化

经典G函数在页岩储层里经常失效,理由是天然裂缝不是静态的。压裂液进入天然裂缝后,缝内压力下降,天然裂缝动态闭合,滤失面积和滤失系数都在变。修正模型的关键是把滤失系数C从常数改成随压力变化的分段函数:当缝内压力高于开启压力时,天然裂缝完全张开,C达到最大值 Cmax;压力降到闭合压力后,裂缝完全闭合,只剩基质滤失,C等于 Cmin;中间过程随压力下降近似线性减小。

这个行为可以用下面的分段函数描述:

$$C(p) = \begin{cases} C_{max} & p \ge p_{open} \ C_{max} - \alpha (p_{open} - p) & p_{close} < p < p_{open} \ C_{min} & p \le p_{close} \end{cases}$$

其中 α 是过渡段斜率,由天然裂缝密度、倾角和岩性共同决定。注意真实储层中的 α 不是常数,多条天然裂缝会在时间上分批闭合,反映到G函数一阶导数上就是 sin 或衰减正弦式的波动。波动频率对应裂缝开启批次,波动幅度对应参与滤失的裂缝面积。这构成了复现代码中所有模拟曲线的理论依据。

这里有个容易误解的地方:滤失系数下降只会让一阶导数向下偏离,而不会向上抬升。所以当你在实际压降曲线上看到导数上半段高于基线、下半段回落,那不是同一组裂缝的行为,而是先后有两批裂缝参与滤失的结果。判断裂缝复杂性,不能只看单点峰值,要看整个窗口内的波动轨迹。

2.3 三类裂缝形态的曲线特征快速判断表

实际压降诊断时,主要看两件事:一阶导数是否波动,叠加导数有没有拐点或波峰。下面这个表整理了三类裂缝形态的典型特征,可以直接放在手边对照。

裂缝形态G函数一阶导数叠加导数物理解释
简单主裂缝常数,水平线水平直线,无拐点仅主裂缝滤失,滤失系数恒定
沟通单条天然裂缝小幅波动,阶段性偏离单次拐点或单波峰一条天然裂缝开启后闭合,滤失系数变化一次
沟通多条天然裂缝大幅波动,呈振荡衰减多个波峰,早期即偏离多条天然裂缝分批开启/闭合,缝网复杂

注意:叠加导数的“波峰数量”并不严格等于天然裂缝条数。如果两条裂缝同时闭合成一个波峰,数量会偏少;如果一条裂缝分多段闭合,又会偏多。所以更稳妥的量化指标是波动幅度和波峰出现的时间分布,这一点在实例分析里会展开。

3. 用Python复现三类裂缝形态的G函数曲线

在写代码前先明确模拟目标:不是拟合真实压力数据,而是生成理论曲线,用来理解不同裂缝形态在G函数上的表现。我们用无因次时间从0.1到10共500个点,模拟停泵后早期到裂缝闭合结束的阶段。三种形态的滤失行为分别用常数、分段函数、衰减正弦波表达。

3.1 模拟数据与参数选择

import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 保证中文字体显示 plt.rcParams['axes.unicode_minus'] = False # 无因次时间序列:从0.1开始,避免t=0处除以零问题 t = np.linspace(0.1, 10, 500) # 简单主裂缝:G函数一阶导数为常数 g_prime_simple = np.ones_like(t) * 0.5 # 沟通单条天然裂缝:滤失系数分阶段变化,小范围正弦波动 g_prime_single = np.piecewise( t, [t < 3, (t >= 3) & (t < 6), t >= 6], [lambda x: 0.5, lambda x: 0.5 + 0.1 * np.sin(x), lambda x: 0.3] ) # 沟通多条天然裂缝:滤失系数动态波动,并随时间衰减 g_prime_multiple = 0.5 + 0.3 * np.sin(2 * t) * np.exp(-0.1 * t)

这里的关键参数:0.5是无因次基线滤失系数;0.1和0.3分别是单条和多条天然裂缝的波动幅度,数值越大代表参与滤失的天然裂缝面积越大;exp(-0.1*t)模拟多条裂缝陆续闭合导致波动衰减。piecewise的三个区间模拟天然裂缝的未开启、开启过渡、闭合三个阶段。注意第二个区间里用np.sin(x)而不是np.sin(t),否则分段拼接处会出现相位突变,与真实压力曲线的连续性不符。

3.2 一阶导数曲线对比

plt.figure(figsize=(10, 6)) plt.plot(t, g_prime_simple, label='简单主裂缝', linestyle='--') plt.plot(t, g_prime_single, label='单条天然裂缝', linestyle='-') plt.plot(t, g_prime_multiple, label='多条天然裂缝', linestyle='-.') plt.xlabel('无因次时间') plt.ylabel('G函数一阶导数') plt.title('不同裂缝形态的G函数一阶导数对比') plt.legend() plt.grid(True) plt.show()

从图上能明显看出三条曲线的差异:简单主裂缝是水平线;单条天然裂缝在 t=3 附近出现小鼓包,随后回落到 0.3,说明天然裂缝闭合后滤失面积反而小于主裂缝初期;多条天然裂缝几乎全程波动,且波峰不止一个。这个区别在叠加导数图上会更清楚。

注意:若三条曲线纵轴范围差异很大,真实数据绘图时建议用plt.ylim固定范围,否则波动幅度小的曲线会被压成一条直线。另外,现实中一阶导数起始段常受井筒储集效应污染,通常需要剔除停泵后前几分钟的数据再画图。

3.3 叠加导数的计算与裂缝闭合点识别

def superposed_derivative(g_prime, t): # 用累积平均近似叠加导数,适合观察趋势 # 实际工程建议用压力对G时间再求导,见下方说明 return np.cumsum(g_prime) / np.arange(1, len(t) + 1) sd_simple = superposed_derivative(g_prime_simple, t) sd_single = superposed_derivative(g_prime_single, t) sd_multiple = superposed_derivative(g_prime_multiple, t) plt.figure(figsize=(10, 6)) plt.plot(t, sd_simple, label='简单主裂缝', linestyle='--') plt.plot(t, sd_single, label='单条天然裂缝', linestyle='-') plt.plot(t, sd_multiple, label='多条天然裂缝', linestyle='-.') plt.xlabel('无因次时间') plt.ylabel('叠加导数') plt.title('叠加导数曲线特征:波峰对应天然裂缝闭合点') plt.legend() plt.grid(True) plt.show()

叠加导数的物理意义是累积滤失效应的平均速率。函数里的np.cumsum对 g′ 做积分,再除以时间序号,得到随时间变化的平均值。你完全可以改成np.cumsum(g_prime * np.diff(np.concatenate(([0], t))))做严格数值积分,但对本模拟的波动形态影响很小。

叠加导数曲线上的第一个偏离点通常被解读为天然裂缝闭合点:简单主裂缝是水平直线,单条天然裂缝在 t=6 附近出现下弯,多条天然裂缝则出现多个波峰。闭合点对应的压力值就是裂缝闭合压力,在压裂设计中用于确定合理停泵时间和支撑剂铺置方案。

3.4 参数敏感性:波动幅度与裂缝条数如何影响判断

调节三个参数看曲线形态变化:波动幅度A、波动频率ω、衰减系数λ。下表总结了它们对判断的影响,方便拟合自己的压降数据。

参数变化G函数一阶导数表现对裂缝复杂性判断的影响
A增大波动幅度变大天然裂缝滤失面积更大,缝网更复杂
ω增大波动频率变密裂缝开启批次增多,或裂缝间距变小
λ增大波动衰减加快裂缝闭合速度快,闭合压力高
基线值抬升整体导数值上移基质渗透率或压裂液黏度变大

实际拟合时不要只调一个参数。常见错误是把 ω 调到很大来拟合每个毛刺,导致模型过拟合。一般先固定 λ,用 A 拟合波峰高度,再用 ω 拟合波峰间距,最后用整体基线校准。拟合完的参数可以放进下一步的实例分析,作为井间对比的量化指标。

4. 涪陵气田三口井实例:波动幅度与产量的相关性验证

原论文中的井名在OCR后出现符号歧义,这里按产量和裂缝形态重新编号:井A对应简单主裂缝,产量5万方/日;井B对应沟通单条天然裂缝,产量8万方/日;井C对应沟通多条天然裂缝,产量12万方/日。逻辑与原文保持一致:裂缝越复杂,产量越高。

4.1 三口井的G函数曲线模拟

# 井A:简单主裂缝 g_A = np.ones_like(t) * 0.5 sd_A = superposed_derivative(g_A, t) # 井B:单条天然裂缝,前期平直后期小幅波动 g_B = np.piecewise( t, [t < 4, t >= 4], [lambda x: 0.5, lambda x: 0.5 + 0.2 * np.sin(x - 4)] ) sd_B = superposed_derivative(g_B, t) # 井C:多条天然裂缝,高频振荡且衰减缓慢 g_C = 0.5 + 0.4 * np.sin(3 * t) * np.exp(-0.05 * t) sd_C = superposed_derivative(g_C, t)

井B的波动幅度取0.2,井C取0.4,衰减系数从0.1降到0.05,使井C的波动在观察窗口内保持明显。用上一节的参数敏感性表反推:井C对应的天然裂缝开启面积约为井B的两倍,闭合时间也更长。绘制对比图时,建议用两个上下排列的子图分别画一阶导数和叠加导数,否则纵轴尺度不同,波形特征会被掩盖。

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(11, 9)) ax1.plot(t, g_A, label='井A (简单主裂缝)', linestyle='--') ax1.plot(t, g_B, label='井B (单条天然裂缝)', linestyle='-.') ax1.plot(t, g_C, label='井C (多条天然裂缝)', linestyle='-') ax1.set_ylabel('G函数一阶导数') ax1.legend() ax1.grid(True) ax2.plot(t, sd_A, label='井A', linestyle='--') ax2.plot(t, sd_B, label='井B', linestyle='-.') ax2.plot(t, sd_C, label='井C', linestyle='-') ax2.set_xlabel('无因次时间') ax2.set_ylabel('叠加导数') ax2.legend() ax2.grid(True) plt.suptitle('涪陵气田三口井G函数曲线对比') plt.show()

叠加导数的识别要点:井A是水平直线,井B在 t=4 之后有一次明显下弯,井C在早期就有偏离并出现两个以上波峰。真实数据里井C的多个波峰容易被噪声掩盖,所以要先做平滑再判断。我一般用Savitzky-Golay滤波加3点中心差分,窗口长度至少覆盖5个压力采样点,窗口太短会保留高频抖动,窗口太长又会把真实波动抹平。

4.2 波动幅度-产量相关性散点图

wells = ['井A', '井B', '井C'] g_fluctuation = [0.0, 0.2, 0.4] # 归一化波动幅度 production = [5, 8, 12] # 压后产量,万方/日 plt.figure(figsize=(8, 5)) plt.scatter(g_fluctuation, production, s=120, color='darkred') for i, well in enumerate(wells): plt.annotate(well, (g_fluctuation[i], production[i]), xytext=(6, -12), textcoords='offset points') plt.xlabel('G函数波动幅度') plt.ylabel('压后产量(万方/日)') plt.title('G函数波动幅度与压后产量的相关性') plt.grid(True) plt.show()

散点图显示正相关:波动幅度越大,产量越高。物理逻辑是波动幅度大意味着更多天然裂缝参与滤失闭合,缝网改造复杂程度高,压裂液在更大范围内建立微缝隙网络,最终增加渗流面积。需要提醒的是,这里只有三个点,不能证明因果关系,只能作为井间相对评估的快速指标。实际项目应至少取同一平台8口以上的井,再把波动幅度与生产动态数据放在一起回归。

如果要在汇报中更直观,可以把产量画成柱状、波动幅度画成折线,用双轴图展示:

fig, ax_left = plt.subplots(figsize=(8, 5)) ax_left.bar(wells, production, color=['#4C72B0', '#55A868', '#C44E52'], alpha=0.7, label='产量') ax_left.set_ylabel('产量(万方/日)') ax_left.legend(loc='upper left') ax_right = ax_left.twinx() ax_right.plot(wells, g_fluctuation, 'ko--', linewidth=2, label='波动幅度') ax_right.set_ylabel('G函数波动幅度') ax_right.legend(loc='upper right') plt.title('涪陵气田三口井的G函数波动与产量关系') plt.grid(axis='y') plt.show()

注意双轴图要分开设置legend,否则Matplotlib会把两个图例合并成一个,导致标签混乱。汇报时我会在波动幅度旁边标注“取自叠加导数在天然裂缝闭合前窗口的均方差”,这样领导知道这个数值不是拍脑袋定的。

4.3 把波动幅度变成裂缝复杂性指数

肉眼判断不便于跨井批量对比,可以定义一个简化裂缝复杂性指数FCI:先减去整个窗口的平均基线,再求标准差,最后除以基线归一化。

def fracture_complexity_index(g_prime, t): # 取主裂缝闭合前的窗口,这里用全部窗口示意 # 实际应截取闭合点之前的时间段,避免后期衰减拉低指数 baseline = np.mean(g_prime) return np.std(g_prime - baseline) / (baseline + 1e-9) fci_A = fracture_complexity_index(g_A, t) fci_B = fracture_complexity_index(g_B, t) fci_C = fracture_complexity_index(g_C, t) print(f"井A FCI={fci_A:.3f}, 井B FCI={fci_B:.3f}, 井C FCI={fci_C:.3f}")

这个指数是波动幅度的归一化标准差。基线取整个关井窗口的平均,实际应用时应该截取在主裂缝闭合点之前的时间段,否则后期波动衰减会拉低复杂井的指数,让简单井和复杂井差距变小。FCI>0.1可认为是复杂缝网,0.03~0.1为中等,<0.03为简单缝。阈值必须根据区块历史井标定,不能直接跨区块套用。

5. 施工参数优化里的落地技巧:从曲线到泵注程序调整

5.1 物性差井的模拟优化

物性差的储层裂缝延伸困难,G函数曲线往往表现为低波动、叠加导数几乎水平。针对这类井,常见优化方向是增加前置液用量,延长有效延伸时间,同时降低砂比,避免近井筒砂堵。在模拟里可以把单条天然裂缝的波动幅度从0.1提高到0.2,观察优化后曲线是否变复杂:

g_low_before = 0.5 + 0.1 * np.sin(t) g_low_after = 0.5 + 0.2 * np.sin(t) # 前置液增加后波动增强

这个变化在真实泵注设计中对应提高前置液百分比,比如从30%提到45%。风险是施工成本上升,且前置液过多可能让裂缝过度延伸形成单条长缝,FCI反而下降。如果优化后井B这类单条裂缝井的波动幅度超过0.3,说明沟通了额外天然裂缝,可以考虑再降砂比。

5.2 深层井的阶梯式加砂设计

深层页岩闭合应力高,裂缝更倾向于单一形态,G函数波动被压缩。补偿思路是阶梯式加砂:低砂量起步,保持净压力持续上升,等测得的G函数导数值抬升后再加下一档砂。模拟代码:

# 阶梯式砂浓度,单位kg/m³,时间无因次 sand_concentration = np.piecewise( t, [t < 2, (t >= 2) & (t < 5), t >= 5], [lambda x: 1.0, lambda x: 1.5, lambda x: 2.0] ) plt.figure(figsize=(8, 4)) plt.step(t, sand_concentration, where='post', color='darkgreen', linewidth=2) plt.xlabel('无因次时间') plt.ylabel('砂液浓度(kg/m³)') plt.title('深层井阶梯式加砂曲线') plt.grid(True) plt.show()

注意这只是教学模拟,真实设计需要压裂模拟软件计算裂缝延伸。G函数在这里承担施工前后诊断:施工前用压降测试确定天然裂缝开启压力,施工后确认FCI是否提高。如果FCI没有变化,优先排查排量是否不足,再考虑前置液比例是否偏低。

5.3 自动识别叠加导数波峰数

手工数波峰容易数错,尤其当压力噪声大时。更可靠的做法是对叠加导数做一阶差分,找到正负号变化的位置,再过滤掉低于阈值的抖动:

def detect_peaks(sd, min_height=0.01): diff_sd = np.diff(sd) sign_changes = np.where(np.diff(np.sign(diff_sd)) != 0)[0] + 1 peaks = [] for idx in sign_changes: if idx < 1 or idx >= len(sd) - 1: continue local_min = min(sd[idx - 1], sd[idx + 1]) if sd[idx] - local_min > min_height: peaks.append(idx) return peaks peaks_C = detect_peaks(sd_C, min_height=0.02) print(f"井C叠加导数波峰数量: {len(peaks_C)}")

阈值 min_height 是关键,建议先用简单主裂缝井的噪声水平做底噪,再乘以3作为检测阈值。不同井之间必须用相同阈值,否则无法横向比较。代码没有依赖scipy,如果环境允许,可以用scipy.signal.find_peaks的 prominence 参数会更稳定。最后提醒常见坑:多井对比时,所有井的G函数时间窗口必须一致,统一定在停泵后第30分钟开始取数,能明显减少井筒储集效应带来的伪波动。

本文还有配套的精品资源,点击获取

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

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

立即咨询