如何解决Python气体物性计算代码报“无法将复数转换为浮点数”错误
复数类型报错的排查与修复步骤
报错Cannot convert complex to float的核心成因是计算链路中某一步生成了复数类型数值,最终传入仅支持实数值的math.exp()触发类型错误。结合油气藏计算的公式逻辑,复数的生成来自三个可复现的代码bug,按排查优先级逐一处理即可:
1. 定位复数生成的两个直接触发点
Python中复数通常在两种计算场景下自动生成:
- 对负数取非整数次幂(如
pow(-1, 0.5)会返回复数) - 迭代求解压缩因子Z时,实数域外的迭代值未被截断,最终生成复数的Z值
对应到你的代码,触发复数的bug如下:
(1)温标传递错误导致Z因子计算输入值非法
- 函数约定:
ZFACT、GFVF的入参温度为华氏度(°F) - 你的
GVISC函数在计算时执行temp = temp + 459.67,将输入的170°F转换为兰金绝对温标(°R)后,直接把这个已转换的值传给GFVF - 链路错误传导:
GFVF收到629.67的“温度值”后直接传给ZFACT,而ZFACT内部会把收到的“华氏度”二次加459.67换算为°R计算对比温度Tr,最终算出的Tr是理论值的2.7倍,迭代求解Z时很容易跳出实数域,直接生成复数的Z因子。
(2)GFVF核心公式的变量覆盖错误
你在GFVF内部,将原本需要传入公式的实际地层温度、实际压力,错误覆盖为了拟临界温度、拟临界压力:
def GFVF(temp, pres, Gamma_G): Z= ZFACT(temp,pres,Gamma_G) # 错误:此处的T、P被赋值为拟临界参数,完全替代了实际地层参数 T = TPC1(Gamma_G) P = PPC1(Gamma_G) return 0.0050035*Z*(T+459.69)/P
这个错误会连锁导致:
- 算出的Bg值与实际压力无数学关联,偏离真实值数个数量级
- 后续计算气体密度
Pg = 0.000007522*(Mw/Bg)时,错误的Bg会传导,极端情况下Z因子为负时会直接得到负的Pg值,后续执行pow(Pg, Y)时因为Y是小数,直接生成复数。
2. 代码修复方案
(1)修正温标传递逻辑
拆分GVISC中的温标使用场景:兰金温标仅用于粘度公式的经验参数计算,给GFVF传值时保留原始华氏度输入,避免温标重复换算:
def GVISC(temp, pres, gamma_G): # 单独定义兰金温标变量,仅用于粘度的经验公式计算 temp_rankine = temp + 459.67 Mw = 28.964*gamma_G # 给GFVF传原始华氏度温度,不要传转换后的兰金温标值 Bg = GFVF(temp, pres, gamma_G) Pg = 0.000007522*(Mw/Bg) # 粘度经验参数计算全部使用兰金温标 K = ((9.379+0.01607*Mw)*(temp_rankine**1.5))/(209.2+19.26*Mw+temp_rankine) X = 3.448+(986.4/temp_rankine)+0.01009*Mw Y = 2.447 - 0.2224*X exponent = X*pow(Pg,Y) Ug = (10**(-4))*K*(math.exp(exponent)) return Ug
(2)修正GFVF的公式逻辑
替换错误的拟临界参数赋值,使用实际地层参数计算干气体积系数(单位bbl/cu.ft),符合行业通用公式:
干气FVF公式:
Bg = 0.0050035 * Z * T(°R) / P(psia)
修正后的GFVF代码:
def GFVF(temp, pres, Gamma_G): Z = ZFACT(temp, pres, Gamma_G) # 将输入的华氏度转换为兰金温标代入公式 temp_rankine = temp + 459.67 # 使用实际温度、实际压力计算,不混用拟临界参数 return 0.0050035 * Z * temp_rankine / pres
3. 增加防御性校验避免同类报错
在计算链路关键节点加入值域、类型校验,一旦出现异常值直接抛出明确错误,避免计算默默进入复数域:
- 校验
ZFACT返回值:确认Z为正实数,若为复数类型直接打印当前输入的temp、pres、gamma_G值,定位Z因子计算的异常输入 - 校验Pg值:计算
pow(Pg, Y)前确认Pg为正数,若为负数直接抛出异常提示Bg计算失真 - 将内置
pow替换为math.pow,当底数为负数时直接抛出实数域错误,而非自动生成复数值
内容的提问来源于stack exchange,提问作者Mhamad Ali Hariri
相关产品推荐
相关产品推荐

