15. Theis 公式非线性拟合求参(最小二乘,Python)

欢迎点评!如果公式乱码,请用浏览器访问,用鼠标右键 -> 加载映像 显示公式。

需要安装的库:Jupyter,Jupyterlab,numpy,scipy,matplotlib,ipympl,mpl_interactions

pip 安装:

pip install Jupyter Jupyterlab numpy scipy matplotlib ipympl mpl_interactions

以下内容源自地下水动力学课程教学内容,程序可在 Jupyter notebook 中运行。

非线性拟合 — Theis 公式

Theis 公式是非线性的,所以需要将其转化为初始参数附近的线性形式,如用泰勒级数展开并忽略高阶项,我们要从初始参数开始寻找参数变化的最优步长。据此可使用最小二乘法拟合。

s= \frac{Q}{4\pi T}\int_u^\infty\frac{1}{y}e^{-y}dy=\frac{Q}{4\pi T}W(u)\tag{1}

取初始参数 T_0S_0,降深 s 的泰勒级数展开为

s(T,S)=s(T_0,S_0)+\frac{\partial{s}}{\partial{S}}\Bigg|_{S=S_0}\Delta{S}+\frac{\partial{s}}{\partial{T}}\Bigg|_{T=T_0}\Delta{T}+O(\Delta{T}^2+\Delta{S}^2) \tag{2}

式中,\Delta{T} = T-T_0,\Delta{S}=S-S_0。因为 \frac{\partial{u}}{\partial{S}}=\frac{u}{S}, \frac{\partial{u}}{\partial{T}}=-\frac{u}{T} ,得

\frac{\partial{s}}{\partial{S}} = -\frac{Q}{4{\pi}T}\frac{e^{-u}}{S},\quad \frac{\partial{s}}{\partial{T}} = \frac{Q}{4{\pi}T^2}\left[-W(u)+e^{-u}\right]

a=\left.\frac{\partial{s}}{\partial{S}}\right|_{S=S_0},\quad b=\left.\frac{\partial{s}}{\partial{T}}\right|_{T=T_0},\quad c=s(T_0,S_0) \tag{3}

忽略高阶无穷小,(2) 式可写为

\hat s =c +a\cdot\Delta S + b\cdot \Delta T \tag{4}

式 (4) 为 Theis 公式取参数(T_0,S_0)时参数微小变化的线性近似式。

从初始参数出发,确定最优步长 (\Delta T, \Delta S),可以得到一步优化的参数。

(\Delta T, \Delta S) 为未知系数, \hat ss 的预测值,a,b,c 根据初始参数(T_0,S_0)及观测时间计算,由此式可构造最小二乘问题。

程序设计需要考虑以下问题

  • 最小二乘法得出的 (T_0+\Delta T,S_0+\Delta S) 有时为不合理的负值,这是需要收缩步长使参数为正值。可以用二分法缩小步长保证参数为正值;
  • 最小二乘法只是在初值的基础上进行了一步优化。为了得到最优参数,需要用得出的参数作为新的参数初值迭代计算;
  • 初值对计算效率有影响,简单方法是选取两组观测数据按 Jacob 公式计算参数初值。

直接上代码

%matplotlib widget

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import exp1

# 控制小数的显示精度
np.set_printoptions(precision=4)

def calc_u(p, r, t):   # 计算变量 u
    S, T = p
    return r**2*S/4/T/t

# 定义井函数计算方法,可用 scipy.special.exp1 计算. 
# 也可用多项式逼近的方法计算井函数
def theis_drawdown(p, t, Q, r):  # 计算降深
    S, T = p
    u = calc_u(p, r, t)
    s_theis = Q/4/np.pi/T*exp1(u)
    return s_theis

def theis_Dfun(p, t, s, Q, r):  # 计算 ds/dT,ds/S
    """Calculate and return ds/dS and ds/dT for the Theis equation.
    The parameters S, T are packed into the tuple p.
    """
    S, T = p
    u = calc_u(p, r, t)
    dsdS = -Q/4/np.pi/T/S*np.exp(-u)
    dsdT = Q/4/np.pi/T**2*(-exp1(u) + np.exp(-u))
    return np.array((-dsdS, -dsdT)).T   # 返回负梯度

def theis_resid(p, t, s, Q, r): # 计算降深预测误差
    S, T = p
    return s - theis_drawdown(p, t, Q, r)

# 抽水量 Q, 观测孔位置 r
r = 125.0  # m, 15#孔位置
Q = 1440   # m^3/d

t=np.array([10., 20., 30., 40., 60., 80., 100., 120., 150., \
            210., 270., 330., 400., 450., 645., 870., 990., 1185.]) / 1440  # 单位 day
s = np.array([0.16, 0.48, 0.54, 0.65, 0.75, 1., 1.12, 1.22, 1.36, 1.55, 1.7, \
              1.83, 1.89, 1.98, 2.17, 2.38, 2.46, 2.54])  # m

# 取数组长度
n = len(t)

# 初始参数怎么取?最简单方法是取中间相邻的两点,用 Jacob 两点公式计算。
# 取数组长度
n = len(t)
i1 = int(n/2)
i2 = i1 + 1
t1 = t[i1]
t2 = t[i2]
s1 = s[i1]
s2 = s[i2]
kk = (s1 - s2)/np.log10(t1/t2)
T0 = 0.183*Q/kk
S0 = 2.25*T0*t1/r**2/np.float_power(10, s1/kk)

p = S0, T0 
S, T = p

# 循环计数器
j = 0
while True:
    c = theis_drawdown(p, t, Q, r)
    a = theis_Dfun(p, t, s, Q, r)[:, 0]
    b = theis_Dfun(p, t, s, Q, r)[:, 1]
    X = np.vstack([a, b]).T  # 形成系数矩阵
    # 调用 np.linalg.solve
    beta = np.linalg.solve(np.dot(X.T, X), np.dot(X.T, c - s))
    DS = beta[0]
    DT = beta[1]
  
    while True:
        if S + DS < 0:    # 步子太大扯了蛋,参数为负不合理!
            DS = DS/2.0  # 缩回半步
        else:
            break 
    while True:
        if T + DT < 0:    # 步长太大,参数为负数不合理!
            DT = DT/2.0  # 缩回半步
        else:
            break
    j = j + 1  # 循环计数器
    if j > 1000:  # 循环次数多,程序可能有错误
        print('  循环超过 1000 次,请先检查程序再运行!')
        break
    if (abs(DT) < 1.0E-6) or (abs(DS) < 1.0e-8):  # 判断计算误差
        break
    # 新参数值
    p = S + DS, T + DT
    S, T = p

# 生成绘图数据
x0 =[i for i in np.arange(-3, 0.1, 0.1)]
x =np.power(10, x0)
y = theis_drawdown(p, x, Q, r)
plt.style.use('default')
fig, ax = plt.subplots(dpi=100)
ax.grid(True)
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlim(0.001, 1)
ax.set_ylim(0.1, 10)
ax.set_aspect(1)
ax.plot(t, s, 'o', label='观测值')
ax.plot(x, y, label='拟合曲线')
plt.xlabel(r'$\log t$') 
plt.ylabel(r'$\log s$')

plt.legend(
    prop={'family': 'Kaiti', 'size': 10},
    loc=4,title="图例",
    title_fontproperties={'family': 'Simsun'})
# 指定图标题,显示中文
ax.set_title("Theis公式最小二乘法求参", fontproperties={'family': 'Simsun'})  

plt.show()

# 显示最终结果
print('循环次数 = {}'.format(j))
print('T = {:.2f} m^2/d,'.format(T), 'S = {:.4e}'.format(S))
print('RSS = {:.4e}'.format(np.sqrt(np.sum((c - s)**2))))
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容