Test wells with analytical solutions#

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

import timflow.transient as tft

plt.rcParams["font.size"] = 8.0
plt.rcParams["figure.figsize"] = (8, 3)

Theis#

def theis(r, t, T, S, Q):
    u = r**2 * S / (4 * T * t)
    h = -Q / (4 * np.pi * T) * exp1(u)
    return h


def theisQr(r, t, T, S, Q):
    u = r**2 * S / (4 * T * t)
    return -Q / (2 * np.pi) * np.exp(-u) / r
T = 500
S = 1e-4
t = np.logspace(-5, 0, 100)
r = 30
Q = 788
htheis = theis(r, t, T, S, Q)
Qrtheis = theisQr(r, t, T, S, Q)
ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=S / 20, tmin=1e-5, tmax=1)
w = tft.Well(ml, tsandQ=[(0, Q)], rw=1e-5)
ml.solve()
h = ml.head(r, 0, t)
Qx, Qy = ml.disvec(r, 0, t)
self.neq  1
solution complete
plt.subplot(121)
plt.semilogx(t, htheis, "b", label="theis")
plt.semilogx(t, h[0], "r--", label="timflow")
plt.xlabel("time (day)")
plt.ylabel("head (m)")
plt.legend()
plt.grid()
plt.subplot(122)
plt.semilogx(t, Qrtheis, "b", label="theis")
plt.semilogx(t, Qx[0], "r--", label="timflow")
plt.xlabel("time (day)")
plt.ylabel("head (m)")
plt.legend(loc="best")
plt.grid()
../../_images/efbf6d3139553cc6f3af833f66b88e6c6058ad0b39322e4ce3434054f6382f76.png
def test(M):
    ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=S / 20, tmin=1e-5, tmax=1, M=M)
    tft.Well(ml, tsandQ=[(0, Q)], rw=1e-5)
    ml.solve(silent=True)
    h = ml.head(r, 0, t)
    return htheis - h[0]
enumba = test(M=10)
plt.plot(t, enumba, "C1")
plt.xlabel("time (d)")
plt.ylabel("head difference Theis - timflow")
plt.grid()
../../_images/a7868637a18f9a8bf1d4ecb0c0e06178f1c37b5301243db175750d852597d263.png
plt.plot(t, Qrtheis - Qx[0])
plt.xlabel("time (d)")
plt.ylabel("Qx difference Theis - Ttim")
plt.grid()
../../_images/b59df1c6ce962231484a99882b3e5f15e4d43c6cf569e8b37011c61084c3a119.png
def compare(M=10):
    ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=S / 20, tmin=1e-5, tmax=1, M=M)
    tft.Well(ml, tsandQ=[(0, Q)], rw=1e-5)
    ml.solve(silent=True)
    h = ml.head(r, 0, t)
    rmse = np.sqrt(np.mean((h[0] - htheis) ** 2))
    return rmse


Mlist = np.arange(1, 21)
rmse = np.zeros(len(Mlist))
for i, M in enumerate(Mlist):
    rmse[i] = compare(M)
plt.semilogy(Mlist, rmse)
plt.xlabel("Number of terms M")
plt.xticks(np.arange(1, 21))
plt.ylabel("relative error")
plt.title(
    "comparison between timflow solution and Theis \n solution using numba and M terms"
)
plt.grid()
../../_images/47118d6bd3bc7d627aa6ef3b6e6364851f09497c74974cc98d1525899b51625b.png
def volume(r, t=1):
    return -2 * np.pi * r * ml.head(r, 0, t) * ml.aq.Scoefaq[0]


quad(volume, 1e-5, np.inf)
(788.0000039400179, 2.21657566933235e-07)
def theis2(r, t, T, S, Q, tend):
    u1 = r**2 * S / (4 * T * t)
    u2 = r**2 * S / (4 * T * (t[t > tend] - tend))
    h = -Q / (4 * np.pi * T) * exp1(u1)
    h[t > tend] -= -Q / (4 * np.pi * T) * exp1(u2)
    return h
ml2 = tft.ModelMaq(kaq=25, z=[20, 0], Saq=S / 20, tmin=1e-5, tmax=10)
w2 = tft.Well(ml2, tsandQ=[(0, Q), (1, 0)])
ml2.solve()
self.neq  1
solution complete
t2 = np.linspace(0.01, 2, 100)
htheis2 = theis2(r, t2, T, S, Q, tend=1)
h2 = ml2.head(r, 0, t2)
plt.plot(t2, htheis2, "b", label="theis")
plt.plot(t2, h2[0], "r--", label="timflow")
plt.legend(loc="best")
plt.grid()
../../_images/3a9ef693b07593d1d9fc33236a91766fc6036fff45f1b79f99ccb4e0aeeb11b9.png

Hantush#

T = 500
S = 1e-4
c = 1000
t = np.logspace(-5, 0, 100)
r = 30
Q = 788
from scipy.integrate import quad


def integrand_hantush(y, r, lab):
    return np.exp(-y - r**2 / (4 * lab**2 * y)) / y


def hantush(r, t, T, S, c, Q, tstart=0):
    lab = np.sqrt(T * c)
    u = r**2 * S / (4 * T * (t - tstart))
    F = quad(integrand_hantush, u, np.inf, args=(r, lab))[0]
    return -Q / (4 * np.pi * T) * F


hantushvec = np.vectorize(hantush)
ml = tft.ModelMaq(
    kaq=25, z=[21, 20, 0], c=[1000], Saq=S / 20, topboundary="semi", tmin=1e-5, tmax=1
)
w = tft.Well(ml, tsandQ=[(0, Q)])
ml.solve()
self.neq  1
solution complete
hhantush = hantushvec(30, t, T, S, c, Q)
h = ml.head(r, 0, t)
plt.semilogx(t, hhantush, "b", label="hantush")
plt.semilogx(t, h[0], "r--", label="timflow")
plt.legend(loc="best")
plt.grid()
../../_images/46030b77694a0e369e070e6fa36e0f74467e036b005937b3d2ef1faf8b23ad6e.png

Well with welbore storage#

T = 500
S = 1e-4
t = np.logspace(-5, 0, 100)
rw = 0.3
Q = 788

ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=S / 20, tmin=1e-5, tmax=1)
w = tft.Well(ml, rw=rw, tsandQ=[(0, Q)])
ml.solve()
hnostorage = ml.head(rw, 0, t)

ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=S / 20, tmin=1e-5, tmax=1)
w = tft.Well(ml, rw=rw, tsandQ=[(0, Q)], rc=rw)
ml.solve()
hstorage = ml.head(rw, 0, t)

plt.semilogx(t, hnostorage[0], label="no storage")
plt.semilogx(t, hstorage[0], label="with storage")
plt.legend(loc="best")
plt.xticks(
    [1 / (24 * 60 * 60), 1 / (24 * 60), 1 / 24, 1], ["1 sec", "1 min", "1 hr", "1 d"]
)
plt.grid()
self.neq  1
solution complete
self.neq  1
solution complete
../../_images/a341a4aadb0ad48edce7fc12d147cd1bd0f4bda08ea1ba00dc54c17f76d1bae9.png

Slug test#

k = 25
H = 20
S = 1e-4 / H
t = np.logspace(-7, -1, 100)
rw = 0.2
rc = 0.2
delh = 1
ml = tft.ModelMaq(kaq=k, z=[H, 0], Saq=S, tmin=1e-7, tmax=1)
Qslug = np.pi * rc**2 * delh
w = tft.Well(ml, tsandQ=[(0, -Qslug)], rw=rw, rc=rc, wbstype="slug")
ml.solve()
h = w.headinside(t)
plt.semilogx(t, h[0])
plt.xticks(
    [1 / (24 * 60 * 60) / 10, 1 / (24 * 60 * 60), 1 / (24 * 60), 1 / 24],
    ["0.1 sec", "1 sec", "1 min", "1 hr"],
)
plt.grid()
self.neq  1
solution complete
../../_images/9d037da4f5cf57f81c03835d372aa950838db46b72f31618f782b48c8dd42330.png

Slug test in 5-layer aquifer#

Well in top 2 layers

k = 25
H = 20
Ss = 1e-4 / H
t = np.logspace(-7, -1, 100)
rw = 0.2
rc = 0.2
delh = 1
ml = tft.Model3D(kaq=k, z=np.linspace(H, 0, 6), Saq=Ss, tmin=1e-7, tmax=1)
Qslug = np.pi * rc**2 * delh
w = tft.Well(ml, tsandQ=[(0, -Qslug)], rw=rw, rc=rc, layers=[0, 1], wbstype="slug")
ml.solve()
hw = w.headinside(t)
plt.semilogx(t, hw[0], label="inside well")
h = ml.head(0.2 + 1e-8, 0, t)
for i in range(2, 5):
    plt.semilogx(t, h[i], label="layer" + str(i))
plt.legend()
plt.xticks(
    [1 / (24 * 60 * 60) / 10, 1 / (24 * 60 * 60), 1 / (24 * 60), 1 / 24],
    ["0.1 sec", "1 sec", "1 min", "1 hr"],
)
plt.grid()
self.neq  2
solution complete
../../_images/cd9c1a63198147645b24eca806351ee7be1ee0e1716b008138ce00af92c2c51b.png

20 layers

k = 25
H = 20
S = 1e-4 / H
t = np.logspace(-7, -1, 100)
rw = 0.2
rc = 0.2
delh = 1
ml = tft.Model3D(kaq=k, z=np.linspace(H, 0, 21), Saq=S, tmin=1e-7, tmax=1)
Qslug = np.pi * rc**2 * delh
w = tft.Well(ml, tsandQ=[(0, -Qslug)], rw=rw, rc=rc, layers=np.arange(8), wbstype="slug")
ml.solve()
hw = w.headinside(t)
plt.semilogx(t, hw[0], label="inside well")
h = ml.head(0.2 + 1e-8, 0, t)
for i in range(8, 20):
    plt.semilogx(t, h[i], label="layer" + str(i))
plt.legend()
plt.xticks(
    [1 / (24 * 60 * 60) / 10, 1 / (24 * 60 * 60), 1 / (24 * 60), 1 / 24],
    ["0.1 sec", "1 sec", "1 min", "1 hr"],
)
plt.grid()
self.neq  8
solution complete
../../_images/0c38b348c15961a9aa6644087a3d8ad8f08c4989fc2de967cd16ca42f5c32f4a.png

Head Well#

ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=1e-5, tmin=1e-3, tmax=1000)
w = tft.HeadWell(ml, tsandh=[(0, -1)], rw=0.2)
ml.solve()
ax0 = plt.subplot(1, 2, 1)
ml.plots.head_along_line(0.2, 100, 0, 0, 100, t=[0.1, 1, 10], sstart=0.2, ax=ax0)
t = np.logspace(-3, 3, 100)
dis = w.discharge(t)
ax1 = plt.subplot(1, 2, 2)
plt.semilogx(t, dis[0], label="$r_w$=0.2")
ml = tft.ModelMaq(kaq=25, z=[20, 0], Saq=1e-5, tmin=1e-3, tmax=1000)
w = tft.HeadWell(ml, tsandh=[(0, -1)], rw=0.3)
ml.solve()
dis = w.discharge(t)
plt.semilogx(t, dis[0], label="$r_w$=0.3")
plt.xlabel("time (d)")
plt.ylabel("discharge (m3/d)")
ax0.legend()
ax1.legend()
ax1.grid()
self.neq  1
solution complete
self.neq  1
solution complete
../../_images/6bff08d2efa5e382219c2a2230a369daa469eac95413a080b36a1e38b5742841.png