Getting started¶
Install¶
The package is not on PyPI yet. Install it from GitHub:
pip install git+https://github.com/GeoPilot-AI/pumptest
It needs Python 3.11 or later, numpy and scipy.
Units: one consistent set¶
The solvers work in the units they are given, so lengths, times and rates
must use one consistent set, and the results come back in it. Metres, days and cubic metres
per day is the usual choice, and gives transmissivity in square metres per
day. Convert field units first with pumptest.units:
from pumptest.units import convert, drawdown_from_levels
rate = float(convert(250, "lpm", "m3/d")) # 250 litres per minute = 360 m3/d
minutes = [1, 2, 5, 10, 30, 60]
days = convert(minutes, "min", "d")
drawdown = drawdown_from_levels([12.31, 12.45, 12.70, 12.88, 13.20, 13.41], static_level=12.05)
convert knows metres, centimetres, millimetres, feet and inches; seconds,
minutes, hours and days; and cubic metres, litres, US and imperial gallons and
cubic feet per second, minute, hour or day (lpm, lps, m3/h, gpm,
cfs and so on).
Describe the test¶
A test is a pumping well, a pumping schedule and one or more observations.
import numpy as np
from pumptest import Observation, PumpingTest, Schedule, Well
t = np.array([0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5]) # days
s = np.array([0.05, 0.11, 0.21, 0.29, 0.37, 0.48, 0.56, 0.64, 0.75]) # metres
test = PumpingTest(
well=Well(radius=0.1),
schedule=Schedule.constant(500.0), # m3/d from time zero
observations=[Observation("OW-1", distance=25.0, time=t, drawdown=s)],
thickness=20.0,
)
distance=0means the observation is in the pumping well itself.Schedule.constant(500, stop=0.5)adds recovery from day 0.5;Schedule(((0, 300), (0.1, 600), (0.2, 900)))is a step test.thicknessis needed by the unconfined solution, and to report K = T/b.
Fit a model¶
from pumptest import Theis, fit
result = fit(test, Theis())
print(result.summary())
print(result.values["T"], result.standard_errors["T"])
result.values holds the estimates, result.standard_errors their
one-sigma errors, result.derived quantities such as K, result.rmse the
misfit in the drawdown unit, and result.residuals the misfit at each
observation.
Hold a parameter at a known value with fixed, fit only some wells with
observations, or give your own starting point with initial:
result = fit(test, Theis(), fixed={"S": 2e-4})
Compare models¶
from pumptest import HantushJacob, Neuman, compare
for r in compare(test, [Theis(), HantushJacob(), Neuman()]):
print(f"{r.model:15} AICc {r.aicc:8.1f} RMSE {r.rmse:.4f}")
compare ranks by AICc, which penalises every extra parameter: a leaky or
unconfined model wins only when it fits enough better to earn its extra
parameters.