3. Synthetic Pumping Test - Calibration test#

import matplotlib.pyplot as plt
import numpy as np

import ttim

Use observation times from Oude Korendijk#

drawdown = np.loadtxt("data/oudekorendijk_h30.dat")
tobs = drawdown[:, 0] / 60 / 24
robs = 30
Q = 788

Generate data#

ml = ttim.ModelMaq(kaq=60, z=(-18, -25), Saq=1e-4, tmin=1e-5, tmax=1)
w = ttim.Well(ml, xw=0, yw=0, rw=0.1, tsandQ=[(0, 788)], layers=0)
ml.solve()
rnd = np.random.default_rng(2)
hobs = ml.head(robs, 0, tobs)[0] + 0.05 * rnd.random(len(tobs))
self.neq  1
solution complete

See if TTim can find aquifer parameters back#

cal = ttim.Calibrate(ml)
cal.set_parameter(name="kaq0", layers=0, initial=100)
cal.set_parameter(name="Saq0", layers=0, initial=1e-3)
cal.series(name="obs1", x=robs, y=0, layer=0, t=tobs, h=hobs)
cal.fit()
................................
....
Fit succeeded.
cal.parameters
layers optimal std perc_std pmin pmax initial inhoms parray
kaq0_0_0 0 59.871358 0.670180 1.119366 -inf inf 100.000 None [[59.87135844623144]]
Saq0_0_0 0 0.000121 0.000004 3.633645 -inf inf 0.001 None [[0.00012118958795889718]]
print("rmse:", cal.rmse())
rmse: 0.014201293762177191
hm = ml.head(robs, 0, tobs, 0)
plt.semilogx(tobs, hobs, ".k")
plt.semilogx(tobs, hm[0], "r");
../_images/25db8476eee45971ce8f67a2b39d0fc4f4ffed38306ff064012244665f3ef5ea.png
print("correlation matrix")
print(cal.fitresult.covar)
correlation matrix
[[ 4.49140659e-01 -2.49689444e-06]
 [-2.49689444e-06  1.93916877e-11]]

Fit with scipy.least_squares (not recommended)

cal = ttim.Calibrate(ml)
cal.set_parameter(name="kaq0", layers=0, initial=100)
cal.set_parameter(name="Saq0", layers=0, initial=1e-3)
cal.series(name="obs1", x=robs, y=0, layer=0, t=tobs, h=hobs)
cal.fit_least_squares(report=True)
.............................
...
.....
          layers    optimal       std  perc_std  pmin  pmax  initial inhoms  \
kaq0_0_0       0  59.870508  0.660039  1.102444  -inf   inf  100.000   None   
Saq0_0_0       0   0.000121  0.000004  3.590870  -inf   inf    0.001   None   

                              parray  
kaq0_0_0       [[59.87050842164771]]  
Saq0_0_0  [[0.00012119687595438834]]  
[6.60038547e-01 4.35202240e-06]
[[ 4.35650883e-01 -2.42868661e-06]
 [-2.42868661e-06  1.89400989e-11]]
[[ 1.         -0.84549503]
 [-0.84549503  1.        ]]

Calibrate parameters in multiple layers#

Example showing how parameters can be optimized when multiple layers share the same parameter value.

ml = ttim.ModelMaq(
    kaq=[10.0, 10.0],
    z=(-10, -16, -18, -25),
    c=[10.0],
    Saq=[0.1, 1e-4],
    tmin=1e-5,
    tmax=1,
)
w = ttim.Well(ml, xw=0, yw=0, rw=0.1, tsandQ=[(0, 788)], layers=1)
ml.solve()
hobs0 = ml.head(robs, 0, tobs, layers=[0])[0]
hobs1 = ml.head(robs, 0, tobs, layers=[1])[0]
self.neq  1
solution complete
cal.parameters
layers optimal std perc_std pmin pmax initial inhoms parray
kaq0_0_0 0 59.870508 0.660039 1.102444 -inf inf 100.000 None [[59.87050842164771]]
Saq0_0_0 0 0.000121 0.000004 3.590870 -inf inf 0.001 None [[0.00012119687595438834]]
cal = ttim.Calibrate(ml)
cal.set_parameter(
    name="kaq0_1", layers=[0, 1], initial=20.0, pmin=0.0, pmax=30.0
)  # layers 0 and 1 have the same k-value
cal.set_parameter(name="Saq0", layers=0, initial=1e-3, pmin=1e-5, pmax=0.2)
cal.set_parameter(name="Saq1", layers=1, initial=1e-3, pmin=1e-5, pmax=0.2)
cal.set_parameter(name="c1", layers=1, initial=1.0, pmin=0.1, pmax=200.0)
cal.series(name="obs0", x=robs, y=0, layer=0, t=tobs, h=hobs0)
cal.series(name="obs1", x=robs, y=0, layer=1, t=tobs, h=hobs1)
cal.fit(report=False)
display(cal.parameters)
...............
...
...
..
...
..............
...
....
.
...
..............
...
....
.
....
..............
..
....
.
....
...
Fit succeeded.
layers optimal std perc_std pmin pmax initial inhoms parray
kaq0_1_0_1 [0, 1] 9.999129 2.442992e-04 0.002443 0.00000 30.0 20.000 None [[9.999129279917383, 9.999129279917383]]
Saq0_0_0 0 0.100008 2.537887e-07 0.000254 0.00001 0.2 0.001 None [[0.10000758667299027]]
Saq1_1_1 1 0.000100 8.769699e-10 0.000877 0.00001 0.2 0.001 None [[9.999637318907012e-05]]
c1_1_1 1 9.999744 7.389049e-05 0.000739 0.10000 200.0 1.000 None [[9.999743718534136]]
plt.semilogx(tobs, hobs0, ".C0", label="obs layer 0")
plt.semilogx(tobs, hobs1, ".C1", label="obs layer 1")

hm = ml.head(robs, 0, tobs)
plt.semilogx(tobs, hm[0], "C0", label="modelled head layer 0")
plt.semilogx(tobs, hm[1], "C1", label="modelled head layer 1")

plt.legend(loc="best");
../_images/7d8aac6fe17f7804650cea5b539b0e8944d7b10c736c621d77eb3c4f770d9a77.png

Generate data for head measured in well#

tobs2 = np.hstack((tobs, np.arange(0.61, 1, 0.01)))
ml = ttim.ModelMaq(kaq=60, z=(-18, -25), Saq=1e-4, tmin=1e-5, tmax=1)
w = ttim.Well(ml, xw=0, yw=0, rw=0.3, res=0.02, tsandQ=[(0, 788), (0.6, 0)], layers=0)
ml.solve()
rnd = np.random.default_rng(2)
hobs2 = w.headinside(tobs2)[0] + 0.05 * rnd.random(len(tobs2))
self.neq  1
solution complete
cal = ttim.Calibrate(ml)
cal.set_parameter(name="kaq0", layers=0, initial=100)
cal.set_parameter(name="Saq0", layers=0, initial=1e-3)
cal.set_parameter_by_reference(name="res", parameter=w.res[:], initial=0.05)
cal.seriesinwell(name="obs1", element=w, t=tobs2, h=hobs2)
cal.fit()
..
...........................
...
.
...........................
...
.
............................
..
.
.............................
.
.
.............................
.
.
.............................
..
..............................
.
..............................
...............................
...............................
...............................
................................
...............................
Fit succeeded.
hm = w.headinside(tobs2)
plt.semilogx(tobs2, hobs2, ".k")
plt.semilogx(tobs2, hm[0], "r");
../_images/67b92260dc0baec30e47b7168b1cf1ea9904ede8f008eb60310ed2fd03c24f8a.png