{ "cells": [ { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "# 2. Leaky Aquifer Test - Hardinxveld " ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Import packages" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "\n", "import timflow.transient as tft\n", "\n", "plt.rcParams[\"figure.figsize\"] = [5, 3]" ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Introduction and Conceptual Model\n", "\n", "Consider a pumping test conducted near the town of Hardinxveld-Giessendam in the Netherlands in 1981. The objective was to quantify the aquifer parameters and the head-loss at the pumping well caused by clogging.\n", "The subsurface consists of a 10 meter thick aquitard, followed by a 27 m aquifer. Below the aquifer is another aquitard of 31 m thickness and a 20 m thick second aquifer. \n", "Five pumping wells are screened in the first aquifer. Drawdown measurements at of one of wells is obtained from the MLU documentation (Carlson & Randall, 2012). The pumping well was operated for 20 minutes at 1848 m$^3$/d. Drawdown was measured inside the pumping well during pumping and during 30 minutes of recovery. The radius of the pumped well is 0.155 m. Two `timflow` models are calibrated. The first one has an impermeable top and bottom. For the second model, the effect of the semi-confining top and the aquitard and aquifer below the pumped aquifer are combined into one semi-confining layer. By trial and error, the resistance of this semi-confining layer was set to $c=2000$ d. For both models, three parameters are calibrated: the hydraulic conductivity and specific storage of the aquifer and the skin resistance of the well. " ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Load data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = np.loadtxt(\"data/recovery.txt\", skiprows=1)\n", "to = data[:, 0]\n", "ho = data[:, 1]" ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Parameters and model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# known parameters\n", "H = 27 # aquifer thickness, m\n", "zt = -10 # upper boundary of aquifer, m\n", "zb = zt - H # lower boundary of the aquifer, m\n", "rw = 0.155 # well screen radius, m\n", "Q = 1848 # constant discharge rate, m^3/d\n", "tstop = 0.013889 # time at which pumping stops, d" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# model with impermeable top and bottom\n", "ml = tft.ModelMaq(\n", " kaq=[50],\n", " z=[zt, zb],\n", " Saq=[1e-4],\n", " topboundary=\"conf\",\n", " tmin=1e-4,\n", " tmax=1,\n", ")\n", "w = tft.Well(ml, xw=0, yw=0, rw=rw, res=1, tsandQ=[(0, Q), (tstop, 0)], layers=0)\n", "ml.solve()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cal = tft.Calibrate(ml)\n", "cal.set_parameter(name=\"kaq\", initial=50, pmin=0, layers=0)\n", "cal.set_parameter(name=\"Saq\", initial=1e-4, pmin=0, pmax=1e-3, layers=0)\n", "\n", "cal.set_parameter_by_reference(name=\"res\", parameter=w.res[:], initial=1, pmin=0)\n", "cal.seriesinwell(name=\"obs\", element=w, t=to, h=ho)\n", "cal.fit(report=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display(cal.parameters.loc[:, [\"optimal\"]])\n", "print(f\"RMSE: {cal.rmse():.3f} m\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# model with semi-confining top\n", "ml1 = tft.ModelMaq(\n", " kaq=[50],\n", " z=[0, zt, zb],\n", " Saq=[1e-4],\n", " c=2000,\n", " topboundary=\"semi\",\n", " tmin=1e-4,\n", " tmax=1,\n", ")\n", "w1 = tft.Well(ml1, xw=0, yw=0, rw=rw, res=1, tsandQ=[(0, Q), (tstop, 0)], layers=0)\n", "ml1.solve()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cal1 = tft.Calibrate(ml1)\n", "cal1.set_parameter(name=\"kaq\", initial=50, pmin=0, layers=0)\n", "cal1.set_parameter(name=\"Saq\", initial=1e-4, pmin=0, pmax=1e-3, layers=0)\n", "\n", "cal1.set_parameter_by_reference(name=\"res\", parameter=w1.res[:], initial=1, pmin=0)\n", "cal1.seriesinwell(name=\"obs\", element=w1, t=to, h=ho)\n", "cal1.fit(report=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display(cal1.parameters[[\"optimal\"]])\n", "print(f\"RMSE: {cal1.rmse(weighted=False):.3f} m\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "tm = np.logspace(np.log10(to[0]), np.log10(to[-1]), 100)\n", "h = w.headinside(tm)\n", "h1 = w1.headinside(tm)\n", "plt.loglog(to, -ho, \".\", label=\"observed\")\n", "plt.loglog(tm, -h[0], label=\"timflow confined\")\n", "plt.loglog(tm, -h1[0], label=\"timflow semi-confined\")\n", "plt.xlabel(\"time [d]\")\n", "plt.ylabel(\"drawdown [m]\")\n", "plt.legend()\n", "plt.title(\"Model Results\")\n", "plt.grid()" ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### Comparison of results" ] }, { "cell_type": "markdown", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "The performance of `timflow` is compared to MLU (Hemker and Post, 2014). \n", "\n", "With the MLU the deeper layers are also included in the aquifer system. Although little information about the deeper layers\n", "is available, they are included because of the principle that including guessed properties of little-known layers is preferable to disregarding them altogether. The entered values for c1 and c2 (1000 d), T2 (800 m2/d) and S2 (0.001) are rough estimates,\n", "based on regional pumping test information.\n", "\n", "The MLU parameters are similar to the `timflow` parameters for the confined case. The semi-confined case gives somewhat lower RMSE and a slightly better fit. It is noted that this model is exceedingly sensitive to the specified moment that the well is turned off. Even a change of 1 second will produce significantly different results. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "t = pd.DataFrame(\n", " columns=[\"k [m/d]\", \"Ss [1/m]\", \"res\", \"RMSE [m]\"],\n", " index=[\"timflow confined\", \"timflow semi-confined\", \"MLU\"],\n", ")\n", "\n", "t.loc[\"timflow confined\"] = np.append(cal.parameters[\"optimal\"].values, cal.rmse())\n", "t.loc[\"timflow semi-confined\"] = np.append(cal1.parameters[\"optimal\"].values, cal1.rmse())\n", "t.loc[\"MLU\"] = [48.94241, 1.037e-05, 0.0007349, 0.00756]\n", "\n", "t_formatted = t.style.format(\n", " {\"k [m/d]\": \"{:.2f}\", \"Ss [1/m]\": \"{:.2e}\", \"res\": \"{:.3f}\", \"RMSE [m]\": \"{:.4f}\"}\n", ")\n", "t_formatted" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References\n", "\n", "* Hemker, K. en Post V. (2014) MLU for Windows: well flow modeling in multilayer aquifer systems; MLU User's guide. https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmicrofem.com%2Fdownload%2Fmlu-user.pdf&data=05%7C02%7CMark.Bakker%40tudelft.nl%7Cad7f16364d2d4fd55dbf08de73832eaa%7C096e524d692940308cd38ab42de0887b%7C0%7C0%7C639075204580287861%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=OBoe8seXZUfoat89Dfr4g6lF%2Bn1FdtXqtp%2F18BMXCn0%3D&reserved=0\n", "* Newville, M., Stensitzki, T., Allen, D.B. and Ingargiola, A. (2014), LMFIT: Non Linear Least-Squares Minimization and Curve Fitting for Python, https://dx.doi.org/10.5281/zenodo.11813, https://lmfit.github.io/lmfit-py/intro.html (last access: August,2021)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.3" } }, "nbformat": 4, "nbformat_minor": 4 }