From 998b86fc128e35f1506e3d4facb169c558679bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Wed, 30 Aug 2023 10:24:46 +0200 Subject: [PATCH 1/9] black + isort --- notebooks/benchmarking_besselaes.ipynb | 143 ++-- notebooks/circareasink_example.ipynb | 16 +- notebooks/circular_buildingpit.ipynb | 14 +- notebooks/lake_horizontal_well.ipynb | 42 +- notebooks/lscontainer.ipynb | 8 +- notebooks/test_linesink_discharge.ipynb | 77 +- notebooks/test_polygon_areasink.ipynb | 27 +- notebooks/test_well_near_lake.ipynb | 16 +- notebooks/timml_besselaesnew_test.ipynb | 125 ++- notebooks/timml_figures.ipynb | 72 +- notebooks/timml_notebook0_sol.ipynb | 140 +++- notebooks/timml_notebook1_sol.ipynb | 74 +- notebooks/timml_notebook2_sol.ipynb | 93 ++- notebooks/timml_notebook3_3D_sol.ipynb | 102 ++- notebooks/timml_notebook3_sol.ipynb | 167 +++- notebooks/timml_notebook4_sol.ipynb | 66 +- notebooks/timml_notebook5_sol.ipynb | 36 +- notebooks/timml_notebook6_sol.ipynb | 105 ++- notebooks/timml_notebook7.ipynb | 35 +- notebooks/timml_xsection.ipynb | 267 +++++-- tests/test_besselaes.py | 68 +- tests/test_import.py | 3 +- tests/test_notebooks.py | 48 +- timml/aquifer.py | 60 +- timml/aquifer_parameters.py | 111 +-- timml/besselaesnumba/besselaesnumba.py | 27 +- timml/besselaesnumba/besselaesnumba_old.py | 32 +- timml/circareasink.py | 105 ++- timml/circinhom.py | 398 ++++++---- timml/constant.py | 120 +-- timml/controlpoints.py | 16 +- timml/element.py | 113 +-- timml/equation.py | 337 +++++--- timml/inhomogeneity.py | 488 ++++++++---- timml/inhomogeneity1d.py | 110 ++- timml/intlinesink.py | 249 ++++-- timml/linedoublet.py | 380 ++++++--- timml/linedoublet1d.py | 106 ++- timml/linesink.py | 857 ++++++++++++++------- timml/linesink1d.py | 187 +++-- timml/model.py | 304 ++++---- timml/stripareasink.py | 159 ++-- timml/trace.py | 106 ++- timml/uflow.py | 34 +- timml/util.py | 131 +++- timml/version.py | 4 +- timml/well.py | 167 +++- 47 files changed, 4317 insertions(+), 2028 deletions(-) diff --git a/notebooks/benchmarking_besselaes.ipynb b/notebooks/benchmarking_besselaes.ipynb index 1c043ca5..5e3055de 100644 --- a/notebooks/benchmarking_besselaes.ipynb +++ b/notebooks/benchmarking_besselaes.ipynb @@ -24,7 +24,7 @@ "import pandas as pd\n", "\n", "import matplotlib as mpl\n", - "import matplotlib.pyplot as plt\n" + "import matplotlib.pyplot as plt" ] }, { @@ -72,7 +72,7 @@ "def ctxt(val):\n", " bg = cmap(norm(val))\n", " c = \"White\" if np.mean(bg[:3]) < 0.4 else \"Black\"\n", - " return f\"color: {c}\"\n" + " return f\"color: {c}\"" ] }, { @@ -144,7 +144,7 @@ " ls2 = timml.HeadLineSinkString(ml, xy=xy2, hls=hls2, layers=0)\n", " ls3 = timml.HeadLineSinkString(ml, xy=xy3, hls=hls3, layers=0)\n", " ls4 = timml.HeadLineSinkString(ml, xy=xy4, hls=hls4, layers=0)\n", - " \n", + "\n", " return ml" ] }, @@ -179,31 +179,29 @@ "print(timml.bessel.bessel) # print module name to check if switch works\n", "\n", "for nproc in df_ls.index:\n", - " \n", " ml = model1()\n", - " \n", + "\n", " if nproc == 0:\n", " t_n = %timeit -o ml.solve(silent=True)\n", " else:\n", " t_n = %timeit -o ml.solve_mp(nproc=nproc, silent=True)\n", - " \n", + "\n", " df_ls.loc[nproc, \"numba\"] = t_n.average\n", "\n", "# %%\n", "# Fortran\n", - "timml.bessel.set_bessel_method(method=\"fortran\") \n", + "timml.bessel.set_bessel_method(method=\"fortran\")\n", "print(timml.bessel.bessel) # print module name to check if switch works\n", "\n", "for nproc in df_ls.index:\n", - "\n", " ml = model1()\n", "\n", " if nproc == 0:\n", " t_f = %timeit -o ml.solve(silent=True)\n", " else:\n", " t_f = %timeit -o ml.solve_mp(nproc=nproc, silent=True)\n", - " \n", - " df_ls.loc[nproc, \"fortran\"] = t_f.average\n" + "\n", + " df_ls.loc[nproc, \"fortran\"] = t_f.average" ] }, { @@ -308,7 +306,7 @@ "norm = mpl.colors.LogNorm(vmin=50, vmax=100)\n", "\n", "df_ls.index.name = \"nproc\"\n", - "(df_ls * 1e3).style.applymap(cbg).applymap(ctxt)\n" + "(df_ls * 1e3).style.applymap(cbg).applymap(ctxt)" ] }, { @@ -471,15 +469,45 @@ " layers = np.arange(np.sum(z_dw <= ml.aq.zaqbot))\n", " last_lay_dw = layers[-1]\n", "\n", - " inhom = timml.BuildingPit(ml, xy, kaq=kh_arr, z=z[1:], topboundary=\"conf\", \n", - " c=c[1:], order=4, ndeg=3, layers=layers)\n", + " inhom = timml.BuildingPit(\n", + " ml,\n", + " xy,\n", + " kaq=kh_arr,\n", + " z=z[1:],\n", + " topboundary=\"conf\",\n", + " c=c[1:],\n", + " order=4,\n", + " ndeg=3,\n", + " layers=layers,\n", + " )\n", "\n", - " timml.HeadLineSink(ml, x1=-l/2+offset, y1=b/2-offset, x2=l/2-offset, y2=b/2-offset, hls=h_bem, \n", - " layers=np.arange(last_lay_dw+1))\n", - " timml.HeadLineSink(ml, x1=-l/2+offset, y1=0, x2=l/2-offset, y2=0, hls=h_bem, \n", - " layers=np.arange(last_lay_dw+1))\n", - " timml.HeadLineSink(ml, x1=-l/2+offset, y1=-b/2+offset, x2=l/2-offset, y2=-b/2+offset, hls=h_bem, \n", - " layers=np.arange(last_lay_dw+1))\n", + " timml.HeadLineSink(\n", + " ml,\n", + " x1=-l / 2 + offset,\n", + " y1=b / 2 - offset,\n", + " x2=l / 2 - offset,\n", + " y2=b / 2 - offset,\n", + " hls=h_bem,\n", + " layers=np.arange(last_lay_dw + 1),\n", + " )\n", + " timml.HeadLineSink(\n", + " ml,\n", + " x1=-l / 2 + offset,\n", + " y1=0,\n", + " x2=l / 2 - offset,\n", + " y2=0,\n", + " hls=h_bem,\n", + " layers=np.arange(last_lay_dw + 1),\n", + " )\n", + " timml.HeadLineSink(\n", + " ml,\n", + " x1=-l / 2 + offset,\n", + " y1=-b / 2 + offset,\n", + " x2=l / 2 - offset,\n", + " y2=-b / 2 + offset,\n", + " hls=h_bem,\n", + " layers=np.arange(last_lay_dw + 1),\n", + " )\n", "\n", " return ml" ] @@ -511,33 +539,31 @@ "source": [ "df_bp = pd.DataFrame(index=nproc_list, columns=[\"numba\", \"fortran\"])\n", "\n", - "timml.bessel.set_bessel_method(method=\"numba\") \n", + "timml.bessel.set_bessel_method(method=\"numba\")\n", "print(timml.bessel.bessel)\n", "\n", "for nproc in df_bp.index:\n", - "\n", " ml = model2()\n", "\n", " if nproc == 0:\n", " t_n = %timeit -o ml.solve(silent=True)\n", " else:\n", " t_n = %timeit -o ml.solve_mp(nproc=nproc, silent=True)\n", - " \n", + "\n", " df_bp.loc[nproc, \"numba\"] = t_n.average\n", "\n", "timml.bessel.set_bessel_method(method=\"fortran\")\n", "print(timml.bessel.bessel)\n", "\n", "for nproc in df_bp.index:\n", - "\n", " ml = model2()\n", - " \n", + "\n", " if nproc == 0:\n", " t_f = %timeit -o ml.solve(silent=True)\n", " else:\n", " t_f = %timeit -o ml.solve_mp(nproc=nproc, silent=True)\n", - " \n", - " df_bp.loc[nproc, \"fortran\"] = t_f.average\n" + "\n", + " df_bp.loc[nproc, \"fortran\"] = t_f.average" ] }, { @@ -770,15 +796,48 @@ "source": [ "def model3():\n", " ml = timml.ModelMaq(kaq=[10, 20], z=[20, 0, -10, -30], c=[4000])\n", - " xy1 = [(0, 600), (-100, 400), (-100, 200), (100, 100), (300, 100), (500, 100),\n", - " (700, 300), (700, 500), (600, 700), (400, 700), (200, 600)]\n", - " p1 = timml.PolygonInhomMaq(ml, xy=xy1, \n", - " kaq=[2, 80], z=[20, 0, -10, -30], c=[500], \n", - " topboundary='conf', order=4, ndeg=2)\n", - " xy2 = [(0, 600), (200, 600), (400, 700), (400, 900), (200, 1100), (0, 1000), (-100, 800)]\n", - " p2 = timml.PolygonInhomMaq(ml, xy=xy2, \n", - " kaq=[2, 8], z=[20, 0, -10, -30], c=[50], \n", - " topboundary='conf', order=4, ndeg=2)\n", + " xy1 = [\n", + " (0, 600),\n", + " (-100, 400),\n", + " (-100, 200),\n", + " (100, 100),\n", + " (300, 100),\n", + " (500, 100),\n", + " (700, 300),\n", + " (700, 500),\n", + " (600, 700),\n", + " (400, 700),\n", + " (200, 600),\n", + " ]\n", + " p1 = timml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy1,\n", + " kaq=[2, 80],\n", + " z=[20, 0, -10, -30],\n", + " c=[500],\n", + " topboundary=\"conf\",\n", + " order=4,\n", + " ndeg=2,\n", + " )\n", + " xy2 = [\n", + " (0, 600),\n", + " (200, 600),\n", + " (400, 700),\n", + " (400, 900),\n", + " (200, 1100),\n", + " (0, 1000),\n", + " (-100, 800),\n", + " ]\n", + " p2 = timml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy2,\n", + " kaq=[2, 8],\n", + " z=[20, 0, -10, -30],\n", + " c=[50],\n", + " topboundary=\"conf\",\n", + " order=4,\n", + " ndeg=2,\n", + " )\n", " rf = timml.Constant(ml, xr=1000, yr=0, hr=40)\n", " uf = timml.Uflow(ml, slope=0.002, angle=-45)\n", " w = timml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", @@ -812,33 +871,31 @@ "source": [ "df = pd.DataFrame(index=nproc_list, columns=[\"numba\", \"fortran\"])\n", "\n", - "timml.bessel.set_bessel_method(method=\"numba\") \n", + "timml.bessel.set_bessel_method(method=\"numba\")\n", "print(timml.bessel.bessel)\n", "\n", "for nproc in df.index:\n", - "\n", " ml = model3()\n", "\n", " if nproc == 0:\n", " t_n = %timeit -o ml.solve(silent=True)\n", " else:\n", " t_n = %timeit -o ml.solve_mp(nproc=nproc, silent=True)\n", - " \n", + "\n", " df.loc[nproc, \"numba\"] = t_n.average\n", "\n", - "timml.bessel.set_bessel_method(method=\"fortran\") \n", + "timml.bessel.set_bessel_method(method=\"fortran\")\n", "print(timml.bessel.bessel)\n", "\n", "for nproc in df.index:\n", - "\n", " ml = model3()\n", - " \n", + "\n", " if nproc == 0:\n", " t_f = %timeit -o ml.solve(silent=True)\n", " else:\n", " t_f = %timeit -o ml.solve_mp(nproc=nproc, silent=True)\n", - " \n", - " df.loc[nproc, \"fortran\"] = t_f.average\n" + "\n", + " df.loc[nproc, \"fortran\"] = t_f.average" ] }, { diff --git a/notebooks/circareasink_example.ipynb b/notebooks/circareasink_example.ipynb index 1c729cb9..6e7f0980 100644 --- a/notebooks/circareasink_example.ipynb +++ b/notebooks/circareasink_example.ipynb @@ -67,9 +67,9 @@ "for i in range(len(x)):\n", " qx[i], qy = ml.disvec(x[i], 1e-6)\n", "plt.plot(x, qx)\n", - "qxb = N * np.pi * R ** 2 / (2 * np.pi * R)\n", - "plt.axhline(qxb, color='r', ls='--')\n", - "plt.axhline(-qxb, color='r', ls='--');" + "qxb = N * np.pi * R**2 / (2 * np.pi * R)\n", + "plt.axhline(qxb, color=\"r\", ls=\"--\")\n", + "plt.axhline(-qxb, color=\"r\", ls=\"--\");" ] }, { @@ -101,7 +101,7 @@ "source": [ "N = 0.001\n", "R = 100\n", - "Q = N * np.pi * R ** 2\n", + "Q = N * np.pi * R**2\n", "ml = tml.ModelMaq(kaq=5, z=[10, 0])\n", "ca = tml.CircAreaSink(ml, xc=-200, yc=0, R=100, N=0.001)\n", "w = tml.Well(ml, 200, 0, Qw=Q, rw=0.1)\n", @@ -140,7 +140,7 @@ "source": [ "N = 0.001\n", "R = 100\n", - "Q = N * np.pi * R ** 2\n", + "Q = N * np.pi * R**2\n", "ml = tml.ModelMaq(kaq=5, z=[10, 0])\n", "ca = tml.CircAreaSink(ml, xc=-200, yc=0, R=100, N=0.001)\n", "w = tml.Well(ml, 200, 0, Qw=Q, rw=0.1)\n", @@ -184,7 +184,7 @@ "source": [ "N = 0.001\n", "R = 100\n", - "Q = N * np.pi * R ** 2\n", + "Q = N * np.pi * R**2\n", "ml = tml.ModelMaq(kaq=[5, 20], z=[20, 12, 10, 0], c=[1000])\n", "ca = tml.CircAreaSink(ml, xc=0, yc=0, R=100, N=0.001)\n", "w = tml.Well(ml, 0, 0, Qw=Q, rw=0.1, layers=1)\n", @@ -192,7 +192,7 @@ "ml.solve()\n", "x = np.linspace(-200, 200, 100)\n", "h = ml.headalongline(x, 0)\n", - "plt.plot(x, h[0]);\n", + "plt.plot(x, h[0])\n", "plt.plot(x, h[1]);" ] }, @@ -215,7 +215,7 @@ "source": [ "x = np.linspace(-1000, 1000, 101)\n", "h = ml.headalongline(x, 0)\n", - "plt.plot(x, h[0]);\n", + "plt.plot(x, h[0])\n", "plt.plot(x, h[1]);" ] }, diff --git a/notebooks/circular_buildingpit.ipynb b/notebooks/circular_buildingpit.ipynb index 693edba8..116e0231 100644 --- a/notebooks/circular_buildingpit.ipynb +++ b/notebooks/circular_buildingpit.ipynb @@ -39,7 +39,7 @@ "metadata": {}, "outputs": [], "source": [ - "R = 100.0 # radius of building pit" + "R = 100.0 # radius of building pit" ] }, { @@ -346,16 +346,16 @@ "Qr = disrvec(r) * 2 * np.pi * r\n", "plt.figure(figsize=(10, 3))\n", "plt.subplot(121)\n", - "plt.plot(r, h, label='head with wall')\n", - "plt.plot(r, head_nowall(r), '--', label='head no wall')\n", - "plt.xlabel('r (m)')\n", - "plt.ylabel('head (m)')\n", + "plt.plot(r, h, label=\"head with wall\")\n", + "plt.plot(r, head_nowall(r), \"--\", label=\"head no wall\")\n", + "plt.xlabel(\"r (m)\")\n", + "plt.ylabel(\"head (m)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.subplot(122)\n", "plt.plot(r, Qr)\n", - "plt.xlabel('r (m)')\n", - "plt.ylabel('$Q_r$ (m$^2$/d)')\n", + "plt.xlabel(\"r (m)\")\n", + "plt.ylabel(\"$Q_r$ (m$^2$/d)\")\n", "plt.grid()\n", "plt.tight_layout()" ] diff --git a/notebooks/lake_horizontal_well.ipynb b/notebooks/lake_horizontal_well.ipynb index 9d552bba..d7fcf274 100644 --- a/notebooks/lake_horizontal_well.ipynb +++ b/notebooks/lake_horizontal_well.ipynb @@ -50,8 +50,17 @@ "source": [ "ml = tml.ModelMaq(kaq=[1, 2], z=[10, 5, 4, 0], c=20)\n", "xy = [(-5, 0), (0, 0), (5, 0), (5, 8), (-5, 8)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy, kaq=[0.2, 8], z=[11, 10, 5, 4, 0], \n", - " c=[2, 20], topboundary='semi', hstar=1.0, order=3, ndeg=1)\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy,\n", + " kaq=[0.2, 8],\n", + " z=[11, 10, 5, 4, 0],\n", + " c=[2, 20],\n", + " topboundary=\"semi\",\n", + " hstar=1.0,\n", + " order=3,\n", + " ndeg=1,\n", + ")\n", "w = tml.Well(ml, xw=0, yw=-10, Qw=100, layers=1)\n", "rf = tml.Constant(ml, xr=0, yr=-100, hr=2)\n", "ml.solve()\n", @@ -107,8 +116,17 @@ "source": [ "ml = tml.ModelMaq(kaq=[1, 2], z=[10, 5, 4, 0], c=20)\n", "xy = [(-5, 0), (0, 0), (5, 0), (5, 8), (-5, 8)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy, kaq=[0.2, 8], z=[11,10,5,4,0], \n", - " c=[2, 20], topboundary='semi', hstar=1.0, order=5, ndeg=2)\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy,\n", + " kaq=[0.2, 8],\n", + " z=[11, 10, 5, 4, 0],\n", + " c=[2, 20],\n", + " topboundary=\"semi\",\n", + " hstar=1.0,\n", + " order=5,\n", + " ndeg=2,\n", + ")\n", "ls1 = tml.LineSinkDitchString(ml, [(0, -4), (0, 0), (0, 4)], 100, order=3, layers=[1])\n", "rf = tml.Constant(ml, xr=0, yr=-100, hr=2)\n", "ml.solve()\n", @@ -191,10 +209,18 @@ "source": [ "ml = tml.ModelMaq(kaq=[1, 2], z=[10, 5, 4, 0], c=20)\n", "xy = [(-5, 0), (0, 0), (5, 0), (5, 8), (-5, 8)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy, kaq=[1, 2], z=[11,10,5,4,0], \n", - " c=[2, 2], topboundary='semi', hstar=1.0, order=5, ndeg=2)\n", - "ls1 = tml.LineSinkDitchString(ml, [(0, -4), (0, 0), (0, 4)], 100, \\\n", - " order=3, layers=[1])\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy,\n", + " kaq=[1, 2],\n", + " z=[11, 10, 5, 4, 0],\n", + " c=[2, 2],\n", + " topboundary=\"semi\",\n", + " hstar=1.0,\n", + " order=5,\n", + " ndeg=2,\n", + ")\n", + "ls1 = tml.LineSinkDitchString(ml, [(0, -4), (0, 0), (0, 4)], 100, order=3, layers=[1])\n", "rf = tml.Constant(ml, xr=0, yr=-100, hr=2)\n", "ml.solve()\n", "\n", diff --git a/notebooks/lscontainer.ipynb b/notebooks/lscontainer.ipynb index 01bbf599..4ef94d60 100644 --- a/notebooks/lscontainer.ipynb +++ b/notebooks/lscontainer.ipynb @@ -36,8 +36,12 @@ ], "source": [ "ml = tml.ModelMaq()\n", - "lsc = tml.HeadLineSinkContainer(ml, xydict={0:[(0, 0), (10, 0), (10, 10)], 1:[(0, -5), (0, -10)]}, \n", - " laydict={0: 0, 1: 0}, hls=10)\n", + "lsc = tml.HeadLineSinkContainer(\n", + " ml,\n", + " xydict={0: [(0, 0), (10, 0), (10, 10)], 1: [(0, -5), (0, -10)]},\n", + " laydict={0: 0, 1: 0},\n", + " hls=10,\n", + ")\n", "rf = tml.Constant(ml, 0, -100, 20)\n", "ml.solve()" ] diff --git a/notebooks/test_linesink_discharge.ipynb b/notebooks/test_linesink_discharge.ipynb index 9d30f7ae..d0017a0f 100644 --- a/notebooks/test_linesink_discharge.ipynb +++ b/notebooks/test_linesink_discharge.ipynb @@ -55,8 +55,8 @@ } ], "source": [ - "print('head at center of line-sink:', ml1.head(ls1.xc, ls1.yc))\n", - "print('discharge of line-sink:', ls1.discharge())" + "print(\"head at center of line-sink:\", ml1.head(ls1.xc, ls1.yc))\n", + "print(\"discharge of line-sink:\", ls1.discharge())" ] }, { @@ -69,8 +69,8 @@ "rf2 = tml.Constant(ml2, xr=0, yr=20, hr=30)\n", "N = 20\n", "d = 20 / N\n", - "xw = np.arange(-10 + d/2, 10, d)\n", - "yw = np.arange(-10 + d/2, 10, d)\n", + "xw = np.arange(-10 + d / 2, 10, d)\n", + "yw = np.arange(-10 + d / 2, 10, d)\n", "for i in range(N):\n", " tml.Well(ml2, xw[i], yw[i], Qw=1000 / N)\n", "ml2.solve(silent=True)" @@ -103,8 +103,8 @@ } ], "source": [ - "ml1.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color='b')\n", - "ml2.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color='r', newfig=False)" + "ml1.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color=\"b\")\n", + "ml2.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color=\"r\", newfig=False)" ] }, { @@ -139,8 +139,8 @@ "rf2 = tml.Constant(ml2, xr=0, yr=20, hr=30)\n", "N = 50\n", "d = 20 / N\n", - "xw = np.arange(-10 + d/2, 10, d)\n", - "yw = np.arange(-10 + d/2, 10, d)\n", + "xw = np.arange(-10 + d / 2, 10, d)\n", + "yw = np.arange(-10 + d / 2, 10, d)\n", "for i in range(N):\n", " tml.HeadWell(ml2, xw[i], yw[i], 20, layers=0)\n", "ml2.solve(silent=True)\n", @@ -164,8 +164,8 @@ } ], "source": [ - "print('discharge of line-sink:', ls1.discharge())\n", - "print('discharge of wells:', Qwell)" + "print(\"discharge of line-sink:\", ls1.discharge())\n", + "print(\"discharge of wells:\", Qwell)" ] }, { @@ -195,8 +195,8 @@ } ], "source": [ - "ml1.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color='b')\n", - "ml2.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color='r', newfig=False)" + "ml1.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color=\"b\")\n", + "ml2.contour([-20, 20, -20, 20], 50, [0], np.arange(20, 31, 1), color=\"r\", newfig=False)" ] }, { @@ -231,8 +231,8 @@ "h1 = ml1.headalongline(x, 0)\n", "h2 = ml2.headalongline(x, 0)\n", "plt.figure()\n", - "plt.plot(x, h1.T, 'b')\n", - "plt.plot(x, h2.T, 'r')" + "plt.plot(x, h1.T, \"b\")\n", + "plt.plot(x, h2.T, \"r\")" ] }, { @@ -582,7 +582,9 @@ "source": [ "ml1 = tml.ModelMaq(kaq=[20, 10], z=[20, 12, 10, 0], c=[100])\n", "rf1 = tml.Constant(ml1, xr=0, yr=20, hr=30)\n", - "ls1 = tml.HeadLineSinkString(ml1, xy=[(-10, 0), (0, 0), (10, 0), (10, 10)], hls=20, order=5, layers=[0])\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml1, xy=[(-10, 0), (0, 0), (10, 0), (10, 10)], hls=20, order=5, layers=[0]\n", + ")\n", "ml1.solve()\n", "ml1.contour([-20, 20, -20, 20], 50, [0], 40)" ] @@ -625,7 +627,9 @@ "source": [ "ml1 = tml.ModelMaq(kaq=[20, 10], z=[20, 12, 10, 0], c=[100])\n", "rf1 = tml.Constant(ml1, xr=0, yr=20, hr=30)\n", - "ls1 = tml.HeadLineSinkString(ml1, xy=[(-10, 0), (0, 0), (10, 0), (10, 10)], hls=[20, 22], order=5, layers=[0])\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml1, xy=[(-10, 0), (0, 0), (10, 0), (10, 10)], hls=[20, 22], order=5, layers=[0]\n", + ")\n", "ml1.solve()\n", "ml1.contour([-20, 20, -20, 20], 50, [0], 40)" ] @@ -717,8 +721,15 @@ "source": [ "ml1 = tml.ModelMaq(kaq=[20, 10], z=[20, 12, 10, 0], c=[100])\n", "rf1 = tml.Constant(ml1, xr=0, yr=200, hr=2)\n", - "ls1 = tml.HeadLineSinkString(ml1, xy=[(-10, 0), (0, 0), (10, 0), (10, 10)], hls=[0, 1], \n", - " res=2, wh=5, order=5, layers=[0])\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml1,\n", + " xy=[(-10, 0), (0, 0), (10, 0), (10, 10)],\n", + " hls=[0, 1],\n", + " res=2,\n", + " wh=5,\n", + " order=5,\n", + " layers=[0],\n", + ")\n", "ml1.solve()" ] }, @@ -830,9 +841,11 @@ "source": [ "ml1 = tml.ModelMaq(kaq=[20, 10], z=[20, 12, 10, 0], c=[100])\n", "rf1 = tml.Constant(ml1, xr=0, yr=20, hr=1)\n", - "ls1 = tml.LineSinkDitchString(ml1, xy=[(-10, 0), (0, 0), (10, 0)], Qls=100, wh=2, res=5, order=2, layers=[0])\n", + "ls1 = tml.LineSinkDitchString(\n", + " ml1, xy=[(-10, 0), (0, 0), (10, 0)], Qls=100, wh=2, res=5, order=2, layers=[0]\n", + ")\n", "ml1.solve()\n", - "print('discharge:', ls1.discharge())" + "print(\"discharge:\", ls1.discharge())" ] }, { @@ -890,7 +903,15 @@ "source": [ "ml1 = tml.ModelMaq(kaq=[20, 10], z=[20, 12, 10, 0], c=[100])\n", "rf1 = tml.Constant(ml1, xr=0, yr=20, hr=1)\n", - "ls1 = tml.LineSinkDitchString(ml1, xy=[(-10, 0), (0, 0), (10, 0), (10, 20)], Qls=100, wh=2, res=5, order=2, layers=[0,1,0])\n", + "ls1 = tml.LineSinkDitchString(\n", + " ml1,\n", + " xy=[(-10, 0), (0, 0), (10, 0), (10, 20)],\n", + " Qls=100,\n", + " wh=2,\n", + " res=5,\n", + " order=2,\n", + " layers=[0, 1, 0],\n", + ")\n", "ml1.solve()" ] }, @@ -917,9 +938,19 @@ } ], "source": [ - "ml = tml.Model3D(kaq=1, z=np.arange(10, -0.1, -0.2), kzoverkh=0.1, topboundary='semi', topres=0, topthick=2, hstar=7)\n", + "ml = tml.Model3D(\n", + " kaq=1,\n", + " z=np.arange(10, -0.1, -0.2),\n", + " kzoverkh=0.1,\n", + " topboundary=\"semi\",\n", + " topres=0,\n", + " topthick=2,\n", + " hstar=7,\n", + ")\n", "xy = list(zip(np.linspace(-10, 10, 21), np.zeros(21)))\n", - "ls = tml.LineSinkDitchString(ml, xy=xy, Qls=100, wh=2, res=5, order=2, layers=np.arange(10, 30, 1))\n", + "ls = tml.LineSinkDitchString(\n", + " ml, xy=xy, Qls=100, wh=2, res=5, order=2, layers=np.arange(10, 30, 1)\n", + ")\n", "ml.solve()" ] }, diff --git a/notebooks/test_polygon_areasink.ipynb b/notebooks/test_polygon_areasink.ipynb index 4126099d..f71bcca7 100644 --- a/notebooks/test_polygon_areasink.ipynb +++ b/notebooks/test_polygon_areasink.ipynb @@ -31,9 +31,17 @@ "source": [ "ml = tml.ModelMaq(kaq=[1, 2], z=[10, 5, 4, 0], c=2)\n", "xy = [(-50, 0), (50, 0), (50, 80), (-50, 80)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy, \n", - " kaq=[1, 2], z=[10, 5, 4, 0], c=[2], \n", - " topboundary='conf', N=0.01, order=5, ndeg=3)\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy,\n", + " kaq=[1, 2],\n", + " z=[10, 5, 4, 0],\n", + " c=[2],\n", + " topboundary=\"conf\",\n", + " N=0.01,\n", + " order=5,\n", + " ndeg=3,\n", + ")\n", "rf = tml.Constant(ml, xr=0, yr=-1000, hr=2)\n", "ml.solve()" ] @@ -121,14 +129,17 @@ "x = 20\n", "y = 60\n", "d = 0.01\n", - "d2hdx2 = (ml.head(x + d, y) - 2 * ml.head(x, y) + ml.head(x - d, y)) / (d ** 2)\n", - "d2hdy2 = (ml.head(x, y + d) - 2 * ml.head(x, y) + ml.head(x, y - d)) / (d ** 2)\n", + "d2hdx2 = (ml.head(x + d, y) - 2 * ml.head(x, y) + ml.head(x - d, y)) / (d**2)\n", + "d2hdy2 = (ml.head(x, y + d) - 2 * ml.head(x, y) + ml.head(x, y - d)) / (d**2)\n", "d2hdx2 + d2hdy2\n", "aqin = ml.aq.inhomlist[0]\n", - "print('recharge from numerical derivative: ', np.sum(aqin.T * (d2hdx2 + d2hdy2)))\n", + "print(\"recharge from numerical derivative: \", np.sum(aqin.T * (d2hdx2 + d2hdy2)))\n", "h = ml.head(x, y)\n", - "print('leakage from aq0 to aq1 from head difference: ', (h[1] - h[0]) / aqin.c[1])\n", - "print('leakage from aq0 to aq1 from num. derivative: ', aqin.T[1] * (d2hdx2[1] + d2hdy2[1]))" + "print(\"leakage from aq0 to aq1 from head difference: \", (h[1] - h[0]) / aqin.c[1])\n", + "print(\n", + " \"leakage from aq0 to aq1 from num. derivative: \",\n", + " aqin.T[1] * (d2hdx2[1] + d2hdy2[1]),\n", + ")" ] }, { diff --git a/notebooks/test_well_near_lake.ipynb b/notebooks/test_well_near_lake.ipynb index 4bb43dda..5a1a5d50 100644 --- a/notebooks/test_well_near_lake.ipynb +++ b/notebooks/test_well_near_lake.ipynb @@ -28,10 +28,18 @@ ], "source": [ "ml = tml.ModelMaq(kaq=[1, 2], z=[10, 5, 4, 0], c=20)\n", - "xy = [(-5,0), (5,0), (5,8), (-5,8)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=[(-5,0), (5,0), (5,8), (-5,8)], \n", - " kaq=[0.2, 8], z=[11,10,5,4,0], c=[2, 20], \n", - " topboundary='semi', hstar=1.0, order=3, ndeg=1)\n", + "xy = [(-5, 0), (5, 0), (5, 8), (-5, 8)]\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=[(-5, 0), (5, 0), (5, 8), (-5, 8)],\n", + " kaq=[0.2, 8],\n", + " z=[11, 10, 5, 4, 0],\n", + " c=[2, 20],\n", + " topboundary=\"semi\",\n", + " hstar=1.0,\n", + " order=3,\n", + " ndeg=1,\n", + ")\n", "w = tml.Well(ml, xw=0, yw=-10, Qw=100, layers=1)\n", "rf = tml.Constant(ml, xr=0, yr=-100, hr=2)\n", "ml.solve()" diff --git a/notebooks/timml_besselaesnew_test.ipynb b/notebooks/timml_besselaesnew_test.ipynb index 9463cdee..927d39b6 100755 --- a/notebooks/timml_besselaesnew_test.ipynb +++ b/notebooks/timml_besselaesnew_test.ipynb @@ -9,6 +9,7 @@ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import sys\n", + "\n", "# sys.path.append('/Users/mark/git/timml')\n", "# from timml.besselaesnew import besselaesnew\n", "# besselaesnew.initialize()\n", @@ -48,8 +49,9 @@ " nx, ny = 100, 100\n", "x, y = np.meshgrid(np.linspace(-10, 10, nx), np.linspace(-10, 10, ny))\n", "\n", + "\n", "def potlstest(order):\n", - " z1 = -2 -4j\n", + " z1 = -2 - 4j\n", " z2 = 3 + 1j\n", " lab = np.array([0, 0.4, 4])\n", " ilap = 1\n", @@ -57,11 +59,14 @@ " pot = np.empty((naq, ny, nx))\n", " for i in range(ny):\n", " for j in range(nx):\n", - " pot[:, i, j] = besselaesnew.potbeslsho(x[i, j], y[i, j], z1, z2, lab, order, ilap, naq)\n", + " pot[:, i, j] = besselaesnew.potbeslsho(\n", + " x[i, j], y[i, j], z1, z2, lab, order, ilap, naq\n", + " )\n", " return pot\n", "\n", + "\n", "def qxqylstest(order):\n", - " z1 = -2 -4j\n", + " z1 = -2 - 4j\n", " z2 = 3 + 1j\n", " lab = np.array([0, 0.4, 4])\n", " ilap = 1\n", @@ -69,11 +74,14 @@ " qx, qy = np.empty((naq, ny, nx)), np.empty((naq, ny, nx))\n", " for i in range(ny):\n", " for j in range(nx):\n", - " qx[:, i, j], qy[:, i, j] = besselaesnew.disbeslsho(x[i, j], y[i, j], z1, z2, lab, order, ilap, naq)\n", + " qx[:, i, j], qy[:, i, j] = besselaesnew.disbeslsho(\n", + " x[i, j], y[i, j], z1, z2, lab, order, ilap, naq\n", + " )\n", " return qx, qy\n", "\n", + "\n", "def potldtest(order):\n", - " z1 = -2 -4j\n", + " z1 = -2 - 4j\n", " z2 = 3 + 1j\n", " lab = np.array([0, 0.4, 4])\n", " ilap = 1\n", @@ -81,11 +89,14 @@ " pot = np.empty((naq, ny, nx))\n", " for i in range(ny):\n", " for j in range(nx):\n", - " pot[:, i, j] = besselaesnew.potbesldho(x[i, j], y[i, j], z1, z2, lab, order, ilap, naq)\n", + " pot[:, i, j] = besselaesnew.potbesldho(\n", + " x[i, j], y[i, j], z1, z2, lab, order, ilap, naq\n", + " )\n", " return pot\n", "\n", + "\n", "def qxqyldtest(order):\n", - " z1 = -2 -4j\n", + " z1 = -2 - 4j\n", " z2 = 3 + 1j\n", " lab = np.array([0, 0.4, 4])\n", " ilap = 1\n", @@ -93,7 +104,9 @@ " qx, qy = np.empty((naq, ny, nx)), np.empty((naq, ny, nx))\n", " for i in range(ny):\n", " for j in range(nx):\n", - " qx[:, i, j], qy[:, i, j] = besselaesnew.disbesldho(x[i, j], y[i, j], z1, z2, lab, order, ilap, naq)\n", + " qx[:, i, j], qy[:, i, j] = besselaesnew.disbesldho(\n", + " x[i, j], y[i, j], z1, z2, lab, order, ilap, naq\n", + " )\n", " return qx, qy" ] }, @@ -160,12 +173,18 @@ " plt.figure(figsize=(16, 8))\n", " for i in range(3):\n", " if comp:\n", - " potfor = np.loadtxt('besselaesnew_test_data/potls_order' + str(order) + '_lab' + str(i) + '.txt')\n", - " print('order, aq', order, i, np.allclose(pot[i], potfor, atol=1e-10))\n", - " plt.subplot(1,3,i + 1)\n", + " potfor = np.loadtxt(\n", + " \"besselaesnew_test_data/potls_order\"\n", + " + str(order)\n", + " + \"_lab\"\n", + " + str(i)\n", + " + \".txt\"\n", + " )\n", + " print(\"order, aq\", order, i, np.allclose(pot[i], potfor, atol=1e-10))\n", + " plt.subplot(1, 3, i + 1)\n", " plt.contour(x, y, pot[i], np.arange(-2, 2, 0.02))\n", - " plt.plot([-2, 3], [-4, 1], 'k')\n", - " plt.axis('scaled')" + " plt.plot([-2, 3], [-4, 1], \"k\")\n", + " plt.axis(\"scaled\")" ] }, { @@ -231,12 +250,18 @@ " plt.figure(figsize=(16, 8))\n", " for i in range(3):\n", " if comp:\n", - " qxfor = np.loadtxt('besselaesnew_test_data/qxls_order' + str(order) + '_lab' + str(i) + '.txt')\n", - " print('order, aq', order, i, np.allclose(qx[i], qxfor, atol=1e-10))\n", - " plt.subplot(1,3,i + 1)\n", + " qxfor = np.loadtxt(\n", + " \"besselaesnew_test_data/qxls_order\"\n", + " + str(order)\n", + " + \"_lab\"\n", + " + str(i)\n", + " + \".txt\"\n", + " )\n", + " print(\"order, aq\", order, i, np.allclose(qx[i], qxfor, atol=1e-10))\n", + " plt.subplot(1, 3, i + 1)\n", " plt.contour(x, y, qx[i], np.arange(-2, 2, 0.02))\n", - " plt.plot([-2, 3], [-4, 1], 'k')\n", - " plt.axis('scaled')" + " plt.plot([-2, 3], [-4, 1], \"k\")\n", + " plt.axis(\"scaled\")" ] }, { @@ -302,12 +327,18 @@ " plt.figure(figsize=(16, 8))\n", " for i in range(3):\n", " if comp:\n", - " qyfor = np.loadtxt('besselaesnew_test_data/qyls_order' + str(order) + '_lab' + str(i) + '.txt')\n", - " print('order, aq', order, i, np.allclose(qy[i], qyfor, atol=1e-10))\n", - " plt.subplot(1,3,i + 1)\n", + " qyfor = np.loadtxt(\n", + " \"besselaesnew_test_data/qyls_order\"\n", + " + str(order)\n", + " + \"_lab\"\n", + " + str(i)\n", + " + \".txt\"\n", + " )\n", + " print(\"order, aq\", order, i, np.allclose(qy[i], qyfor, atol=1e-10))\n", + " plt.subplot(1, 3, i + 1)\n", " plt.contour(x, y, qy[i], np.arange(-2, 2, 0.02))\n", - " plt.plot([-2, 3], [-4, 1], 'k')\n", - " plt.axis('scaled')" + " plt.plot([-2, 3], [-4, 1], \"k\")\n", + " plt.axis(\"scaled\")" ] }, { @@ -337,12 +368,18 @@ " plt.figure(figsize=(16, 8))\n", " for i in range(3):\n", " if comp:\n", - " potfor = np.loadtxt('besselaesnew_test_data/potld_order' + str(order) + '_lab' + str(i) + '.txt')\n", - " print('order, aq', order, i, np.allclose(pot[i], potfor, atol=1e-10))\n", - " plt.subplot(1,3,i + 1)\n", + " potfor = np.loadtxt(\n", + " \"besselaesnew_test_data/potld_order\"\n", + " + str(order)\n", + " + \"_lab\"\n", + " + str(i)\n", + " + \".txt\"\n", + " )\n", + " print(\"order, aq\", order, i, np.allclose(pot[i], potfor, atol=1e-10))\n", + " plt.subplot(1, 3, i + 1)\n", " plt.contour(x, y, pot[i], np.arange(-2, 2, 0.02))\n", - " plt.plot([-2, 3], [-4, 1], 'k')\n", - " plt.axis('scaled')" + " plt.plot([-2, 3], [-4, 1], \"k\")\n", + " plt.axis(\"scaled\")" ] }, { @@ -356,12 +393,18 @@ " plt.figure(figsize=(16, 8))\n", " for i in range(3):\n", " if comp:\n", - " qxfor = np.loadtxt('besselaesnew_test_data/qxld_order' + str(order) + '_lab' + str(i) + '.txt')\n", - " print('order, aq', order, i, np.allclose(qx[i], qxfor, atol=1e-10))\n", - " plt.subplot(1,3,i + 1)\n", + " qxfor = np.loadtxt(\n", + " \"besselaesnew_test_data/qxld_order\"\n", + " + str(order)\n", + " + \"_lab\"\n", + " + str(i)\n", + " + \".txt\"\n", + " )\n", + " print(\"order, aq\", order, i, np.allclose(qx[i], qxfor, atol=1e-10))\n", + " plt.subplot(1, 3, i + 1)\n", " plt.contour(x, y, qx[i], np.arange(-2, 2, 0.02))\n", - " plt.plot([-2, 3], [-4, 1], 'k')\n", - " plt.axis('scaled')" + " plt.plot([-2, 3], [-4, 1], \"k\")\n", + " plt.axis(\"scaled\")" ] }, { @@ -375,12 +418,18 @@ " plt.figure(figsize=(16, 8))\n", " for i in range(3):\n", " if comp:\n", - " qyfor = np.loadtxt('besselaesnew_test_data/qyld_order' + str(order) + '_lab' + str(i) + '.txt')\n", - " print('order, aq', order, i, np.allclose(qy[i], qyfor, atol=1e-10))\n", - " plt.subplot(1,3,i + 1)\n", + " qyfor = np.loadtxt(\n", + " \"besselaesnew_test_data/qyld_order\"\n", + " + str(order)\n", + " + \"_lab\"\n", + " + str(i)\n", + " + \".txt\"\n", + " )\n", + " print(\"order, aq\", order, i, np.allclose(qy[i], qyfor, atol=1e-10))\n", + " plt.subplot(1, 3, i + 1)\n", " plt.contour(x, y, qy[i], np.arange(-2, 2, 0.02))\n", - " plt.plot([-2, 3], [-4, 1], 'k')\n", - " plt.axis('scaled')" + " plt.plot([-2, 3], [-4, 1], \"k\")\n", + " plt.axis(\"scaled\")" ] }, { diff --git a/notebooks/timml_figures.ipynb b/notebooks/timml_figures.ipynb index c6fc36b9..e9e7b319 100644 --- a/notebooks/timml_figures.ipynb +++ b/notebooks/timml_figures.ipynb @@ -33,23 +33,23 @@ "source": [ "# ModelMaq figure\n", "plt.figure()\n", - "plt.axes(frameon = 0)\n", - "grey = [.9, .9, .9]\n", - "plt.plot([-1, 1], [0, 0], 'k', lw=2)\n", + "plt.axes(frameon=0)\n", + "grey = [0.9, 0.9, 0.9]\n", + "plt.plot([-1, 1], [0, 0], \"k\", lw=2)\n", "plt.axhspan(-5, -10, color=grey)\n", "plt.axhspan(-20, -25, color=grey)\n", - "plt.plot([-1, 1], [-35, -35], 'k', lw=2)\n", - "plt.text(0, -2.5, '$k$ = 10 m/d', ha='center', va='center')\n", - "plt.text(0, -15, '$k$ = 30 m/d', ha='center', va='center')\n", - "plt.text(0, -30, '$k$ = 20 m/d', ha='center', va='center')\n", - "plt.text(0, -7.5, '$c$ = 2000 d', ha='center', va='center')\n", - "plt.text(0, -22.5, '$c$ = 5000 d', ha='center', va='center')\n", + "plt.plot([-1, 1], [-35, -35], \"k\", lw=2)\n", + "plt.text(0, -2.5, \"$k$ = 10 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -15, \"$k$ = 30 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -30, \"$k$ = 20 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -7.5, \"$c$ = 2000 d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -22.5, \"$c$ = 5000 d\", ha=\"center\", va=\"center\")\n", "plt.xlim(-1, 1)\n", "plt.yticks([0, -5, -10, -20, -25, -35])\n", - "plt.ylabel('elevation (m)')\n", + "plt.ylabel(\"elevation (m)\")\n", "plt.xticks([])\n", - "plt.savefig('../docs/models/modelmaq.png', bbox_inches='tight')\n", - "#ModelMaq(kaq=[10, 30, 20], z=[0, -5, -10, -20, -25, -35], c=[2000, 5000])" + "plt.savefig(\"../docs/models/modelmaq.png\", bbox_inches=\"tight\")\n", + "# ModelMaq(kaq=[10, 30, 20], z=[0, -5, -10, -20, -25, -35], c=[2000, 5000])" ] }, { @@ -76,25 +76,25 @@ "source": [ "# ModelMaq figure\n", "plt.figure()\n", - "plt.axes(frameon = 0)\n", - "grey = [.9, .9, .9]\n", - "plt.plot([-1, 1], [0, 0], 'k', lw=2)\n", + "plt.axes(frameon=0)\n", + "grey = [0.9, 0.9, 0.9]\n", + "plt.plot([-1, 1], [0, 0], \"k\", lw=2)\n", "plt.axhspan(-5, -5, color=grey)\n", "plt.axhspan(-10, -10, color=grey)\n", "plt.axhspan(-20, -20, color=grey)\n", "plt.axhspan(-25, -25, color=grey)\n", - "plt.plot([-1, 1], [-35, -35], 'k', lw=2)\n", - "plt.text(0, -2.5, '$k$ = 10 m/d', ha='center', va='center')\n", - "plt.text(0, -7.5, '$k$ = 0.025 m/d', ha='center', va='center')\n", - "plt.text(0, -15, '$k$ = 30 m/d', ha='center', va='center')\n", - "plt.text(0, -22.5, '$k$ = 0.01 m/d', ha='center', va='center')\n", - "plt.text(0, -30, '$k$ = 20 m/d', ha='center', va='center')\n", + "plt.plot([-1, 1], [-35, -35], \"k\", lw=2)\n", + "plt.text(0, -2.5, \"$k$ = 10 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -7.5, \"$k$ = 0.025 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -15, \"$k$ = 30 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -22.5, \"$k$ = 0.01 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -30, \"$k$ = 20 m/d\", ha=\"center\", va=\"center\")\n", "plt.xlim(-1, 1)\n", "plt.yticks([0, -5, -10, -20, -25, -35])\n", - "plt.ylabel('elevation (m)')\n", + "plt.ylabel(\"elevation (m)\")\n", "plt.xticks([])\n", - "plt.savefig('../docs/models/model3d.png', bbox_inches='tight')\n", - "#Model3D(kaq=[10, 0.0025, 30, 0.001, 20], z=[0, -5, -10, -20, -25, -35], kzoverkh=0.1)" + "plt.savefig(\"../docs/models/model3d.png\", bbox_inches=\"tight\")\n", + "# Model3D(kaq=[10, 0.0025, 30, 0.001, 20], z=[0, -5, -10, -20, -25, -35], kzoverkh=0.1)" ] }, { @@ -121,24 +121,24 @@ "source": [ "# Model\n", "plt.figure()\n", - "plt.axes(frameon = 0)\n", - "grey = [.9, .9, .9]\n", - "plt.plot([-1, 1], [0, 0], 'k', lw=2)\n", + "plt.axes(frameon=0)\n", + "grey = [0.9, 0.9, 0.9]\n", + "plt.plot([-1, 1], [0, 0], \"k\", lw=2)\n", "plt.axhspan(-5, -5, color=grey)\n", "plt.axhspan(-10, -10, color=grey)\n", "plt.axhspan(-20, -25, color=grey)\n", - "plt.plot([-1, 1], [-35, -35], 'k', lw=2)\n", - "plt.text(0, -2.5, '$k$ = 10 m/d', ha='center', va='center')\n", - "plt.text(0, -7.5, '$k$ = 5 m/d', ha='center', va='center')\n", - "plt.text(0, -15, '$k$ = 30 m/d', ha='center', va='center')\n", - "plt.text(0, -22.5, '$c$ = 2000 d', ha='center', va='center')\n", - "plt.text(0, -30, '$k$ = 20 m/d', ha='center', va='center')\n", + "plt.plot([-1, 1], [-35, -35], \"k\", lw=2)\n", + "plt.text(0, -2.5, \"$k$ = 10 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -7.5, \"$k$ = 5 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -15, \"$k$ = 30 m/d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -22.5, \"$c$ = 2000 d\", ha=\"center\", va=\"center\")\n", + "plt.text(0, -30, \"$k$ = 20 m/d\", ha=\"center\", va=\"center\")\n", "plt.xlim(-1, 1)\n", "plt.yticks([0, -5, -10, -20, -25, -35])\n", - "plt.ylabel('elevation (m)')\n", + "plt.ylabel(\"elevation (m)\")\n", "plt.xticks([])\n", - "plt.savefig('../docs/models/model.png', bbox_inches='tight')\n", - "#Model(kaq=[10, 5, 30, 20], c=[2, 5, 2000], z=[0, -5, -10, -20, -25, -35], \n", + "plt.savefig(\"../docs/models/model.png\", bbox_inches=\"tight\")\n", + "# Model(kaq=[10, 5, 30, 20], c=[2, 5, 2000], z=[0, -5, -10, -20, -25, -35],\n", "# npor=[0.3, 0.3, 0.3, 0.3], ltype=['a', 'a', 'a', 'l', 'a'])" ] }, diff --git a/notebooks/timml_notebook0_sol.ipynb b/notebooks/timml_notebook0_sol.ipynb index 041b27c3..1b6e3ba7 100644 --- a/notebooks/timml_notebook0_sol.ipynb +++ b/notebooks/timml_notebook0_sol.ipynb @@ -94,8 +94,15 @@ } ], "source": [ - "ml.contour(win=[-1200, 200, -500, 500], ngr=50,\n", - " levels=10, labels=True, decimals=2, legend=True, figsize=(6, 6));" + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " levels=10,\n", + " labels=True,\n", + " decimals=2,\n", + " legend=True,\n", + " figsize=(6, 6),\n", + ");" ] }, { @@ -123,8 +130,14 @@ } ], "source": [ - "ml.contour(win=[-1200, 200, -500, 500], ngr=50,\n", - " levels=np.arange(39, 42, 0.1), labels=True, decimals=1, figsize=(6, 6));" + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " levels=np.arange(39, 42, 0.1),\n", + " labels=True,\n", + " decimals=1,\n", + " figsize=(6, 6),\n", + ");" ] }, { @@ -140,7 +153,7 @@ "metadata": {}, "outputs": [], "source": [ - "w = tml.Well(ml, xw=-400, yw=0, Qw=50., rw=0.2)" + "w = tml.Well(ml, xw=-400, yw=0, Qw=50.0, rw=0.2)" ] }, { @@ -178,8 +191,12 @@ ], "source": [ "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6))\n", - "ml.tracelines(-800 * np.ones(1), -200 * np.ones(1), np.zeros(1), hstepmax=20, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(1), -200 * np.ones(1), np.zeros(1), hstepmax=20, color=\"C1\"\n", + ")" ] }, { @@ -214,8 +231,16 @@ } ], "source": [ - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6))\n", - "ml.tracelines(-800 * np.ones(10), np.linspace(-500, 500, 10), np.zeros(10), hstepmax=20, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(10),\n", + " np.linspace(-500, 500, 10),\n", + " np.zeros(10),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + ")" ] }, { @@ -259,9 +284,17 @@ "uf = tml.Uflow(ml, slope=0.001, angle=0)\n", "w = tml.Well(ml, xw=-400, yw=0, Qw=200, rw=0.2)\n", "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6))\n", - "ml.tracelines(-800 * np.ones(10), np.linspace(-500, 500, 10), np.zeros(10), hstepmax=20, color='C1')\n", - "print(('head at well:', w.headinside()))" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(10),\n", + " np.linspace(-500, 500, 10),\n", + " np.zeros(10),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + ")\n", + "print((\"head at well:\", w.headinside()))" ] }, { @@ -305,8 +338,10 @@ "w = tml.Well(ml, xw=-400, yw=0, Qw=200, rw=0.2)\n", "ls1 = tml.HeadLineSink(ml, 0, -500, 0, 500, 40)\n", "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6))\n", - "print(('head at well:', w.headinside()))" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6)\n", + ")\n", + "print((\"head at well:\", w.headinside()))" ] }, { @@ -351,11 +386,21 @@ "w = tml.Well(ml, xw=-400, yw=0, Qw=200, rw=0.2)\n", "xls = np.zeros(21)\n", "yls = np.linspace(-800, 800, 21)\n", - "ls = tml.HeadLineSinkString(ml, xy=list(zip(xls, yls)), hls=40, layers=0, label='river')\n", + "ls = tml.HeadLineSinkString(ml, xy=list(zip(xls, yls)), hls=40, layers=0, label=\"river\")\n", "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6))\n", - "ml.tracelines(-800 * np.ones(10), np.linspace(-500, 500, 10), np.zeros(10), hstepmax=20, color='C1')\n", - "ml.tracelines(-0.01 * np.ones(5), np.linspace(-150, 150, 5), np.zeros(5), hstepmax=20, color='C2')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(6, 6)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(10),\n", + " np.linspace(-500, 500, 10),\n", + " np.zeros(10),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + ")\n", + "ml.tracelines(\n", + " -0.01 * np.ones(5), np.linspace(-150, 150, 5), np.zeros(5), hstepmax=20, color=\"C2\"\n", + ")" ] }, { @@ -390,8 +435,14 @@ } ], "source": [ - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), layers=0, figsize=(6, 6))\n", - "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=5 * 365.25, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500],\n", + " ngr=50,\n", + " levels=np.arange(39, 42, 0.1),\n", + " layers=0,\n", + " figsize=(6, 6),\n", + ")\n", + "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=5 * 365.25, color=\"C1\")" ] }, { @@ -426,8 +477,14 @@ } ], "source": [ - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), layers=0, figsize=(6, 6))\n", - "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=20 * 365.25, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500],\n", + " ngr=50,\n", + " levels=np.arange(39, 42, 0.1),\n", + " layers=0,\n", + " figsize=(6, 6),\n", + ")\n", + "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=20 * 365.25, color=\"C1\")" ] }, { @@ -476,8 +533,15 @@ "w3 = tml.HeadWell(ml, -400, -200, 40, rw=0.3)\n", "w4 = tml.HeadWell(ml, -400, 200, 40, rw=0.3)\n", "ml.solve()\n", - "ml.contour(win=[-1200, 200, -500, 500], ngr=50,\n", - " levels=10, labels=True, decimals=2, legend=True, figsize=(6, 6))\n", + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " levels=10,\n", + " labels=True,\n", + " decimals=2,\n", + " legend=True,\n", + " figsize=(6, 6),\n", + ")\n", "print(ml.head(-800 + 0.3, -200))\n", "print(ml.head(-800 + 0.3, 200))\n", "print(ml.head(-400 + 0.3, -200))\n", @@ -530,11 +594,29 @@ "w3 = tml.HeadWell(ml, -500, -100, 40, rw=0.3, xc=-400, yc=-200)\n", "w4 = tml.HeadWell(ml, -500, 100, 40, rw=0.3, xc=-400, yc=200)\n", "ml.solve()\n", - "ml.contour(win=[-1200, 200, -500, 500], ngr=50,\n", - " levels=10, labels=True, decimals=2, legend=True, figsize=(6, 6))\n", - "ml.contour(win=[-1200, 200, -500, 500], ngr=50, color='C1',\n", - " levels=[40,], labels=True, decimals=2, legend=True, figsize=(6, 6), newfig=False)\n", - "plt.plot([-800, -800, -400, -400], [-200, 200, -200, 200], 'kx')\n", + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " levels=10,\n", + " labels=True,\n", + " decimals=2,\n", + " legend=True,\n", + " figsize=(6, 6),\n", + ")\n", + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " color=\"C1\",\n", + " levels=[\n", + " 40,\n", + " ],\n", + " labels=True,\n", + " decimals=2,\n", + " legend=True,\n", + " figsize=(6, 6),\n", + " newfig=False,\n", + ")\n", + "plt.plot([-800, -800, -400, -400], [-200, 200, -200, 200], \"kx\")\n", "print(ml.head(-800, -200))\n", "print(ml.head(-800, 200))\n", "print(ml.head(-400, -200))\n", diff --git a/notebooks/timml_notebook1_sol.ipynb b/notebooks/timml_notebook1_sol.ipynb index 8e9659a9..6539f94d 100755 --- a/notebooks/timml_notebook1_sol.ipynb +++ b/notebooks/timml_notebook1_sol.ipynb @@ -43,7 +43,7 @@ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", - "figsize=(8, 8)" + "figsize = (8, 8)" ] }, { @@ -62,9 +62,7 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[10, 20, 5],\n", - " z=[0, -20, -40, -80, -90, -140], \n", - " c=[4000, 10000])\n", + "ml = tml.ModelMaq(kaq=[10, 20, 5], z=[0, -20, -40, -80, -90, -140], c=[4000, 10000])\n", "w = tml.Well(ml, xw=0, yw=0, Qw=10000, rw=0.2, layers=1)\n", "tml.Constant(ml, xr=10000, yr=0, hr=20, layer=0)\n", "tml.Uflow(ml, slope=0.002, angle=0)\n", @@ -95,7 +93,7 @@ } ], "source": [ - "print('The leakage factors of the aquifers are:')\n", + "print(\"The leakage factors of the aquifers are:\")\n", "print(ml.aq.lab)" ] }, @@ -122,7 +120,7 @@ } ], "source": [ - "print('The head at the well is:')\n", + "print(\"The head at the well is:\")\n", "print(w.headinside())" ] }, @@ -163,8 +161,14 @@ } ], "source": [ - "ml.contour(win=[-3000, 3000, -3000, 3000], ngr=50, layers=[0, 1, 2], levels=10, \n", - " legend=True, figsize=figsize)" + "ml.contour(\n", + " win=[-3000, 3000, -3000, 3000],\n", + " ngr=50,\n", + " layers=[0, 1, 2],\n", + " levels=10,\n", + " legend=True,\n", + " figsize=figsize,\n", + ")" ] }, { @@ -202,8 +206,15 @@ } ], "source": [ - "ml.contour(win=[-3000, 3000, -3000, 3000], ngr=50, layers=[1], levels=np.arange(30, 45, 1), \n", - " labels=True, legend=['layer 1'], figsize=figsize)" + "ml.contour(\n", + " win=[-3000, 3000, -3000, 3000],\n", + " ngr=50,\n", + " layers=[1],\n", + " levels=np.arange(30, 45, 1),\n", + " labels=True,\n", + " legend=[\"layer 1\"],\n", + " figsize=figsize,\n", + ")" ] }, { @@ -239,12 +250,24 @@ } ], "source": [ - "win=[-3000, 3000, -3000, 3000]\n", - "ml.plot(win=win, orientation='both', figsize=figsize)\n", - "ml.tracelines(-2000 * np.ones(3), -1000 * np.ones(3), [-120, -60, -10], hstepmax=50, \n", - " win=win, orientation='both')\n", - "ml.tracelines(0 * np.ones(3), 1000 * np.ones(3), [-120, -50, -10], hstepmax=50, \n", - " win=win, orientation='both')" + "win = [-3000, 3000, -3000, 3000]\n", + "ml.plot(win=win, orientation=\"both\", figsize=figsize)\n", + "ml.tracelines(\n", + " -2000 * np.ones(3),\n", + " -1000 * np.ones(3),\n", + " [-120, -60, -10],\n", + " hstepmax=50,\n", + " win=win,\n", + " orientation=\"both\",\n", + ")\n", + "ml.tracelines(\n", + " 0 * np.ones(3),\n", + " 1000 * np.ones(3),\n", + " [-120, -50, -10],\n", + " hstepmax=50,\n", + " win=win,\n", + " orientation=\"both\",\n", + ")" ] }, { @@ -292,16 +315,21 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[10, 20, 5],\n", - " z=[0, -20, -40, -80, -90, -140], \n", - " c=[4000, 10000])\n", + "ml = tml.ModelMaq(kaq=[10, 20, 5], z=[0, -20, -40, -80, -90, -140], c=[4000, 10000])\n", "w = tml.Well(ml, xw=0, yw=0, Qw=10000, rw=0.2, layers=1)\n", "tml.Constant(ml, xr=10000, yr=0, hr=20, layer=0)\n", "tml.Uflow(ml, slope=0.002, angle=0)\n", "wabandoned = tml.Well(ml, xw=100, yw=100, Qw=0, rw=0.2, layers=[0, 1])\n", "ml.solve()\n", - "ml.contour(win=[-200, 200, -200, 200], ngr=50, layers=[0, 2], \n", - " levels=20, color=['C0', 'C1', 'C2'], legend=True, figsize=figsize)" + "ml.contour(\n", + " win=[-200, 200, -200, 200],\n", + " ngr=50,\n", + " layers=[0, 2],\n", + " levels=20,\n", + " color=[\"C0\", \"C1\", \"C2\"],\n", + " legend=True,\n", + " figsize=figsize,\n", + ")" ] }, { @@ -321,9 +349,9 @@ } ], "source": [ - "print('The head at the abandoned well is:')\n", + "print(\"The head at the abandoned well is:\")\n", "print(wabandoned.headinside())\n", - "print('The discharge at the abandoned well is:')\n", + "print(\"The discharge at the abandoned well is:\")\n", "print(wabandoned.discharge())" ] }, diff --git a/notebooks/timml_notebook2_sol.ipynb b/notebooks/timml_notebook2_sol.ipynb index 652870bd..6ef025c1 100755 --- a/notebooks/timml_notebook2_sol.ipynb +++ b/notebooks/timml_notebook2_sol.ipynb @@ -40,7 +40,7 @@ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", - "figsize=(8, 8)" + "figsize = (8, 8)" ] }, { @@ -50,24 +50,52 @@ "outputs": [], "source": [ "# Create basic model elements\n", - "ml = tml.ModelMaq(kaq=[2, 6, 4],\n", - " z=[165, 140, 120, 80, 60, 0],\n", - " c=[2000, 20000],\n", - " npor=0.3)\n", + "ml = tml.ModelMaq(\n", + " kaq=[2, 6, 4], z=[165, 140, 120, 80, 60, 0], c=[2000, 20000], npor=0.3\n", + ")\n", "rf = tml.Constant(ml, xr=20000, yr=20000, hr=175, layer=0)\n", "p = tml.CircAreaSink(ml, xc=10000, yc=10000, R=15000, N=0.0002, layer=0)\n", - "w1 = tml.Well(ml, xw=10000, yw=8000, Qw=1000, rw=0.3, layers=0, label='well 1')\n", - "w2 = tml.Well(ml, xw=12100, yw=10700, Qw=5000, rw=0.3, layers=2, label='well 2')\n", - "w3 = tml.Well(ml, xw=10000, yw=4600, Qw=5000, rw=0.3, layers=[1,2], label='maq well')\n", + "w1 = tml.Well(ml, xw=10000, yw=8000, Qw=1000, rw=0.3, layers=0, label=\"well 1\")\n", + "w2 = tml.Well(ml, xw=12100, yw=10700, Qw=5000, rw=0.3, layers=2, label=\"well 2\")\n", + "w3 = tml.Well(ml, xw=10000, yw=4600, Qw=5000, rw=0.3, layers=[1, 2], label=\"maq well\")\n", "#\n", - "xy1 = [(833, 14261), (3229, 14843), (6094, 15885), (8385, 15677), (10781, 14895), (12753, 14976)]\n", + "xy1 = [\n", + " (833, 14261),\n", + " (3229, 14843),\n", + " (6094, 15885),\n", + " (8385, 15677),\n", + " (10781, 14895),\n", + " (12753, 14976),\n", + "]\n", "hls1 = [176, 166]\n", - "xy2 = [(356, 6976), (4043, 7153), (6176, 8400), (9286, 9820), (12266, 9686), (15066, 9466)]\n", - "hls2 = [174, 162] \n", - "xy3 = [(1376, 1910), (4176, 2043), (6800, 1553), (9953, 2086), (14043, 2043), (17600, 976)]\n", + "xy2 = [\n", + " (356, 6976),\n", + " (4043, 7153),\n", + " (6176, 8400),\n", + " (9286, 9820),\n", + " (12266, 9686),\n", + " (15066, 9466),\n", + "]\n", + "hls2 = [174, 162]\n", + "xy3 = [\n", + " (1376, 1910),\n", + " (4176, 2043),\n", + " (6800, 1553),\n", + " (9953, 2086),\n", + " (14043, 2043),\n", + " (17600, 976),\n", + "]\n", "hls3 = [170, 156]\n", - "xy4 = [(9510, 19466), (12620, 17376), (12753, 14976), (13020, 12176),\n", - " (15066, 9466), (16443, 7910), (17510, 5286), (17600, 976)]\n", + "xy4 = [\n", + " (9510, 19466),\n", + " (12620, 17376),\n", + " (12753, 14976),\n", + " (13020, 12176),\n", + " (15066, 9466),\n", + " (16443, 7910),\n", + " (17510, 5286),\n", + " (17600, 976),\n", + "]\n", "hls4 = [170, np.nan, 166, np.nan, 162, np.nan, np.nan, 156]\n", "\n", "ls1 = tml.HeadLineSinkString(ml, xy=xy1, hls=hls1, layers=0)\n", @@ -124,8 +152,15 @@ ], "source": [ "ml.solve()\n", - "ml.contour(win=[0, 20000, 0, 20000], ngr=50, layers=[0, 1, 2], \n", - " levels=10, color=['C0', 'C1', 'C2'], legend=True, figsize=figsize)" + "ml.contour(\n", + " win=[0, 20000, 0, 20000],\n", + " ngr=50,\n", + " layers=[0, 1, 2],\n", + " levels=10,\n", + " color=[\"C0\", \"C1\", \"C2\"],\n", + " legend=True,\n", + " figsize=figsize,\n", + ")" ] }, { @@ -152,9 +187,9 @@ } ], "source": [ - "print('The head at well 1 is:', w1.headinside())\n", - "print('The head at well 2 is:', w2.headinside())\n", - "print('The head at well 3 is:', w3.headinside())" + "print(\"The head at well 1 is:\", w1.headinside())\n", + "print(\"The head at well 2 is:\", w2.headinside())\n", + "print(\"The head at well 3 is:\", w3.headinside())" ] }, { @@ -193,11 +228,11 @@ } ], "source": [ - "ml.plot(win=[0, 20000, 0, 20000], orientation='both', figsize=figsize)\n", - "w1.plotcapzone(hstepmax=50, nt=10, zstart=150, tmax=250 * 365.25, orientation='both')\n", - "w2.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=250 * 365.25, orientation='both')\n", - "w3.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=250 * 365.25, orientation='both')\n", - "w3.plotcapzone(hstepmax=50, nt=10, zstart=100, tmax=250 * 365.25, orientation='both')" + "ml.plot(win=[0, 20000, 0, 20000], orientation=\"both\", figsize=figsize)\n", + "w1.plotcapzone(hstepmax=50, nt=10, zstart=150, tmax=250 * 365.25, orientation=\"both\")\n", + "w2.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=250 * 365.25, orientation=\"both\")\n", + "w3.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=250 * 365.25, orientation=\"both\")\n", + "w3.plotcapzone(hstepmax=50, nt=10, zstart=100, tmax=250 * 365.25, orientation=\"both\")" ] }, { @@ -227,11 +262,11 @@ } ], "source": [ - "ml.plot(win=[0, 20000, 0, 20000], orientation='both', topfigfrac=0.7, figsize=figsize)\n", - "w1.plotcapzone(hstepmax=50, nt=10, zstart=150, tmax=50 * 365.25, orientation='both')\n", - "w2.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=50 * 365.25, orientation='both')\n", - "w3.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=50 * 365.25, orientation='both')\n", - "w3.plotcapzone(hstepmax=50, nt=10, zstart=100, tmax=50 * 365.25, orientation='both')" + "ml.plot(win=[0, 20000, 0, 20000], orientation=\"both\", topfigfrac=0.7, figsize=figsize)\n", + "w1.plotcapzone(hstepmax=50, nt=10, zstart=150, tmax=50 * 365.25, orientation=\"both\")\n", + "w2.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=50 * 365.25, orientation=\"both\")\n", + "w3.plotcapzone(hstepmax=50, nt=10, zstart=30, tmax=50 * 365.25, orientation=\"both\")\n", + "w3.plotcapzone(hstepmax=50, nt=10, zstart=100, tmax=50 * 365.25, orientation=\"both\")" ] }, { diff --git a/notebooks/timml_notebook3_3D_sol.ipynb b/notebooks/timml_notebook3_3D_sol.ipynb index 36556e3f..ce32ea4a 100755 --- a/notebooks/timml_notebook3_3D_sol.ipynb +++ b/notebooks/timml_notebook3_3D_sol.ipynb @@ -34,7 +34,7 @@ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", - "plt.rcParams['figure.figsize'] = (6, 6)" + "plt.rcParams[\"figure.figsize\"] = (6, 6)" ] }, { @@ -56,11 +56,29 @@ ], "source": [ "ml = tml.Model3D(kaq=10, z=[20, 10, 0], kzoverkh=0.02)\n", - "xy1 = [(0, 600), (-100, 400), (-100, 200), (100, 100), (300, 100), (500, 100),\n", - " (700, 300), (700, 500), (600, 700), (400, 700), (200, 600)]\n", - "p1 = tml.PolygonInhom3D(ml, xy=xy1, \n", - " kaq=2, z=[20, 10, 0], kzoverkh=0.002,\n", - " topboundary='conf', order=5, ndeg=3)\n", + "xy1 = [\n", + " (0, 600),\n", + " (-100, 400),\n", + " (-100, 200),\n", + " (100, 100),\n", + " (300, 100),\n", + " (500, 100),\n", + " (700, 300),\n", + " (700, 500),\n", + " (600, 700),\n", + " (400, 700),\n", + " (200, 600),\n", + "]\n", + "p1 = tml.PolygonInhom3D(\n", + " ml,\n", + " xy=xy1,\n", + " kaq=2,\n", + " z=[20, 10, 0],\n", + " kzoverkh=0.002,\n", + " topboundary=\"conf\",\n", + " order=5,\n", + " ndeg=3,\n", + ")\n", "rf = tml.Constant(ml, xr=1000, yr=0, hr=40)\n", "uf = tml.Uflow(ml, slope=0.002, angle=-45)\n", "w = tml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", @@ -82,8 +100,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Leakage factor of the background aquifer is:', ml.aq.lab)\n", - "print('Leakage factor of the inhomogeneity is:', p1.lab)" + "print(\"Leakage factor of the background aquifer is:\", ml.aq.lab)\n", + "print(\"Leakage factor of the inhomogeneity is:\", p1.lab)" ] }, { @@ -100,7 +118,9 @@ "metadata": {}, "outputs": [], "source": [ - "ml.contour(win=[-200, 800, 0, 800], ngr=50, layers=[0, 1], levels=20, labels=1, decimals=2);" + "ml.contour(\n", + " win=[-200, 800, 0, 800], ngr=50, layers=[0, 1], levels=20, labels=1, decimals=2\n", + ");" ] }, { @@ -109,7 +129,14 @@ "metadata": {}, "outputs": [], "source": [ - "ml.contour(win=[-1200, 1800, -1000, 1800], ngr=50, layers=[0, 1], levels=50, labels=1, decimals=2);" + "ml.contour(\n", + " win=[-1200, 1800, -1000, 1800],\n", + " ngr=50,\n", + " layers=[0, 1],\n", + " levels=50,\n", + " labels=1,\n", + " decimals=2,\n", + ");" ] }, { @@ -159,8 +186,8 @@ "metadata": {}, "outputs": [], "source": [ - "ml.plot(win=[-200, 800, 0, 800], orientation='both')\n", - "w.plotcapzone(hstepmax=50, nt=20, zstart=15, tmax=20 * 365.25, orientation='both')" + "ml.plot(win=[-200, 800, 0, 800], orientation=\"both\")\n", + "w.plotcapzone(hstepmax=50, nt=20, zstart=15, tmax=20 * 365.25, orientation=\"both\")" ] }, { @@ -192,15 +219,48 @@ "outputs": [], "source": [ "ml = tml.Model3D(kaq=10, z=[20, 10, 0], kzoverkh=0.02)\n", - "xy1 = [(0, 600), (-100, 400), (-100, 200), (100, 100), (300, 100), (500, 100),\n", - " (700, 300), (700, 500), (600, 700), (400, 700), (200, 600)]\n", - "p1 = tml.PolygonInhom3D(ml, xy=xy1, \n", - " kaq=2, z=[20, 10, 0], kzoverkh=0.002,\n", - " topboundary='conf', order=5, ndeg=3)\n", - "xy2 = [(0, 600), (200, 600), (400, 700), (400, 900), (200, 1100), (0, 1000), (-100, 800)]\n", - "p2 = tml.PolygonInhom3D(ml, xy=xy2, \n", - " kaq=20, z=[20, 10, 0], kzoverkh=0.05, \n", - " topboundary='conf', order=5, ndeg=3)\n", + "xy1 = [\n", + " (0, 600),\n", + " (-100, 400),\n", + " (-100, 200),\n", + " (100, 100),\n", + " (300, 100),\n", + " (500, 100),\n", + " (700, 300),\n", + " (700, 500),\n", + " (600, 700),\n", + " (400, 700),\n", + " (200, 600),\n", + "]\n", + "p1 = tml.PolygonInhom3D(\n", + " ml,\n", + " xy=xy1,\n", + " kaq=2,\n", + " z=[20, 10, 0],\n", + " kzoverkh=0.002,\n", + " topboundary=\"conf\",\n", + " order=5,\n", + " ndeg=3,\n", + ")\n", + "xy2 = [\n", + " (0, 600),\n", + " (200, 600),\n", + " (400, 700),\n", + " (400, 900),\n", + " (200, 1100),\n", + " (0, 1000),\n", + " (-100, 800),\n", + "]\n", + "p2 = tml.PolygonInhom3D(\n", + " ml,\n", + " xy=xy2,\n", + " kaq=20,\n", + " z=[20, 10, 0],\n", + " kzoverkh=0.05,\n", + " topboundary=\"conf\",\n", + " order=5,\n", + " ndeg=3,\n", + ")\n", "rf = tml.Constant(ml, xr=1000, yr=0, hr=40)\n", "uf = tml.Uflow(ml, slope=0.002, angle=-45)\n", "w = tml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", diff --git a/notebooks/timml_notebook3_sol.ipynb b/notebooks/timml_notebook3_sol.ipynb index d3450b1f..c7bf548c 100755 --- a/notebooks/timml_notebook3_sol.ipynb +++ b/notebooks/timml_notebook3_sol.ipynb @@ -73,11 +73,29 @@ ], "source": [ "ml = tml.ModelMaq(kaq=[10, 20], z=[20, 0, -10, -30], c=[4000])\n", - "xy1 = [(0, 600), (-100, 400), (-100, 200), (100, 100), (300, 100), (500, 100),\n", - " (700, 300), (700, 500), (600, 700), (400, 700), (200, 600)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy1, \n", - " kaq=[2, 80], z=[20, 0, -10, -30], c=[500], \n", - " topboundary='conf', order=3, ndeg=2)\n", + "xy1 = [\n", + " (0, 600),\n", + " (-100, 400),\n", + " (-100, 200),\n", + " (100, 100),\n", + " (300, 100),\n", + " (500, 100),\n", + " (700, 300),\n", + " (700, 500),\n", + " (600, 700),\n", + " (400, 700),\n", + " (200, 600),\n", + "]\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy1,\n", + " kaq=[2, 80],\n", + " z=[20, 0, -10, -30],\n", + " c=[500],\n", + " topboundary=\"conf\",\n", + " order=3,\n", + " ndeg=2,\n", + ")\n", "rf = tml.Constant(ml, xr=1000, yr=0, hr=40)\n", "uf = tml.Uflow(ml, slope=0.002, angle=-45)\n", "w = tml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", @@ -108,8 +126,8 @@ } ], "source": [ - "print('Leakage factor of the background aquifer is:', ml.aq.lab)\n", - "print('Leakage factor of the inhomogeneity is:', p1.lab)" + "print(\"Leakage factor of the background aquifer is:\", ml.aq.lab)\n", + "print(\"Leakage factor of the inhomogeneity is:\", p1.lab)" ] }, { @@ -148,7 +166,15 @@ } ], "source": [ - "ml.contour(win=[-200, 800, 0, 800], ngr=50, layers=[0, 1], levels=50, labels=1, decimals=2, figsize=figsize)" + "ml.contour(\n", + " win=[-200, 800, 0, 800],\n", + " ngr=50,\n", + " layers=[0, 1],\n", + " levels=50,\n", + " labels=1,\n", + " decimals=2,\n", + " figsize=figsize,\n", + ")" ] }, { @@ -179,7 +205,15 @@ } ], "source": [ - "ml.contour(win=[-1200, 1800, -1000, 1800], ngr=50, layers=[0, 1], levels=50, labels=1, decimals=2, figsize=figsize)" + "ml.contour(\n", + " win=[-1200, 1800, -1000, 1800],\n", + " ngr=50,\n", + " layers=[0, 1],\n", + " levels=50,\n", + " labels=1,\n", + " decimals=2,\n", + " figsize=figsize,\n", + ")" ] }, { @@ -289,8 +323,8 @@ } ], "source": [ - "ml.plot(win=[-200, 800, 0, 800], orientation='both', figsize=figsize)\n", - "w.plotcapzone(hstepmax=50, nt=20, zstart=10, tmax=20 * 365.25, orientation='both')" + "ml.plot(win=[-200, 800, 0, 800], orientation=\"both\", figsize=figsize)\n", + "w.plotcapzone(hstepmax=50, nt=20, zstart=10, tmax=20 * 365.25, orientation=\"both\")" ] }, { @@ -323,11 +357,29 @@ ], "source": [ "ml = tml.ModelMaq(kaq=[10, 20], z=[20, 0, -10, -30], c=[4000])\n", - "xy1 = [(0, 600), (-100, 400), (-100, 200), (100, 100), (300, 100), (500, 100),\n", - " (700, 300), (700, 500), (600, 700), (400, 700), (200, 600)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy1, \n", - " kaq=[2, 80], z=[20, 0, -10, -40], c=[500], \n", - " topboundary='conf', order=5, ndeg=3)\n", + "xy1 = [\n", + " (0, 600),\n", + " (-100, 400),\n", + " (-100, 200),\n", + " (100, 100),\n", + " (300, 100),\n", + " (500, 100),\n", + " (700, 300),\n", + " (700, 500),\n", + " (600, 700),\n", + " (400, 700),\n", + " (200, 600),\n", + "]\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy1,\n", + " kaq=[2, 80],\n", + " z=[20, 0, -10, -40],\n", + " c=[500],\n", + " topboundary=\"conf\",\n", + " order=5,\n", + " ndeg=3,\n", + ")\n", "rf = tml.Constant(ml, xr=1000, yr=0, hr=40)\n", "uf = tml.Uflow(ml, slope=0.002, angle=-45)\n", "w = tml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", @@ -365,8 +417,10 @@ } ], "source": [ - "ml.plot(win=[-200, 800, 0, 800], orientation='both', figsize=figsize)\n", - "ml.tracelines(-200 * np.ones(2), 700 * np.ones(2), [-25, -15], hstepmax=25, orientation='both')" + "ml.plot(win=[-200, 800, 0, 800], orientation=\"both\", figsize=figsize)\n", + "ml.tracelines(\n", + " -200 * np.ones(2), 700 * np.ones(2), [-25, -15], hstepmax=25, orientation=\"both\"\n", + ")" ] }, { @@ -408,15 +462,48 @@ ], "source": [ "ml = tml.ModelMaq(kaq=[10, 20], z=[20, 0, -10, -30], c=[4000])\n", - "xy1 = [(0, 600), (-100, 400), (-100, 200), (100, 100), (300, 100), (500, 100),\n", - " (700, 300), (700, 500), (600, 700), (400, 700), (200, 600)]\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy1, \n", - " kaq=[2, 80], z=[20, 0, -10, -30], c=[500], \n", - " topboundary='conf', order=4, ndeg=2)\n", - "xy2 = [(0, 600), (200, 600), (400, 700), (400, 900), (200, 1100), (0, 1000), (-100, 800)]\n", - "p2 = tml.PolygonInhomMaq(ml, xy=xy2, \n", - " kaq=[2, 8], z=[20, 0, -10, -30], c=[50], \n", - " topboundary='conf', order=4, ndeg=2)\n", + "xy1 = [\n", + " (0, 600),\n", + " (-100, 400),\n", + " (-100, 200),\n", + " (100, 100),\n", + " (300, 100),\n", + " (500, 100),\n", + " (700, 300),\n", + " (700, 500),\n", + " (600, 700),\n", + " (400, 700),\n", + " (200, 600),\n", + "]\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy1,\n", + " kaq=[2, 80],\n", + " z=[20, 0, -10, -30],\n", + " c=[500],\n", + " topboundary=\"conf\",\n", + " order=4,\n", + " ndeg=2,\n", + ")\n", + "xy2 = [\n", + " (0, 600),\n", + " (200, 600),\n", + " (400, 700),\n", + " (400, 900),\n", + " (200, 1100),\n", + " (0, 1000),\n", + " (-100, 800),\n", + "]\n", + "p2 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy2,\n", + " kaq=[2, 8],\n", + " z=[20, 0, -10, -30],\n", + " c=[50],\n", + " topboundary=\"conf\",\n", + " order=4,\n", + " ndeg=2,\n", + ")\n", "rf = tml.Constant(ml, xr=1000, yr=0, hr=40)\n", "uf = tml.Uflow(ml, slope=0.002, angle=-45)\n", "w = tml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", @@ -451,8 +538,7 @@ } ], "source": [ - "ml.contour(win=[-200, 1000, 0, 1200], ngr=50, layers=[0, 1], \n", - " levels=20, figsize=figsize)" + "ml.contour(win=[-200, 1000, 0, 1200], ngr=50, layers=[0, 1], levels=20, figsize=figsize)" ] }, { @@ -509,9 +595,16 @@ ], "source": [ "ml = tml.ModelMaq(kaq=[10, 20], z=[20, 0, -10, -30], c=[4000])\n", - "p1 = tml.PolygonInhomMaq(ml, xy=xy1[::-1], \n", - " kaq=[2, 80], z=[20, 0, -10, -30], c=[500], \n", - " topboundary='conf', order=3, ndeg=2)\n", + "p1 = tml.PolygonInhomMaq(\n", + " ml,\n", + " xy=xy1[::-1],\n", + " kaq=[2, 80],\n", + " z=[20, 0, -10, -30],\n", + " c=[500],\n", + " topboundary=\"conf\",\n", + " order=3,\n", + " ndeg=2,\n", + ")\n", "rf = tml.Constant(ml, xr=1000, yr=0, hr=40)\n", "uf = tml.Uflow(ml, slope=0.002, angle=-45)\n", "w = tml.Well(ml, xw=400, yw=400, Qw=500, rw=0.2, layers=0)\n", @@ -546,7 +639,15 @@ } ], "source": [ - "ml.contour(win=[-200, 800, 0, 800], ngr=50, layers=[0, 1], levels=50, labels=1, decimals=2, figsize=figsize)" + "ml.contour(\n", + " win=[-200, 800, 0, 800],\n", + " ngr=50,\n", + " layers=[0, 1],\n", + " levels=50,\n", + " labels=1,\n", + " decimals=2,\n", + " figsize=figsize,\n", + ")" ] }, { diff --git a/notebooks/timml_notebook4_sol.ipynb b/notebooks/timml_notebook4_sol.ipynb index 7707f554..c06dac8b 100644 --- a/notebooks/timml_notebook4_sol.ipynb +++ b/notebooks/timml_notebook4_sol.ipynb @@ -46,7 +46,13 @@ "z = [20, 15, 10, 8, 6, 5.5, 5.2, 4.8, 4.4, 4, 2, 0]\n", "ml = tml.Model3D(kaq=10, z=z, kzoverkh=0.1)\n", "ls1 = tml.LineSinkDitch(ml, x1=-100, y1=0, x2=100, y2=0, Qls=10000, order=5, layers=6)\n", - "ls2 = tml.HeadLineSinkString(ml, [(200, -1000), (200, -200), (200, 0), (200, 200), (200, 1000)], hls=40, order=5, layers=0)\n", + "ls2 = tml.HeadLineSinkString(\n", + " ml,\n", + " [(200, -1000), (200, -200), (200, 0), (200, 200), (200, 1000)],\n", + " hls=40,\n", + " order=5,\n", + " layers=0,\n", + ")\n", "rf = tml.Constant(ml, xr=-1000, yr=0, hr=42, layer=0)" ] }, @@ -113,9 +119,8 @@ } ], "source": [ - "ml.contour(win=[-150, 150, -150, 150], ngr=[50, 100], layers = [0, 6],\n", - " figsize=figsize)\n", - "print('The head at the top and in layer 6 are:')\n", + "ml.contour(win=[-150, 150, -150, 150], ngr=[50, 100], layers=[0, 6], figsize=figsize)\n", + "print(\"The head at the top and in layer 6 are:\")\n", "print(ml.head(0, 0.2, [0, 6]))" ] }, @@ -153,11 +158,25 @@ } ], "source": [ - "ml.plot(win=[-1000, 1000, -1000, 1000], orientation='both', figsize=figsize)\n", - "ml.tracelines(xstart=[-500, -500, -500], ystart=[-500, -500, -500], zstart=[5, 9, 15], \n", - " hstepmax=20, tmax=10 * 365.25, orientation='both', color='C0')\n", - "ml.tracelines(xstart=[250, 250, 250], ystart=[50, 50, 50], zstart=[5, 9, 15], \n", - " hstepmax=20, tmax=10 * 365.25, orientation='both', color='C1')" + "ml.plot(win=[-1000, 1000, -1000, 1000], orientation=\"both\", figsize=figsize)\n", + "ml.tracelines(\n", + " xstart=[-500, -500, -500],\n", + " ystart=[-500, -500, -500],\n", + " zstart=[5, 9, 15],\n", + " hstepmax=20,\n", + " tmax=10 * 365.25,\n", + " orientation=\"both\",\n", + " color=\"C0\",\n", + ")\n", + "ml.tracelines(\n", + " xstart=[250, 250, 250],\n", + " ystart=[50, 50, 50],\n", + " zstart=[5, 9, 15],\n", + " hstepmax=20,\n", + " tmax=10 * 365.25,\n", + " orientation=\"both\",\n", + " color=\"C1\",\n", + ")" ] }, { @@ -221,7 +240,7 @@ } ], "source": [ - "print('head inside w/o resistance:')\n", + "print(\"head inside w/o resistance:\")\n", "print(ls1.headinside())" ] }, @@ -242,9 +261,16 @@ ], "source": [ "ml = tml.Model3D(kaq=10, z=z, kzoverkh=0.1)\n", - "ls = tml.LineSinkDitch(ml, x1=-100, y1=0, x2=100, y2=0, Qls=10000, order=5, layers=6, wh=0.4, res=0.01)\n", - "tml.HeadLineSinkString(ml, [(200, -1000), (200, -200), (200, 0), (200, 200), (200, 1000)], \n", - " hls=40, order=5, layers=0)\n", + "ls = tml.LineSinkDitch(\n", + " ml, x1=-100, y1=0, x2=100, y2=0, Qls=10000, order=5, layers=6, wh=0.4, res=0.01\n", + ")\n", + "tml.HeadLineSinkString(\n", + " ml,\n", + " [(200, -1000), (200, -200), (200, 0), (200, 200), (200, 1000)],\n", + " hls=40,\n", + " order=5,\n", + " layers=0,\n", + ")\n", "rf = tml.Constant(ml, xr=-1000, yr=0, hr=42, layer=0)\n", "ml.solve()" ] @@ -263,7 +289,7 @@ } ], "source": [ - "print('head inside horizontal well:', ls.headinside())" + "print(\"head inside horizontal well:\", ls.headinside())" ] }, { @@ -325,7 +351,9 @@ "rf = tml.Constant(ml, 0, 1000, 20)\n", "x = np.linspace(-200, 200, 21)\n", "y = np.zeros(21)\n", - "ls = tml.HeadLineSinkString(ml, xy=list(zip(x, y)), hls=10, layers=np.arange(0, 20, 1), order=0)\n", + "ls = tml.HeadLineSinkString(\n", + " ml, xy=list(zip(x, y)), hls=10, layers=np.arange(0, 20, 1), order=0\n", + ")\n", "ml.solve()" ] }, @@ -412,7 +440,7 @@ ], "source": [ "Qtot = np.sum(ls.discharge())\n", - "print('Discharge of slanted well when modeled with fixed head hls=10:', Qtot)" + "print(\"Discharge of slanted well when modeled with fixed head hls=10:\", Qtot)" ] }, { @@ -436,7 +464,9 @@ "rf = tml.Constant(ml, 0, 1000, 20)\n", "x = np.linspace(-200, 200, 21)\n", "y = np.zeros(21)\n", - "ls = tml.LineSinkDitchString(ml, xy=list(zip(x, y)), Qls=Qtot, layers=np.arange(0, 20, 1), order=0)\n", + "ls = tml.LineSinkDitchString(\n", + " ml, xy=list(zip(x, y)), Qls=Qtot, layers=np.arange(0, 20, 1), order=0\n", + ")\n", "ml.solve()" ] }, @@ -504,7 +534,7 @@ } ], "source": [ - "print('Head in slanted well when modeled with fixed discharge:')\n", + "print(\"Head in slanted well when modeled with fixed discharge:\")\n", "[print(lspart.headinside()) for lspart in ls.lslist];" ] }, diff --git a/notebooks/timml_notebook5_sol.ipynb b/notebooks/timml_notebook5_sol.ipynb index 6c9b9c49..e4a42989 100644 --- a/notebooks/timml_notebook5_sol.ipynb +++ b/notebooks/timml_notebook5_sol.ipynb @@ -94,9 +94,15 @@ } ], "source": [ - "ml.contour(win=[-300, 300, -300, 300], ngr=50, \n", - " labels=1, decimals=1, layers=[0, 3], levels=np.arange(48, 58, 0.5),\n", - " figsize=(6,6))" + "ml.contour(\n", + " win=[-300, 300, -300, 300],\n", + " ngr=50,\n", + " labels=1,\n", + " decimals=1,\n", + " layers=[0, 3],\n", + " levels=np.arange(48, 58, 0.5),\n", + " figsize=(6, 6),\n", + ")" ] }, { @@ -123,9 +129,15 @@ } ], "source": [ - "ml.plot(win=[-300, 300, -300, 300], orientation='both')\n", - "ml.tracelines(xstart=-200 * np.ones(5), ystart=np.arange(-200, 201, 100), \n", - " zstart=35 * np.ones(5), hstepmax=10, tmax=20 * 365.25, orientation='both')" + "ml.plot(win=[-300, 300, -300, 300], orientation=\"both\")\n", + "ml.tracelines(\n", + " xstart=-200 * np.ones(5),\n", + " ystart=np.arange(-200, 201, 100),\n", + " zstart=35 * np.ones(5),\n", + " hstepmax=10,\n", + " tmax=20 * 365.25,\n", + " orientation=\"both\",\n", + ")" ] }, { @@ -152,9 +164,15 @@ } ], "source": [ - "ml.plot(win=[-300, 300, -300, 300], orientation='both')\n", - "ml.tracelines(xstart=-200 * np.ones(3), ystart=np.arange(-100, 101, 100), \n", - " zstart=35 * np.ones(3), hstepmax=10, tmax=20 * 365.25, orientation='both')" + "ml.plot(win=[-300, 300, -300, 300], orientation=\"both\")\n", + "ml.tracelines(\n", + " xstart=-200 * np.ones(3),\n", + " ystart=np.arange(-100, 101, 100),\n", + " zstart=35 * np.ones(3),\n", + " hstepmax=10,\n", + " tmax=20 * 365.25,\n", + " orientation=\"both\",\n", + ")" ] }, { diff --git a/notebooks/timml_notebook6_sol.ipynb b/notebooks/timml_notebook6_sol.ipynb index ee913d9a..4edf80ff 100644 --- a/notebooks/timml_notebook6_sol.ipynb +++ b/notebooks/timml_notebook6_sol.ipynb @@ -99,8 +99,15 @@ } ], "source": [ - "ml.contour(win=[-1200, 200, -500, 500], ngr=50,\n", - " levels=10, labels=True, decimals=2, legend=True, figsize=(8, 8))" + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " levels=10,\n", + " labels=True,\n", + " decimals=2,\n", + " legend=True,\n", + " figsize=(8, 8),\n", + ")" ] }, { @@ -138,8 +145,14 @@ } ], "source": [ - "ml.contour(win=[-1200, 200, -500, 500], ngr=50,\n", - " levels=np.arange(39, 42, 0.1), labels=True, decimals=1, figsize=(8, 8))" + "ml.contour(\n", + " win=[-1200, 200, -500, 500],\n", + " ngr=50,\n", + " levels=np.arange(39, 42, 0.1),\n", + " labels=True,\n", + " decimals=1,\n", + " figsize=(8, 8),\n", + ")" ] }, { @@ -155,7 +168,7 @@ "metadata": {}, "outputs": [], "source": [ - "w = tml.Well(ml, xw=-400, yw=0, Qw=50., rw=0.2)" + "w = tml.Well(ml, xw=-400, yw=0, Qw=50.0, rw=0.2)" ] }, { @@ -193,8 +206,18 @@ ], "source": [ "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8))\n", - "traces = ml.tracelines(-800 * np.ones(1), -200 * np.ones(1), np.zeros(1), hstepmax=20, color='C1', return_traces=True, metadata=True)" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8)\n", + ")\n", + "traces = ml.tracelines(\n", + " -800 * np.ones(1),\n", + " -200 * np.ones(1),\n", + " np.zeros(1),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + " return_traces=True,\n", + " metadata=True,\n", + ")" ] }, { @@ -229,8 +252,16 @@ } ], "source": [ - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8))\n", - "ml.tracelines(-800 * np.ones(10), np.linspace(-500, 500, 10), np.zeros(10), hstepmax=20, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(10),\n", + " np.linspace(-500, 500, 10),\n", + " np.zeros(10),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + ")" ] }, { @@ -274,9 +305,17 @@ "uf = tml.Uflow(ml, slope=0.001, angle=0)\n", "w = tml.Well(ml, xw=-400, yw=0, Qw=200, rw=0.2)\n", "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8))\n", - "ml.tracelines(-800 * np.ones(10), np.linspace(-500, 500, 10), np.zeros(10), hstepmax=20, color='C1')\n", - "print(('head at well:', w.headinside()))" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(10),\n", + " np.linspace(-500, 500, 10),\n", + " np.zeros(10),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + ")\n", + "print((\"head at well:\", w.headinside()))" ] }, { @@ -320,8 +359,10 @@ "w = tml.Well(ml, xw=-400, yw=0, Qw=200, rw=0.2)\n", "ls1 = tml.HeadLineSink(ml, 0, -500, 0, 500, 40)\n", "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8))\n", - "print(('head at well:', w.headinside()))" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8)\n", + ")\n", + "print((\"head at well:\", w.headinside()))" ] }, { @@ -368,9 +409,19 @@ "yls = np.linspace(-800, 800, 21)\n", "ls = tml.HeadLineSinkString(ml, xy=list(zip(xls, yls)), hls=40, layers=0)\n", "ml.solve()\n", - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8))\n", - "ml.tracelines(-800 * np.ones(10), np.linspace(-500, 500, 10), np.zeros(10), hstepmax=20, color='C1')\n", - "ml.tracelines(-0.01 * np.ones(5), np.linspace(-150, 150, 5), np.zeros(5), hstepmax=20, color='C2')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), figsize=(8, 8)\n", + ")\n", + "ml.tracelines(\n", + " -800 * np.ones(10),\n", + " np.linspace(-500, 500, 10),\n", + " np.zeros(10),\n", + " hstepmax=20,\n", + " color=\"C1\",\n", + ")\n", + "ml.tracelines(\n", + " -0.01 * np.ones(5), np.linspace(-150, 150, 5), np.zeros(5), hstepmax=20, color=\"C2\"\n", + ")" ] }, { @@ -405,8 +456,14 @@ } ], "source": [ - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), layers=0, figsize=(8, 8))\n", - "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=5 * 365.25, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500],\n", + " ngr=50,\n", + " levels=np.arange(39, 42, 0.1),\n", + " layers=0,\n", + " figsize=(8, 8),\n", + ")\n", + "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=5 * 365.25, color=\"C1\")" ] }, { @@ -441,8 +498,14 @@ } ], "source": [ - "ml.contour(win=[-1000, 100, -500, 500], ngr=50, levels=np.arange(39, 42, 0.1), layers=0, figsize=(8, 8))\n", - "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=20 * 365.25, color='C1')" + "ml.contour(\n", + " win=[-1000, 100, -500, 500],\n", + " ngr=50,\n", + " levels=np.arange(39, 42, 0.1),\n", + " layers=0,\n", + " figsize=(8, 8),\n", + ")\n", + "w.plotcapzone(hstepmax=20, nt=20, zstart=0, tmax=20 * 365.25, color=\"C1\")" ] }, { diff --git a/notebooks/timml_notebook7.ipynb b/notebooks/timml_notebook7.ipynb index 30657c74..61ef606e 100644 --- a/notebooks/timml_notebook7.ipynb +++ b/notebooks/timml_notebook7.ipynb @@ -41,11 +41,11 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[10, 20, 5],\n", - " z=[0, -20, -40, -80, -90, -140], \n", - " c=[4000, 10000])\n", + "ml = tml.ModelMaq(kaq=[10, 20, 5], z=[0, -20, -40, -80, -90, -140], c=[4000, 10000])\n", "rf = tml.Constant(ml, xr=0, yr=10000, hr=20, layer=0)\n", - "ls1 = tml.HeadLineSinkString(ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=0)\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=0\n", + ")\n", "ml.solve()" ] }, @@ -95,11 +95,11 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[10, 20, 5],\n", - " z=[0, -20, -40, -80, -90, -140], \n", - " c=[4000, 10000])\n", + "ml = tml.ModelMaq(kaq=[10, 20, 5], z=[0, -20, -40, -80, -90, -140], c=[4000, 10000])\n", "rf = tml.Constant(ml, xr=0, yr=10000, hr=20, layer=0)\n", - "ls1 = tml.HeadLineSinkString(ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=[0, 1])\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=[0, 1]\n", + ")\n", "ml.solve()" ] }, @@ -149,11 +149,11 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[10, 20, 5],\n", - " z=[0, -20, -40, -80, -90, -140], \n", - " c=[4000, 10000])\n", + "ml = tml.ModelMaq(kaq=[10, 20, 5], z=[0, -20, -40, -80, -90, -140], c=[4000, 10000])\n", "rf = tml.Constant(ml, xr=0, yr=10000, hr=20, layer=0)\n", - "ls1 = tml.HeadLineSinkString(ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=[0, 1, 0])\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=[0, 1, 0]\n", + ")\n", "ml.solve()" ] }, @@ -271,11 +271,14 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[10, 20, 5],\n", - " z=[0, -20, -40, -80, -90, -140], \n", - " c=[4000, 10000])\n", + "ml = tml.ModelMaq(kaq=[10, 20, 5], z=[0, -20, -40, -80, -90, -140], c=[4000, 10000])\n", "rf = tml.Constant(ml, xr=0, yr=10000, hr=20, layer=0)\n", - "ls1 = tml.HeadLineSinkString(ml, xy=[(-100, 0), (0, 0), (100, 0), (100, 50)], hls=10, layers=[[0, 1], [0, 1], [0, 1]])\n", + "ls1 = tml.HeadLineSinkString(\n", + " ml,\n", + " xy=[(-100, 0), (0, 0), (100, 0), (100, 50)],\n", + " hls=10,\n", + " layers=[[0, 1], [0, 1], [0, 1]],\n", + ")\n", "ml.solve()" ] }, diff --git a/notebooks/timml_xsection.ipynb b/notebooks/timml_xsection.ipynb index 4d835e88..0fb7f582 100644 --- a/notebooks/timml_xsection.ipynb +++ b/notebooks/timml_xsection.ipynb @@ -63,16 +63,17 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], \\\n", - " topboundary='semi', hstar=5)\n", + "ml = tml.ModelMaq(\n", + " kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary=\"semi\", hstar=5\n", + ")\n", "ls = tml.HeadLineSink1D(ml, xls=0, hls=2, layers=0)\n", "ml.solve()\n", "\n", "x = np.linspace(-200, 200, 101)\n", "h = ml.headalongline(x, np.zeros_like(x))\n", - "plt.plot(x, h[0], label='layer 0')\n", - "plt.plot(x, h[1], label='layer 1')\n", - "plt.legend(loc='best')" + "plt.plot(x, h[0], label=\"layer 0\")\n", + "plt.plot(x, h[1], label=\"layer 1\")\n", + "plt.legend(loc=\"best\")" ] }, { @@ -110,20 +111,49 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary='semi', hstar=5)\n", - "tml.StripInhomMaq(ml, x1=-np.inf, x2=-50, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=15)\n", - "tml.StripInhomMaq(ml, x1=-50, x2=50, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=13)\n", - "tml.StripInhomMaq(ml, x1=50, x2=np.inf, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=11)\n", + "ml = tml.ModelMaq(\n", + " kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary=\"semi\", hstar=5\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-np.inf,\n", + " x2=-50,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=15,\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-50,\n", + " x2=50,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=13,\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=50,\n", + " x2=np.inf,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=11,\n", + ")\n", "ml.solve()\n", "\n", "x = np.linspace(-200, 200, 101)\n", "h = ml.headalongline(x, np.zeros(101))\n", - "plt.plot(x, h[0], label='layer 0')\n", - "plt.plot(x, h[1], label='layer 1')\n", - "plt.legend(loc='best');" + "plt.plot(x, h[0], label=\"layer 0\")\n", + "plt.plot(x, h[1], label=\"layer 1\")\n", + "plt.legend(loc=\"best\");" ] }, { @@ -199,13 +229,40 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary='semi', hstar=5)\n", - "tml.StripInhomMaq(ml, x1=-np.inf, x2=-50, kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], npor=0.3, \n", - " topboundary='conf')\n", - "tml.StripInhomMaq(ml, x1=-50, x2=50, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=3)\n", - "tml.StripInhomMaq(ml, x1=50, x2=np.inf, kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], npor=0.3, \n", - " topboundary='conf')\n", + "ml = tml.ModelMaq(\n", + " kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary=\"semi\", hstar=5\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-np.inf,\n", + " x2=-50,\n", + " kaq=[1, 2],\n", + " z=[3, 2, 1, 0],\n", + " c=[1000],\n", + " npor=0.3,\n", + " topboundary=\"conf\",\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-50,\n", + " x2=50,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=3,\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=50,\n", + " x2=np.inf,\n", + " kaq=[1, 2],\n", + " z=[3, 2, 1, 0],\n", + " c=[1000],\n", + " npor=0.3,\n", + " topboundary=\"conf\",\n", + ")\n", "rf1 = tml.Constant(ml, -100, 0, 4)\n", "rf2 = tml.Constant(ml, 100, 0, 4)\n", "\n", @@ -217,14 +274,14 @@ "\n", "plt.figure(figsize=(12, 4))\n", "plt.subplot(121)\n", - "plt.plot(x, h[0], label='layer 0')\n", - "plt.plot(x, h[1], label='layer 1')\n", - "plt.plot([-100, 100], [4, 4], 'b.', label='fixed heads')\n", - "plt.legend(loc='best')\n", + "plt.plot(x, h[0], label=\"layer 0\")\n", + "plt.plot(x, h[1], label=\"layer 1\")\n", + "plt.plot([-100, 100], [4, 4], \"b.\", label=\"fixed heads\")\n", + "plt.legend(loc=\"best\")\n", "plt.subplot(122)\n", - "plt.title('Qx')\n", - "plt.plot(x, Qx[0], label='layer 0')\n", - "plt.plot(x, Qx[1], label='layer 1')" + "plt.title(\"Qx\")\n", + "plt.plot(x, Qx[0], label=\"layer 0\")\n", + "plt.plot(x, Qx[1], label=\"layer 1\")" ] }, { @@ -305,7 +362,7 @@ "uf = tml.Uflow(ml, 0.002, 0)\n", "rf = tml.Constant(ml, 100, 0, 20)\n", "ld1 = tml.ImpLineDoublet1D(ml, xld=0, layers=[0, 1])\n", - " \n", + "\n", "ml.solve()\n", "\n", "x = np.linspace(-100, 100, 101)\n", @@ -314,17 +371,17 @@ "\n", "plt.figure(figsize=(12, 4))\n", "plt.subplot(121)\n", - "plt.title('head')\n", - "plt.plot(x, h[0], label='layer 0')\n", - "plt.plot(x, h[1], label='layer 1')\n", - "plt.plot(x, h[2], label='layer 2')\n", - "plt.legend(loc='best')\n", + "plt.title(\"head\")\n", + "plt.plot(x, h[0], label=\"layer 0\")\n", + "plt.plot(x, h[1], label=\"layer 1\")\n", + "plt.plot(x, h[2], label=\"layer 2\")\n", + "plt.legend(loc=\"best\")\n", "plt.subplot(122)\n", - "plt.title('Qx')\n", - "plt.plot(x, Qx[0], label='layer 0')\n", - "plt.plot(x, Qx[1], label='layer 1')\n", - "plt.plot(x, Qx[2], label='layer 2')\n", - "plt.legend(loc='best')" + "plt.title(\"Qx\")\n", + "plt.plot(x, Qx[0], label=\"layer 0\")\n", + "plt.plot(x, Qx[1], label=\"layer 1\")\n", + "plt.plot(x, Qx[2], label=\"layer 2\")\n", + "plt.legend(loc=\"best\")" ] }, { @@ -416,19 +473,44 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], topboundary='conf')\n", - "tml.StripInhomMaq(ml, x1=-np.inf, x2=-50, kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], npor=0.3, \n", - " topboundary='conf')\n", - "tml.StripInhomMaq(ml, x1=-50, x2=50, kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], npor=0.3, \n", - " topboundary='conf', N=0.001)\n", - "tml.StripInhomMaq(ml, x1=50, x2=np.inf, kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], npor=0.3, \n", - " topboundary='conf')\n", + "ml = tml.ModelMaq(kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], topboundary=\"conf\")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-np.inf,\n", + " x2=-50,\n", + " kaq=[1, 2],\n", + " z=[3, 2, 1, 0],\n", + " c=[1000],\n", + " npor=0.3,\n", + " topboundary=\"conf\",\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-50,\n", + " x2=50,\n", + " kaq=[1, 2],\n", + " z=[3, 2, 1, 0],\n", + " c=[1000],\n", + " npor=0.3,\n", + " topboundary=\"conf\",\n", + " N=0.001,\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=50,\n", + " x2=np.inf,\n", + " kaq=[1, 2],\n", + " z=[3, 2, 1, 0],\n", + " c=[1000],\n", + " npor=0.3,\n", + " topboundary=\"conf\",\n", + ")\n", "tml.Constant(ml, -100, 0, 10)\n", "tml.Constant(ml, 100, 0, 10)\n", "ml.solve()\n", "ml.vcontoursf1D(x1=-100, x2=100, nx=100, levels=20)\n", "#\n", - "ml2 = tml.ModelMaq(kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], topboundary='conf')\n", + "ml2 = tml.ModelMaq(kaq=[1, 2], z=[3, 2, 1, 0], c=[1000], topboundary=\"conf\")\n", "tml.StripAreaSink(ml2, -50, 50, 0.001)\n", "tml.Constant(ml2, -100, 0, 10)\n", "ml2.solve()\n", @@ -436,10 +518,10 @@ "#\n", "x = np.linspace(-100, 100, 100)\n", "plt.figure()\n", - "plt.plot(x, ml.headalongline(x, 0)[0], 'C0')\n", - "plt.plot(x, ml.headalongline(x, 0)[1], 'C0')\n", - "plt.plot(x, ml2.headalongline(x, 0)[0], '--C1')\n", - "plt.plot(x, ml2.headalongline(x, 0)[1], '--C1')" + "plt.plot(x, ml.headalongline(x, 0)[0], \"C0\")\n", + "plt.plot(x, ml.headalongline(x, 0)[1], \"C0\")\n", + "plt.plot(x, ml2.headalongline(x, 0)[0], \"--C1\")\n", + "plt.plot(x, ml2.headalongline(x, 0)[1], \"--C1\")" ] }, { @@ -479,12 +561,19 @@ ], "source": [ "ml = tml.Model3D(kaq=1, z=np.arange(5, -0.1, -0.1))\n", - "tml.StripInhom3D(ml, x1=-np.inf, x2=-5, kaq=1, z=np.arange(5, -0.1, -0.1), \n", - " kzoverkh=0.1)\n", - "tml.StripInhom3D(ml, x1=-5, x2=5, kaq=1, z=np.arange(5, -0.1, -0.1),\n", - " kzoverkh=0.1, topboundary='semi', hstar=3, topres=3)\n", - "tml.StripInhom3D(ml, x1=5, x2=np.inf, kaq=1, z=np.arange(5, -0.1, -0.1), \n", - " kzoverkh=0.1)\n", + "tml.StripInhom3D(ml, x1=-np.inf, x2=-5, kaq=1, z=np.arange(5, -0.1, -0.1), kzoverkh=0.1)\n", + "tml.StripInhom3D(\n", + " ml,\n", + " x1=-5,\n", + " x2=5,\n", + " kaq=1,\n", + " z=np.arange(5, -0.1, -0.1),\n", + " kzoverkh=0.1,\n", + " topboundary=\"semi\",\n", + " hstar=3,\n", + " topres=3,\n", + ")\n", + "tml.StripInhom3D(ml, x1=5, x2=np.inf, kaq=1, z=np.arange(5, -0.1, -0.1), kzoverkh=0.1)\n", "rf1 = tml.Constant(ml, -100, 0, 3.2)\n", "rf2 = tml.Constant(ml, 100, 0, 2.97)\n", "\n", @@ -530,12 +619,19 @@ ], "source": [ "ml = tml.Model3D(kaq=1, z=np.arange(5, -0.1, -1))\n", - "tml.StripInhom3D(ml, x1=-np.inf, x2=-5, kaq=1, z=np.arange(5, -0.1, -1), \n", - " kzoverkh=0.1)\n", - "tml.StripInhom3D(ml, x1=-5, x2=5, kaq=1, z=np.arange(5, -0.1, -1),\n", - " kzoverkh=0.1, topboundary='semi', hstar=3, topres=3)\n", - "tml.StripInhom3D(ml, x1=5, x2=np.inf, kaq=1, z=np.arange(5, -0.1, -1), \n", - " kzoverkh=0.1)\n", + "tml.StripInhom3D(ml, x1=-np.inf, x2=-5, kaq=1, z=np.arange(5, -0.1, -1), kzoverkh=0.1)\n", + "tml.StripInhom3D(\n", + " ml,\n", + " x1=-5,\n", + " x2=5,\n", + " kaq=1,\n", + " z=np.arange(5, -0.1, -1),\n", + " kzoverkh=0.1,\n", + " topboundary=\"semi\",\n", + " hstar=3,\n", + " topres=3,\n", + ")\n", + "tml.StripInhom3D(ml, x1=5, x2=np.inf, kaq=1, z=np.arange(5, -0.1, -1), kzoverkh=0.1)\n", "rf1 = tml.Constant(ml, -100, 0, 3.2)\n", "rf2 = tml.Constant(ml, 100, 0, 2.97)\n", "\n", @@ -560,13 +656,42 @@ } ], "source": [ - "ml = tml.ModelMaq(kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary='semi', hstar=5)\n", - "tml.StripInhomMaq(ml, x1=-np.inf, x2=-50, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=15)\n", - "tml.StripInhomMaq(ml, x1=-50, x2=50, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=13)\n", - "tml.StripInhomMaq(ml, x1=50, x2=np.inf, kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], npor=0.3, \n", - " topboundary='semi', hstar=11)\n", + "ml = tml.ModelMaq(\n", + " kaq=[1, 2], z=[4, 3, 2, 1, 0], c=[1000, 1000], topboundary=\"semi\", hstar=5\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-np.inf,\n", + " x2=-50,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=15,\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=-50,\n", + " x2=50,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=13,\n", + ")\n", + "tml.StripInhomMaq(\n", + " ml,\n", + " x1=50,\n", + " x2=np.inf,\n", + " kaq=[1, 2],\n", + " z=[4, 3, 2, 1, 0],\n", + " c=[1000, 1000],\n", + " npor=0.3,\n", + " topboundary=\"semi\",\n", + " hstar=11,\n", + ")\n", "ml.solve()" ] }, diff --git a/tests/test_besselaes.py b/tests/test_besselaes.py index 7c44cb06..d31fc4ac 100644 --- a/tests/test_besselaes.py +++ b/tests/test_besselaes.py @@ -1,6 +1,7 @@ import numpy as np import pytest from numpy.testing import assert_allclose + from timml.besselaesnumba import besselaesnumba as besselaesnew """ @@ -20,53 +21,60 @@ # @pytest.mark.skip(reason="no fortran extension by default") def potbesldho(x): - pot = besselaesnew.potbesldho(2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), - [0.0, 2.0, 11.0], x, 1, 3) + pot = besselaesnew.potbesldho( + 2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), [0.0, 2.0, 11.0], x, 1, 3 + ) return pot # @pytest.mark.skip(reason="no fortran extension by default") def test_potbesldho(): - assert_allclose(potbesldho(0), np.array( - [-0.31055947, -0.23498503, -0.30327438])) - assert_allclose(potbesldho(1), np.array( - [-0.17694283, -0.15257055, -0.17583515])) + assert_allclose(potbesldho(0), np.array([-0.31055947, -0.23498503, -0.30327438])) + assert_allclose(potbesldho(1), np.array([-0.17694283, -0.15257055, -0.17583515])) # @pytest.mark.skip(reason="no fortran extension by default") def test_potbesldv(): - potv = besselaesnew.potbesldv(2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), - [0.0, 2.0, 11.0], 1, 1, 3) + potv = besselaesnew.potbesldv( + 2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), [0.0, 2.0, 11.0], 1, 1, 3 + ) assert_allclose(potv[0], np.array([-0.31055947, -0.23498503, -0.30327438])) assert_allclose(potv[1], np.array([-0.17694283, -0.15257055, -0.17583515])) # @pytest.mark.skip(reason="no fortran extension by default") def test_disbesldho(): - qxqy_zero = besselaesnew.disbesldho(2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), - [0.0, 2.0, 11.0], 0, 1, 3) - assert_allclose(qxqy_zero[0], np.array( - [-0.170131146, -0.18423853, -0.173157849])) - assert_allclose(qxqy_zero[1], np.array( - [0.0274405074, 0.0888068675, 0.0342656083])) + qxqy_zero = besselaesnew.disbesldho( + 2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), [0.0, 2.0, 11.0], 0, 1, 3 + ) + assert_allclose(qxqy_zero[0], np.array([-0.170131146, -0.18423853, -0.173157849])) + assert_allclose(qxqy_zero[1], np.array([0.0274405074, 0.0888068675, 0.0342656083])) - qxqy_one = besselaesnew.disbesldho(2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), - [0.0, 2.0, 11.0], 1, 1, 3) - assert_allclose(qxqy_one[0], np.array( - [-0.10412493, -0.1084466406, -0.104477618])) - assert_allclose(qxqy_one[1], np.array( - [0.106176131, 0.1162738781, 0.1067421121])) + qxqy_one = besselaesnew.disbesldho( + 2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), [0.0, 2.0, 11.0], 1, 1, 3 + ) + assert_allclose(qxqy_one[0], np.array([-0.10412493, -0.1084466406, -0.104477618])) + assert_allclose(qxqy_one[1], np.array([0.106176131, 0.1162738781, 0.1067421121])) # @pytest.mark.skip(reason="no fortran extension by default") def test_disbesldv(): - qxqyv = besselaesnew.disbesldv(2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), - [0.0, 2.0, 11.0], 1, 1, 3) - assert_allclose(qxqyv[0], np.array( - [-0.17013114606375021, -0.18423853257632447, -0.17315784943727297])) - assert_allclose(qxqyv[2], np.array( - [2.7440507429637e-002, 8.880686745447e-002, 3.426560831291e-002])) - assert_allclose(qxqyv[1], np.array( - [-0.10412493484448178, -0.10844664064434061, -0.10447761803194042])) - assert_allclose(qxqyv[3], np.array( - [0.10617613097471285, 0.11627387807684744, 0.10674211206906066])) + qxqyv = besselaesnew.disbesldv( + 2.0, 1.0, complex(-3.0, -1.0), complex(2.0, 2.0), [0.0, 2.0, 11.0], 1, 1, 3 + ) + assert_allclose( + qxqyv[0], + np.array([-0.17013114606375021, -0.18423853257632447, -0.17315784943727297]), + ) + assert_allclose( + qxqyv[2], + np.array([2.7440507429637e-002, 8.880686745447e-002, 3.426560831291e-002]), + ) + assert_allclose( + qxqyv[1], + np.array([-0.10412493484448178, -0.10844664064434061, -0.10447761803194042]), + ) + assert_allclose( + qxqyv[3], + np.array([0.10617613097471285, 0.11627387807684744, 0.10674211206906066]), + ) diff --git a/tests/test_import.py b/tests/test_import.py index e422a320..ff8b0284 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -1,5 +1,6 @@ def test_import(): import timml -if __name__ == '__main__': + +if __name__ == "__main__": test_import() diff --git a/tests/test_notebooks.py b/tests/test_notebooks.py index 4fd1bb39..6abcf62c 100644 --- a/tests/test_notebooks.py +++ b/tests/test_notebooks.py @@ -5,47 +5,59 @@ import pytest -nbdir = os.path.join('notebooks') +nbdir = os.path.join("notebooks") testdir = tempfile.mkdtemp() + def get_notebooks(): skip = ["benchmarking_besselaes.ipynb"] - return [f for f in os.listdir(nbdir) if f.endswith('.ipynb') and f not in skip] + return [f for f in os.listdir(nbdir) if f.endswith(".ipynb") and f not in skip] + def get_jupyter_kernel(): try: - jklcmd = ('jupyter', 'kernelspec', 'list') - b = subprocess.Popen(jklcmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0] + jklcmd = ("jupyter", "kernelspec", "list") + b = subprocess.Popen( + jklcmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ).communicate()[0] if isinstance(b, bytes): - b = b.decode('utf-8') + b = b.decode("utf-8") print(b) for line in b.splitlines(): - if 'python' in line: + if "python" in line: kernel = line.split()[0] except: kernel = None - - return kernel + + return kernel + @pytest.mark.notebooks @pytest.mark.parametrize("fn", get_notebooks()) def test_notebook(fn): - kernel = get_jupyter_kernel() - print('available jupyter kernel {}'.format(kernel)) + print("available jupyter kernel {}".format(kernel)) pth = os.path.join(nbdir, fn) - - cmd = 'jupyter ' + 'nbconvert ' + \ - '--ExecutePreprocessor.timeout=600 ' + '--to ' + 'notebook ' + \ - '--execute ' + '{} '.format(pth) + \ - '--output-dir ' + '{} '.format(testdir) + \ - '--output ' + '{}'.format(fn) + + cmd = ( + "jupyter " + + "nbconvert " + + "--ExecutePreprocessor.timeout=600 " + + "--to " + + "notebook " + + "--execute " + + "{} ".format(pth) + + "--output-dir " + + "{} ".format(testdir) + + "--output " + + "{}".format(fn) + ) ival = os.system(cmd) - assert ival == 0, 'could not run {}'.format(fn) + assert ival == 0, "could not run {}".format(fn) -if __name__ == '__main__': +if __name__ == "__main__": test_notebook() shutil.rmtree(testdir) diff --git a/timml/aquifer.py b/timml/aquifer.py index fafb9fe0..e4dd62dd 100644 --- a/timml/aquifer.py +++ b/timml/aquifer.py @@ -1,8 +1,11 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np + from .aquifer_parameters import param_maq from .constant import ConstantStar + class AquiferData: def __init__(self, model, kaq, c, z, npor, ltype): # All input variables except model should be numpy arrays @@ -20,34 +23,36 @@ def __init__(self, model, kaq, c, z, npor, ltype): self.npor = np.atleast_1d(npor) self.ltype = np.atleast_1d(ltype) # tag indicating whether an aquifer is Laplace (confined on top) - if self.ltype[0] == 'a': + if self.ltype[0] == "a": self.ilap = 1 else: self.ilap = 0 # self.area = 1e200 # Smaller than default of ml.aq so that inhom is found - self.layernumber = np.zeros(self.nlayers, dtype='int') - self.layernumber[self.ltype == 'a'] = np.arange(self.naq) - self.layernumber[self.ltype == 'l'] = np.arange(self.nlayers - self.naq) - if self.ltype[0] == 'a': - self.layernumber[self.ltype == 'l'] += 1 # first leaky layer below first aquifer layer - self.zaqtop = self.z[:-1][self.ltype == 'a'] - self.zaqbot = self.z[1:][self.ltype == 'a'] + self.layernumber = np.zeros(self.nlayers, dtype="int") + self.layernumber[self.ltype == "a"] = np.arange(self.naq) + self.layernumber[self.ltype == "l"] = np.arange(self.nlayers - self.naq) + if self.ltype[0] == "a": + self.layernumber[ + self.ltype == "l" + ] += 1 # first leaky layer below first aquifer layer + self.zaqtop = self.z[:-1][self.ltype == "a"] + self.zaqbot = self.z[1:][self.ltype == "a"] self.Haq = self.zaqtop - self.zaqbot self.T = self.kaq * self.Haq self.Tcol = self.T[:, np.newaxis] - self.zlltop = self.z[:-1][self.ltype == 'l'] - self.zllbot = self.z[1:][self.ltype == 'l'] - if self.ltype[0] == 'a': + self.zlltop = self.z[:-1][self.ltype == "l"] + self.zllbot = self.z[1:][self.ltype == "l"] + if self.ltype[0] == "a": self.zlltop = np.hstack((self.z[0], self.zlltop)) self.zllbot = np.hstack((self.z[0], self.zllbot)) self.Hll = self.zlltop - self.zllbot - self.nporaq = self.npor[self.ltype == 'a'] - if self.ltype[0] == 'a': - self.nporll = np.ones(len(self.npor[self.ltype == 'l']) + 1) - self.nporll[1:] = self.npor[self.ltype == 'l'] + self.nporaq = self.npor[self.ltype == "a"] + if self.ltype[0] == "a": + self.nporll = np.ones(len(self.npor[self.ltype == "l"]) + 1) + self.nporll[1:] = self.npor[self.ltype == "l"] else: - self.nporll = self.npor[self.ltype == 'l'] + self.nporll = self.npor[self.ltype == "l"] def initialize(self): self.elementlist = [] # Elementlist of aquifer @@ -64,7 +69,9 @@ def initialize(self): if self.ilap: self.lab = np.zeros(self.naq) self.lab[1:] = 1.0 / np.sqrt(w[1:]) - self.zeropluslab = self.lab # to be deprecated when new lambda is fully implemented + self.zeropluslab = ( + self.lab + ) # to be deprecated when new lambda is fully implemented v[:, 0] = self.T / np.sum(self.T) # first column is normalized T else: self.lab = 1.0 / np.sqrt(w) @@ -77,24 +84,24 @@ def add_element(self, e): self.hstar = e.hstar def isinside(self, x, y): - raise Exception('Must overload AquiferData.isinside()') + raise Exception("Must overload AquiferData.isinside()") def storeinput(self, frame): self.inputargs, _, _, self.inputvalues = inspect.getargvalues(frame) - + def findlayer(self, z): - ''' - Returns layer-number, layer-type and model-layer-number''' + """ + Returns layer-number, layer-type and model-layer-number""" if z > self.z[0]: - modellayer, ltype = -1, 'above' + modellayer, ltype = -1, "above" layernumber = None elif z < self.z[-1]: - modellayer, ltype = len(self.layernumber), 'below' + modellayer, ltype = len(self.layernumber), "below" layernumber = None else: modellayer = np.argwhere((z <= self.z[:-1]) & (z >= self.z[1:]))[0, 0] layernumber = self.layernumber[modellayer] - ltype = self.ltype[modellayer] + ltype = self.ltype[modellayer] return layernumber, ltype, modellayer @@ -131,6 +138,3 @@ def find_aquifer_data(self, x, y): # if inhom.area < rv.area: # rv = i # return rv - - - diff --git a/timml/aquifer_parameters.py b/timml/aquifer_parameters.py index 9ac0ee3d..cf020155 100644 --- a/timml/aquifer_parameters.py +++ b/timml/aquifer_parameters.py @@ -1,64 +1,81 @@ import numpy as np + def param_maq(kaq, z, c, npor, top): # Computes the parameters for a ModelBase from input for a maq model - kaq = np.atleast_1d(kaq).astype('d') - z = np.atleast_1d(z).astype('d') - c = np.atleast_1d(c).astype('d') - npor = np.atleast_1d(npor).astype('d') - if top == 'conf': + kaq = np.atleast_1d(kaq).astype("d") + z = np.atleast_1d(z).astype("d") + c = np.atleast_1d(c).astype("d") + npor = np.atleast_1d(npor).astype("d") + if top == "conf": Naq = int(len(z) / 2) - ltype = np.array( list((Naq-1) * 'al' + 'a' )) - else: # leaky layer on top + ltype = np.array(list((Naq - 1) * "al" + "a")) + else: # leaky layer on top Naq = int((len(z) - 1) / 2) - ltype = np.array(list(Naq * 'la')) - if len(kaq) == 1: kaq = kaq * np.ones(Naq) - assert len(kaq) == Naq, 'Error: length of kaq needs to be 1 or' + str(Naq) + ltype = np.array(list(Naq * "la")) + if len(kaq) == 1: + kaq = kaq * np.ones(Naq) + assert len(kaq) == Naq, "Error: length of kaq needs to be 1 or" + str(Naq) H = z[:-1] - z[1:] - assert np.all(H >= 0), 'Error: Not all layers thicknesses are non-negative' + str(H) - if top == 'conf': - if len(c) == 1: c = c * np.ones(Naq - 1) - if len(npor) == 1: npor = npor * np.ones(2 * Naq - 1) - assert len(c) == Naq-1, 'Error: Length of c needs to be 1 or' + str(Naq-1) - assert len(npor) == 2 * Naq - 1, 'Error: Length of npor needs to be 1 or' + str(2*Naq-1) - c = np.hstack((1e100,c)) - else: # leaky layer on top - if len(c) == 1: c = c * np.ones(Naq) - if len(npor) == 1: npor = npor * np.ones(2 * Naq) - assert len(c) == Naq, 'Error: Length of c needs to be 1 or' + str(Naq) - assert len(npor) == 2 * Naq, 'Error: Length of npor needs to be 1 or' + str(2*Naq) + assert np.all(H >= 0), "Error: Not all layers thicknesses are non-negative" + str(H) + if top == "conf": + if len(c) == 1: + c = c * np.ones(Naq - 1) + if len(npor) == 1: + npor = npor * np.ones(2 * Naq - 1) + assert len(c) == Naq - 1, "Error: Length of c needs to be 1 or" + str(Naq - 1) + assert len(npor) == 2 * Naq - 1, "Error: Length of npor needs to be 1 or" + str( + 2 * Naq - 1 + ) + c = np.hstack((1e100, c)) + else: # leaky layer on top + if len(c) == 1: + c = c * np.ones(Naq) + if len(npor) == 1: + npor = npor * np.ones(2 * Naq) + assert len(c) == Naq, "Error: Length of c needs to be 1 or" + str(Naq) + assert len(npor) == 2 * Naq, "Error: Length of npor needs to be 1 or" + str( + 2 * Naq + ) return kaq, c, npor, ltype -def param_3d(kaq, z, kzoverkh, npor, top='conf', topres=0): + +def param_3d(kaq, z, kzoverkh, npor, top="conf", topres=0): # Computes the parameters for a ModelBase from input for a model3d model - kaq = np.atleast_1d(kaq).astype('d') - z = np.atleast_1d(z).astype('d') - kzoverkh = np.atleast_1d(kzoverkh).astype('d') - npor = np.atleast_1d(npor).astype('d') - if top == 'conf': + kaq = np.atleast_1d(kaq).astype("d") + z = np.atleast_1d(z).astype("d") + kzoverkh = np.atleast_1d(kzoverkh).astype("d") + npor = np.atleast_1d(npor).astype("d") + if top == "conf": Naq = len(z) - 1 - ltype = np.array(Naq * ['a']) - elif top == 'semi': + ltype = np.array(Naq * ["a"]) + elif top == "semi": Naq = len(z) - 1 - ltype = np.hstack(('l', Naq * ['a'])) - if len(kaq) == 1: kaq = kaq * np.ones(Naq) - assert len(kaq) == Naq, 'Error: length of kaq needs to be 1 or' + str(Naq) - if len(kzoverkh) == 1: kzoverkh = kzoverkh * np.ones(Naq) - assert len(kzoverkh) == Naq, 'Error: length of kzoverkh needs to be 1 or' + str(Naq) + ltype = np.hstack(("l", Naq * ["a"])) + if len(kaq) == 1: + kaq = kaq * np.ones(Naq) + assert len(kaq) == Naq, "Error: length of kaq needs to be 1 or" + str(Naq) + if len(kzoverkh) == 1: + kzoverkh = kzoverkh * np.ones(Naq) + assert len(kzoverkh) == Naq, "Error: length of kzoverkh needs to be 1 or" + str(Naq) if len(npor) == 1: - if top == 'conf': + if top == "conf": npor = npor * np.ones(Naq) - elif top == 'semi': + elif top == "semi": npor = npor * np.ones(Naq + 1) - if top == 'conf': - assert len(npor) == Naq, 'Error: length of npor needs to be 1 or' + str(Naq) - elif top == 'semi': - assert len(npor) == Naq + 1, 'Error: length of npor needs to be 1 or' + str(Naq + 1) + if top == "conf": + assert len(npor) == Naq, "Error: length of npor needs to be 1 or" + str(Naq) + elif top == "semi": + assert len(npor) == Naq + 1, "Error: length of npor needs to be 1 or" + str( + Naq + 1 + ) H = z[:-1] - z[1:] - assert np.all(H >= 0), 'Error: Not all layers thicknesses are non-negative' + str(H) - c = 0.5 * H[:-1] / (kzoverkh[:-1] * kaq[:-1]) + 0.5 * H[1:] / (kzoverkh[1:] * kaq[1:]) - if top == 'conf': - c = np.hstack((1e100,c)) - elif top == 'semi': + assert np.all(H >= 0), "Error: Not all layers thicknesses are non-negative" + str(H) + c = 0.5 * H[:-1] / (kzoverkh[:-1] * kaq[:-1]) + 0.5 * H[1:] / ( + kzoverkh[1:] * kaq[1:] + ) + if top == "conf": + c = np.hstack((1e100, c)) + elif top == "semi": c = np.hstack((topres + 0.5 * H[0] / (kzoverkh[0] * kaq[0]), c)) - return kaq, c, npor, ltype \ No newline at end of file + return kaq, c, npor, ltype diff --git a/timml/besselaesnumba/besselaesnumba.py b/timml/besselaesnumba/besselaesnumba.py index 9a8b2036..78997b14 100644 --- a/timml/besselaesnumba/besselaesnumba.py +++ b/timml/besselaesnumba/besselaesnumba.py @@ -101,7 +101,7 @@ def prepare_z(x, y, z1, z2): def potbeslsho(x, y, z1, z2, labda, order, ilap, naq): """ Parameters - ---------- + ---------- x,y: Point where potential is computed z1: Complex begin point of line-sink z2: Complex end point of line-sink @@ -136,7 +136,7 @@ def potbeslsho(x, y, z1, z2, labda, order, ilap, naq): pcor = pcor + z ** (power - 2 * n + 1) / (2 * n - 1) pcor = 2.0 * pcor comega = ( - z ** power * np.log((zmin1) / (zplus1)) + z**power * np.log((zmin1) / (zplus1)) + pcor - np.log(zmin1) + (-1.0) ** power * np.log(zplus1) @@ -204,7 +204,7 @@ def disbeslsho(x, y, z1, z2, labda, order, ilap, naq): cdum = 1.0 / ( order + 1 ) # Without this intermediate statement it didn't seem to work - wdis = float(order + 1) * z ** order * np.log((zmin1) / (zplus1)) + pcor + wdis = float(order + 1) * z**order * np.log((zmin1) / (zplus1)) + pcor wdis = ( wdis @@ -252,7 +252,6 @@ def disbeslsv(x, y, z1, z2, lab, order, ilap, naq): @numba.njit(nogil=True, cache=True) def potbesldho(x, y, z1, z2, labda, order, ilap, naq): - # Input: # x,y: Point where potential is computed # z1: Complex begin point of line-doublet @@ -276,7 +275,7 @@ def potbesldho(x, y, z1, z2, labda, order, ilap, naq): # Laplace line-doublet if ilap == 1: - comega = z ** order * np.log(zmin1 / zplus1) + comega = z**order * np.log(zmin1 / zplus1) qm = complex(0.0, 0.0) for n in range(1, int((order + 1) / 2) + 1): qm = qm + z ** (order - 2.0 * float(n) + 1.0) / (2.0 * float(n) - 1.0) @@ -351,7 +350,7 @@ def disbesldho(x, y, z1, z2, labda, order, ilap, naq): ) else: wdis = float(order) * z ** (order - 1) * np.log(zmin1 / zplus1) - wdis = wdis + z ** order * (1.0 / zmin1 - 1.0 / zplus1) + wdis = wdis + z**order * (1.0 / zmin1 - 1.0 / zplus1) qm = complex(0.0, 0.0) if order > 1: # To avoid a possible problem of 0 * 0^(-1) for n in range(1, int(order / 2) + 1): @@ -388,7 +387,7 @@ def disbesldho(x, y, z1, z2, labda, order, ilap, naq): wdis2 = IntegralG(zin, z1in, z2in, Lin, labda[i], order, Rconv, lstype) wdis3 = pot / (2.0 * complex(0.0, 1.0)) + wdis2 * np.imag(z) - wdis = wdis1 - 4.0 * wdis3 / (biglab ** 2 * (z2in - z1in)) + wdis = wdis1 - 4.0 * wdis3 / (biglab**2 * (z2in - z1in)) rv[0, i] = np.real(wdis) rv[1, i] = -1.0 * np.imag(wdis) return rv @@ -449,7 +448,7 @@ def IntegralF(zin, z1in, z2in, Lin, labda, order, Rconv, lstype): # Compute coefficients of delta^p for m in range(0, order + 1): - cc[m] = RBINOM[order, m] * z ** (order - m) * biglab ** order + cc[m] = RBINOM[order, m] * z ** (order - m) * biglab**order if order > 0: for n in range(0, 2 * NTERMS + order + 1): calpha[n] = complex(0.0, 0.0) @@ -552,7 +551,7 @@ def IntegralG(zin, z1in, z2in, Lin, labda, order, Rconv, lstype): # Compute coefficients of delta^p for m in range(0, order + 1): - cc[m] = RBINOM[order, m] * z ** (order - m) * biglab ** order + cc[m] = RBINOM[order, m] * z ** (order - m) * biglab**order if order > 0: for n in range(0, 2 * NTERMS + order): calpha[n] = complex(0.0, 0.0) @@ -597,7 +596,7 @@ def IntegralG(zin, z1in, z2in, Lin, labda, order, Rconv, lstype): # Compute coefficients of delta^p for m in range(0, order + 1): - cc[m] = RBINOM[order, m] * zbar ** (order - m) * biglab ** order + cc[m] = RBINOM[order, m] * zbar ** (order - m) * biglab**order if order > 0: for n in range(0, 2 * NTERMS + order): @@ -639,11 +638,11 @@ def IntegralLapLineDipole(zin, z1, z2, del0, ra, order): # We don't always have to do this, so maybe put in condition? # Determine coefficients of powers of Delta for m in range(0, order + 1): - cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra ** order + cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra**order zterm = complex(0.0, 0.0) for n in range(0, order + 1): - zterm = zterm + cg[n] * z ** n + zterm = zterm + cg[n] * z**n qmtot = complex(0.0, 0.0) for m in range(1, order + 1): @@ -666,14 +665,14 @@ def IntegralLapLineDipoleDis(zin, z1, z2, del0, ra, order): # Determine coefficients of powers of Delta for [ (Delta-Delta_0)/a ] ^ p for m in range(0, order + 1): - cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra ** order + cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra**order zterm1 = complex(0.0, 0.0) zterm2 = complex(0.0, 0.0) for n in range(1, order + 1): zterm1 = zterm1 + cg[n] * float(n) * z ** (n - 1) for n in range(0, order + 1): - zterm2 = zterm2 + cg[n] * z ** n + zterm2 = zterm2 + cg[n] * z**n qmtot = complex(0.0, 0.0) for m in range(2, order + 1): diff --git a/timml/besselaesnumba/besselaesnumba_old.py b/timml/besselaesnumba/besselaesnumba_old.py index 84838084..d458c874 100644 --- a/timml/besselaesnumba/besselaesnumba_old.py +++ b/timml/besselaesnumba/besselaesnumba_old.py @@ -13,9 +13,9 @@ def make_rbnimon(): for n in range(9): for m in range(9): if m > n: - rbinom[n, m] = 1 + rbinom[n, m] = 1 else: - rbinom[n, m] = np.prod(rrange[m + 1: n + 1]) / np.prod( + rbinom[n, m] = np.prod(rrange[m + 1 : n + 1]) / np.prod( rrange[1 : n - m + 1] ) return rbinom @@ -90,7 +90,7 @@ def prepare_z(x, y, z1, z2): def potbeslsho(x, y, z1, z2, labda, order, ilap, naq): """ Parameters - ---------- + ---------- x,y: Point where potential is computed z1: Complex begin point of line-sink z2: Complex end point of line-sink @@ -125,7 +125,7 @@ def potbeslsho(x, y, z1, z2, labda, order, ilap, naq): pcor = pcor + z ** (power - 2 * n + 1) / (2 * n - 1) pcor = 2.0 * pcor comega = ( - z ** power * np.log((zmin1) / (zplus1)) + z**power * np.log((zmin1) / (zplus1)) + pcor - np.log(zmin1) + (-1.0) ** power * np.log(zplus1) @@ -146,6 +146,7 @@ def potbeslsho(x, y, z1, z2, labda, order, ilap, naq): rv[i] = 0.0 return rv + @numba.njit def potbeslsv(x, y, z1, z2, lab, order, ilap, naq): # Check if endpoints need to be adjusted using the largest labda (the first one) @@ -192,7 +193,7 @@ def disbeslsho(x, y, z1, z2, labda, order, ilap, naq): cdum = 1.0 / ( order + 1 ) # Without this intermediate statement it didn't seem to work - wdis = float(order + 1) * z ** order * np.log((zmin1) / (zplus1)) + pcor + wdis = float(order + 1) * z**order * np.log((zmin1) / (zplus1)) + pcor wdis = ( wdis @@ -240,7 +241,6 @@ def disbeslsv(x, y, z1, z2, lab, order, ilap, naq): @numba.njit def potbesldho(x, y, z1, z2, labda, order, ilap, naq): - # Input: # x,y: Point where potential is computed # z1: Complex begin point of line-doublet @@ -264,7 +264,7 @@ def potbesldho(x, y, z1, z2, labda, order, ilap, naq): # Laplace line-doublet if ilap == 1: - comega = z ** order * np.log(zmin1 / zplus1) + comega = z**order * np.log(zmin1 / zplus1) qm = complex(0.0, 0.0) for n in range(1, int((order + 1) / 2) + 1): qm = qm + z ** (order - 2.0 * float(n) + 1.0) / (2.0 * float(n) - 1.0) @@ -339,7 +339,7 @@ def disbesldho(x, y, z1, z2, labda, order, ilap, naq): ) else: wdis = float(order) * z ** (order - 1) * np.log(zmin1 / zplus1) - wdis = wdis + z ** order * (1.0 / zmin1 - 1.0 / zplus1) + wdis = wdis + z**order * (1.0 / zmin1 - 1.0 / zplus1) qm = complex(0.0, 0.0) if order > 1: # To avoid a possible problem of 0 * 0^(-1) for n in range(1, int(order / 2) + 1): @@ -376,7 +376,7 @@ def disbesldho(x, y, z1, z2, labda, order, ilap, naq): wdis2 = IntegralG(zin, z1in, z2in, Lin, labda[i], order, Rconv, lstype) wdis3 = pot / (2.0 * complex(0.0, 1.0)) + wdis2 * np.imag(z) - wdis = wdis1 - 4.0 * wdis3 / (biglab ** 2 * (z2in - z1in)) + wdis = wdis1 - 4.0 * wdis3 / (biglab**2 * (z2in - z1in)) rv[0, i] = np.real(wdis) rv[1, i] = -1.0 * np.imag(wdis) return rv @@ -437,7 +437,7 @@ def IntegralF(zin, z1in, z2in, Lin, labda, order, Rconv, lstype): # Compute coefficients of delta^p for m in range(0, order + 1): - cc[m] = RBINOM[order, m] * z ** (order - m) * biglab ** order + cc[m] = RBINOM[order, m] * z ** (order - m) * biglab**order if order > 0: for n in range(0, 2 * NTERMS + order + 1): calpha[n] = complex(0.0, 0.0) @@ -540,7 +540,7 @@ def IntegralG(zin, z1in, z2in, Lin, labda, order, Rconv, lstype): # Compute coefficients of delta^p for m in range(0, order + 1): - cc[m] = RBINOM[order, m] * z ** (order - m) * biglab ** order + cc[m] = RBINOM[order, m] * z ** (order - m) * biglab**order if order > 0: for n in range(0, 2 * NTERMS + order): calpha[n] = complex(0.0, 0.0) @@ -585,7 +585,7 @@ def IntegralG(zin, z1in, z2in, Lin, labda, order, Rconv, lstype): # Compute coefficients of delta^p for m in range(0, order + 1): - cc[m] = RBINOM[order, m] * zbar ** (order - m) * biglab ** order + cc[m] = RBINOM[order, m] * zbar ** (order - m) * biglab**order if order > 0: for n in range(0, 2 * NTERMS + order): @@ -627,11 +627,11 @@ def IntegralLapLineDipole(zin, z1, z2, del0, ra, order): # We don't always have to do this, so maybe put in condition? # Determine coefficients of powers of Delta for m in range(0, order + 1): - cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra ** order + cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra**order zterm = complex(0.0, 0.0) for n in range(0, order + 1): - zterm = zterm + cg[n] * z ** n + zterm = zterm + cg[n] * z**n qmtot = complex(0.0, 0.0) for m in range(1, order + 1): @@ -654,14 +654,14 @@ def IntegralLapLineDipoleDis(zin, z1, z2, del0, ra, order): # Determine coefficients of powers of Delta for [ (Delta-Delta_0)/a ] ^ p for m in range(0, order + 1): - cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra ** order + cg[m] = RBINOM[order, m] * (-del0) ** (order - m) / ra**order zterm1 = complex(0.0, 0.0) zterm2 = complex(0.0, 0.0) for n in range(1, order + 1): zterm1 = zterm1 + cg[n] * float(n) * z ** (n - 1) for n in range(0, order + 1): - zterm2 = zterm2 + cg[n] * z ** n + zterm2 = zterm2 + cg[n] * z**n qmtot = complex(0.0, 0.0) for m in range(2, order + 1): diff --git a/timml/circareasink.py b/timml/circareasink.py index bfed3e38..30ae910b 100644 --- a/timml/circareasink.py +++ b/timml/circareasink.py @@ -1,9 +1,12 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np +from scipy.special import i0, i1, k0, k1 + from .element import Element -from scipy.special import k0, k1, i0, i1 -__all__ = ['CircAreaSink'] +__all__ = ["CircAreaSink"] + class CircAreaSink(Element): """ @@ -28,11 +31,14 @@ class CircAreaSink(Element): label of the well """ - - def __init__(self, model, xc=0, yc=0, R=1, N=0.001, layer=0, name='CircAreasink', label=None): + + def __init__( + self, model, xc=0, yc=0, R=1, N=0.001, layer=0, name="CircAreasink", label=None + ): self.storeinput(inspect.currentframe()) - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layer, \ - name=name, label=label) + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layer, name=name, label=label + ) self.xc = xc self.yc = yc self.R = R @@ -40,10 +46,10 @@ def __init__(self, model, xc=0, yc=0, R=1, N=0.001, layer=0, name='CircAreasink' self.model.add_element(self) def __repr__(self): - return self.name + ' at ' + str((self.xc, self.yc)) + return self.name + " at " + str((self.xc, self.yc)) def initialize(self): - self.Rsq = self.R ** 2 + self.Rsq = self.R**2 self.aq = self.model.aq.find_aquifer_data(self.xc, self.yc) self.aq.add_element(self) self.parameters = np.array([[self.N]]) @@ -52,12 +58,12 @@ def initialize(self): self.lab = self.aq.lab[1:] self.A = -self.aq.coef[self.layers, 1:] * self.R * self.lab self.B = self.aq.coef[self.layers, 1:] * self.R * self.lab - self.C = self.aq.coef[self.layers, 1:] * self.lab ** 2 + self.C = self.aq.coef[self.layers, 1:] * self.lab**2 else: self.lab = self.aq.lab self.A = -self.aq.coef[self.layers] * self.R * self.lab self.B = self.aq.coef[self.layers] * self.R * self.lab - self.C = self.aq.coef[self.layers] * self.lab ** 2 + self.C = self.aq.coef[self.layers] * self.lab**2 self.islarge = self.R / self.lab > self.Rlarge self.labsmall = self.lab[~self.islarge] self.labbig = self.lab[self.islarge] @@ -65,13 +71,14 @@ def initialize(self): self.i1Roverlab = i1(self.R / self.labsmall) def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: r = np.sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) if r <= self.R: if aq.ilap: - rv[0, 0] = 0.25 * (self.Rsq - r ** 2) + rv[0, 0] = 0.25 * (self.Rsq - r**2) rv[0, 1:] = self.A * self.K1RI0r(r) + self.C else: rv[0] = self.A * self.K1RI0r(r) + self.C @@ -84,7 +91,8 @@ def potinf(self, x, y, aq=None): return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: r = np.sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) @@ -102,8 +110,8 @@ def disvecinf(self, x, y, aq=None): rv[1, 0] = -self.A * K1RI1r * (y - self.yc) / r else: if aq.ilap: - rv[0, 0, 0] = 0.5 * self.Rsq * (x - self.xc) / r ** 2 - rv[1, 0, 0] = 0.5 * self.Rsq * (y - self.yc) / r ** 2 + rv[0, 0, 0] = 0.5 * self.Rsq * (x - self.xc) / r**2 + rv[1, 0, 0] = 0.5 * self.Rsq * (y - self.yc) / r**2 I1RK1r = self.I1RK1r(r) rv[0, 0, 1:] = self.B * I1RK1r * (x - self.xc) / (r * self.lab) rv[1, 0, 1:] = self.B * I1RK1r * (y - self.yc) / (r * self.lab) @@ -127,9 +135,12 @@ def K1RI0r(self, rin): if index.any(): r = rin / self.labbig[index] R = self.R / self.labbig[index] - rv[self.islarge * index] = np.sqrt(1 / (4 * r * R)) * np.exp(r - R) * \ - (1 + 3 / (8 * R) - 15 / (128 * R ** 2) + 315 / (3072 * R ** 3)) * \ - (1 + 1 / (8 * r) + 9 / (128 * r ** 2) + 225 / (3072 * r ** 3)) + rv[self.islarge * index] = ( + np.sqrt(1 / (4 * r * R)) + * np.exp(r - R) + * (1 + 3 / (8 * R) - 15 / (128 * R**2) + 315 / (3072 * R**3)) + * (1 + 1 / (8 * r) + 9 / (128 * r**2) + 225 / (3072 * r**3)) + ) if ~self.islarge.any(): index = (self.R - rin) / self.labsmall < 10 if index.any(): @@ -144,9 +155,12 @@ def K1RI1r(self, rin): if index.any(): r = rin / self.labbig[index] R = self.R / self.labbig[index] - rv[self.islarge * index] = np.sqrt(1 / (4 * r * R)) * np.exp(r - R) * \ - (1 + 3 / (8 * R) - 15 / (128 * R ** 2) + 315 / (3072 * R ** 3)) * \ - (1 - 3 / (8 * r) - 15 / (128 * r ** 2) - 315 / (3072 * r ** 3)) + rv[self.islarge * index] = ( + np.sqrt(1 / (4 * r * R)) + * np.exp(r - R) + * (1 + 3 / (8 * R) - 15 / (128 * R**2) + 315 / (3072 * R**3)) + * (1 - 3 / (8 * r) - 15 / (128 * r**2) - 315 / (3072 * r**3)) + ) if ~self.islarge.any(): index = (self.R - rin) / self.labsmall < 10 if index.any(): @@ -161,9 +175,12 @@ def I1RK0r(self, rin): if index.any(): r = rin / self.labbig[index] R = self.R / self.labbig[index] - rv[self.islarge * index] = np.sqrt(1 / (4 * r * R)) * np.exp(R - r) * \ - (1 - 3 / (8 * R) - 15 / (128 * R ** 2) - 315 / (3072 * R ** 3)) * \ - (1 - 1 / (8 * r) + 9 / (128 * r ** 2) - 225 / (3072 * r ** 3)) + rv[self.islarge * index] = ( + np.sqrt(1 / (4 * r * R)) + * np.exp(R - r) + * (1 - 3 / (8 * R) - 15 / (128 * R**2) - 315 / (3072 * R**3)) + * (1 - 1 / (8 * r) + 9 / (128 * r**2) - 225 / (3072 * r**3)) + ) if ~self.islarge.any(): index = (self.R - rin) / self.labsmall < 10 if index.any(): @@ -178,9 +195,12 @@ def I1RK1r(self, rin): if index.any(): r = rin / self.labbig[index] R = self.R / self.labbig[index] - rv[self.islarge * index] = np.sqrt(1 / (4 * r * R)) * np.exp(R - r) * \ - (1 - 3 / (8 * R) - 15 / (128 * R ** 2) - 315 / (3072 * R ** 3)) * \ - (1 + 3 / (8 * r) - 15 / (128 * r ** 2) + 315 / (3072 * r ** 3)) + rv[self.islarge * index] = ( + np.sqrt(1 / (4 * r * R)) + * np.exp(R - r) + * (1 - 3 / (8 * R) - 15 / (128 * R**2) - 315 / (3072 * R**3)) + * (1 + 3 / (8 * r) - 15 / (128 * r**2) + 315 / (3072 * r**3)) + ) if ~self.islarge.any(): index = (self.R - rin) / self.labsmall < 10 if index.any(): @@ -191,10 +211,14 @@ def I1RK1r(self, rin): def qztop(self, x, y, aq): rv = 0.0 if np.sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) <= self.R: - rv = -self.parameters[0, 0] # minus cause the parameter is the infiltration rate + rv = -self.parameters[ + 0, 0 + ] # minus cause the parameter is the infiltration rate return rv - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 @@ -202,19 +226,28 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst eps = 1e-8 r1sq = (xyzt1[0] - self.xc) ** 2 + (xyzt1[1] - self.yc) ** 2 r2sq = (xyzt2[0] - self.xc) ** 2 + (xyzt2[1] - self.yc) ** 2 - if (r1sq < self.Rsq and r2sq > self.Rsq ) or (r1sq > self.Rsq and r2sq < self.Rsq): + if (r1sq < self.Rsq and r2sq > self.Rsq) or ( + r1sq > self.Rsq and r2sq < self.Rsq + ): changed = True x1, y1 = xyzt1[0:2] x2, y2 = xyzt2[0:2] a = (x2 - x1) ** 2 + (y2 - y1) ** 2 b = 2 * ((x2 - x1) * (x1 - self.xc) + (y2 - y1) * (y1 - self.yc)) - c = self.xc ** 2 + self.yc ** 2 + x1 ** 2 + y1 ** 2 - 2 * (self.xc * x1 +self.yc * y1) - self.Rsq - u1 = (-b - np.sqrt(b ** 2 - 4 * a * c)) / (2 * a) - u2 = (-b + np.sqrt(b ** 2 - 4 * a * c)) / (2 * a) + c = ( + self.xc**2 + + self.yc**2 + + x1**2 + + y1**2 + - 2 * (self.xc * x1 + self.yc * y1) + - self.Rsq + ) + u1 = (-b - np.sqrt(b**2 - 4 * a * c)) / (2 * a) + u2 = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a) if u1 > 0: - u = u1 * (1.0 + eps) # Go just beyond circle + u = u1 * (1.0 + eps) # Go just beyond circle else: - u = u2 * (1.0 + eps) # Go just beyond circle + u = u2 * (1.0 + eps) # Go just beyond circle xn = x1 + u * (x2 - x1) yn = y1 + u * (y2 - y1) zn = xyzt1[2] + u * (xyzt2[2] - xyzt1[2]) diff --git a/timml/circinhom.py b/timml/circinhom.py index d113181b..df6f74f2 100644 --- a/timml/circinhom.py +++ b/timml/circinhom.py @@ -1,9 +1,9 @@ -''' +""" mlcircinhom.py contains the CircleInhom class This file is part of the TimML library and is distributed under the GNU LPGL. See the TimML.py file for more details. (c) Mark Bakker, 2002-2007 -''' +""" import scipy.special from element import * @@ -11,10 +11,11 @@ class CircleInhom(Element): - '''CircleInhom class + """CircleInhom class Note that aquiferparent doesn't have a meaning for this element All attributes from element. - ''' + """ + Rconvsq = 7 * 7 def __init__(self, modelParent, order, aqin, aqout, label=None): @@ -22,22 +23,29 @@ def __init__(self, modelParent, order, aqin, aqout, label=None): self.order = order self.aqin = aqin self.aqout = aqout - assert aqin.Naquifers == aqout.Naquifers, "TimML Input error: Number of aquifers inside and outside must be equal" + assert ( + aqin.Naquifers == aqout.Naquifers + ), "TimML Input error: Number of aquifers inside and outside must be equal" self.label = label - self.type = 'circleinhom' + self.type = "circleinhom" self.setCoefs() self.modelParent.addElement(self) def __repr__(self): - return 'CircInhom xc,yc,order ' + str((self.xc, self.yc, self.order)) + ' with inside aquifer data ' + str(self.aqin) + return ( + "CircInhom xc,yc,order " + + str((self.xc, self.yc, self.order)) + + " with inside aquifer data " + + str(self.aqin) + ) def setCoefs(self): self.xc = self.aqin.xc self.yc = self.aqin.yc self.R = self.aqin.R self.Rsq = self.aqin.Rsq - self.paramin = zeros((2 * self.order + 1, self.aqin.Naquifers), 'd') - self.paramout = zeros((2 * self.order + 1, self.aqin.Naquifers), 'd') + self.paramin = zeros((2 * self.order + 1, self.aqin.Naquifers), "d") + self.paramout = zeros((2 * self.order + 1, self.aqin.Naquifers), "d") self.Nparamin = (2 * self.order + 1) * self.aqin.Naquifers self.Nparamout = self.Nparamin # Compute control points @@ -47,74 +55,71 @@ def setCoefs(self): self.ycp = self.yc + self.R * sin(self.thetacp) # Compute values on the edge (to scale functions) # values on inside edge - self.matRin = zeros((self.order + 1, self.aqin.Naquifers), 'd') + self.matRin = zeros((self.order + 1, self.aqin.Naquifers), "d") rolab = self.R / self.aqin.lab # vector with all R/labin values if self.aqin.type == self.aqin.conf: for p in range(self.order + 1): self.matRin[p, 0] = self.R**p # first value in row is R**p self.matRin[p, 1:] = scipy.special.iv( - p, rolab) # other values are Ip(R/lab) + p, rolab + ) # other values are Ip(R/lab) elif self.aqin.type == self.aqin.semi: for p in range(self.order + 1): self.matRin[p, :] = scipy.special.iv( - p, rolab) # all values are Ip(R/lab) + p, rolab + ) # all values are Ip(R/lab) self.matRin = 1.0 / self.matRin # values on outside edge - self.matRout = zeros((self.order + 1, self.aqout.Naquifers), 'd') + self.matRout = zeros((self.order + 1, self.aqout.Naquifers), "d") rolab = self.R / self.aqout.lab # vector with all R/labout values if self.aqout.type == self.aqin.conf: for p in range(self.order + 1): # first value in row is 1/r**p - self.matRout[p, 0] = 1. / self.R**(p) - self.matRout[p, 1:] = scipy.special.kn( - p, rolab) # other values are Kp + self.matRout[p, 0] = 1.0 / self.R ** (p) + self.matRout[p, 1:] = scipy.special.kn(p, rolab) # other values are Kp # first term is logarithm, so scale by log(self.R+1)to make sure that self.R can be 1 self.matRout[0, 0] = log(self.R + 1.0) / (2.0 * pi) elif self.aqout.type == self.aqout.semi: for p in range(self.order + 1): - self.matRout[p, :] = scipy.special.kn( - p, rolab) # other values are Kp + self.matRout[p, :] = scipy.special.kn(p, rolab) # other values are Kp self.matRout = 1.0 / self.matRout def potentialInfluence(self, aq, x, y): - r = sqrt((x - self.xc)**2 + (y - self.yc)**2) + r = sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) theta = arctan2((y - self.yc), (x - self.xc)) - mat = zeros((self.order + 1, aq.Naquifers), - 'd') # matrix to store values - # Inside Cylinder + mat = zeros((self.order + 1, aq.Naquifers), "d") # matrix to store values + # Inside Cylinder if aq == self.aqin: rolab = r / aq.lab # vector with all r/lab values if aq.type == aq.conf: # Confined aquifer for p in range(self.order + 1): mat[p, 0] = r**p # first value in row is r**p - mat[p, 1:] = scipy.special.iv( - p, rolab) # other values are Ip + mat[p, 1:] = scipy.special.iv(p, rolab) # other values are Ip elif aq.type == aq.semi: # Semi-confined aquifer for p in range(self.order + 1): mat[p, :] = scipy.special.iv(p, rolab) # all values are Ip mat = mat * self.matRin - # In aquifer outside cylinder + # In aquifer outside cylinder elif aq == self.aqout: rolab = r / aq.lab # vector with all r/lab values if aq.type == aq.conf: # Confined aquifer for p in range(self.order + 1): - mat[p, 0] = 1. / r**(p) # first value in row is 1/r**p - mat[p, 1:] = scipy.special.kn( - p, rolab) # other values are Kp + mat[p, 0] = 1.0 / r ** (p) # first value in row is 1/r**p + mat[p, 1:] = scipy.special.kn(p, rolab) # other values are Kp mat[0, 0] = log(r) / (2.0 * pi) # logarithm on outside if aq.type == aq.semi: # Semi-confined aquifer for p in range(self.order + 1): mat[p, :] = scipy.special.kn(p, rolab) # all values are Kp mat = mat * self.matRout - # Somewhere else, assume outside + # Somewhere else, assume outside else: if self.aqout.type == self.aqout.conf and aq.type == aq.conf: for p in range(self.order + 1): - mat[p, 0] = 1. / r**(p) # first value in row is 1/r**p + mat[p, 0] = 1.0 / r ** (p) # first value in row is 1/r**p mat[0, 0] = log(r) / (2.0 * pi) mat = mat * self.matRout - # Store values in return value - rv = zeros((2 * self.order + 1, aq.Naquifers), 'd') + # Store values in return value + rv = zeros((2 * self.order + 1, aq.Naquifers), "d") rv[0, :] = mat[0, :] # First row only has cosine part; sin(0)=0 for p in range(1, self.order + 1): rv[2 * p - 1, :] = mat[p, :] * cos(p * theta) @@ -122,47 +127,47 @@ def potentialInfluence(self, aq, x, y): return rv def potentialInfluenceInLayer(self, aq, pylayer, x, y): - '''Returns PotentialInfluence function in aquifer aq in pylayer as array (1 value per parameter) + """Returns PotentialInfluence function in aquifer aq in pylayer as array (1 value per parameter) Needs to be overloaded because there is no parameter outside the functions - Needs to be modified for inside and outside''' + Needs to be modified for inside and outside""" potInf = self.potentialInfluence(aq, x, y) - rv = zeros(0, 'd') + rv = zeros(0, "d") for p in potInf: rv = hstack((rv, p * aq.eigvec[pylayer, :])) if aq == self.aqin: - rv = hstack((rv, zeros(self.Nparamout, 'd'))) + rv = hstack((rv, zeros(self.Nparamout, "d"))) else: - rv = hstack((zeros(self.Nparamin, 'd'), rv)) + rv = hstack((zeros(self.Nparamin, "d"), rv)) return rv def potentialInfluenceAllLayers(self, aq, pylayer, x, y): - '''Returns PotentialInfluence function in aquifer aq in all layers as an array''' + """Returns PotentialInfluence function in aquifer aq in all layers as an array""" potInf = self.potentialInfluence(aq, x, y) - rv = zeros((aq.Naquifers, 0), 'd') + rv = zeros((aq.Naquifers, 0), "d") for p in potInf: rv = hstack((rv, p * aq.eigvec)) if aq == self.aqin: - rv = hstack((rv, zeros((aq.Naquifers, self.Nparamout), 'd'))) + rv = hstack((rv, zeros((aq.Naquifers, self.Nparamout), "d"))) else: - rv = hstack((zeros((aq.Naquifers, self.Nparamin), 'd'), rv)) + rv = hstack((zeros((aq.Naquifers, self.Nparamin), "d"), rv)) return rv def potentialInfluenceSpecLayers(self, aq, pylayer, x, y): - '''Returns PotentialInfluence function in aquifer aq in all layers as an array''' + """Returns PotentialInfluence function in aquifer aq in all layers as an array""" potInf = self.potentialInfluence(aq, x, y) pylen = len(pylayer) - rv = zeros((pylen, 0), 'd') + rv = zeros((pylen, 0), "d") eigvec = take(aq.eigvec, pylayer, 0) for p in potInf: rv = hstack((rv, p * eigvec)) if aq == self.aqin: - rv = hstack((rv, zeros((pylen, self.Nparamout), 'd'))) + rv = hstack((rv, zeros((pylen, self.Nparamout), "d"))) else: - rv = hstack((zeros((pylen, self.Nparamin), 'd'), rv)) + rv = hstack((zeros((pylen, self.Nparamin), "d"), rv)) return rv def potentialContribution(self, aq, x, y): - '''Returns array of potentialContribution. Needs to be overloaded cause there is inside and outside''' + """Returns array of potentialContribution. Needs to be overloaded cause there is inside and outside""" if aq == self.aqin: potInf = sum(self.paramin * self.potentialInfluence(aq, x, y), 0) else: @@ -170,10 +175,9 @@ def potentialContribution(self, aq, x, y): return potInf def dischargeInfluence(self, aq, x, y): - r = sqrt((x - self.xc)**2 + (y - self.yc)**2) + r = sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) theta = arctan2((y - self.yc), (x - self.xc)) - mat = zeros((self.order + 1, aq.Naquifers), - 'd') # matrix to store values + mat = zeros((self.order + 1, aq.Naquifers), "d") # matrix to store values if aq == self.aqin: # Inside cylinder rolab = r / aq.lab # vector with all r/lab values if aq.type == aq.conf: # Confined aquifer @@ -182,49 +186,52 @@ def dischargeInfluence(self, aq, x, y): mat[0, 0] = 0.0 else: # first value in row is pr**(p-1) - mat[p, 0] = - float(p) * r**(p - 1) - mat[p, 1:] = - (scipy.special.iv(p - 1, rolab) + - scipy.special.iv(p + 1, rolab)) / (2 * aq.lab) + mat[p, 0] = -float(p) * r ** (p - 1) + mat[p, 1:] = -( + scipy.special.iv(p - 1, rolab) + scipy.special.iv(p + 1, rolab) + ) / (2 * aq.lab) elif aq.type == aq.semi: for p in range(self.order + 1): - mat[p, :] = - (scipy.special.iv(p - 1, rolab) + - scipy.special.iv(p + 1, rolab)) / (2 * aq.lab) + mat[p, :] = -( + scipy.special.iv(p - 1, rolab) + scipy.special.iv(p + 1, rolab) + ) / (2 * aq.lab) mat = mat * self.matRin elif aq == self.aqout: # In aquifer outside cylinder rolab = r / aq.lab # vector with all r/lab values if aq.type == aq.conf: for p in range(self.order + 1): - mat[p, 0] = p / r**(p + 1) # first value in row is 1/r**p - mat[p, 1:] = (scipy.special.kn(p - 1, rolab) + - scipy.special.kn(p + 1, rolab)) / (2 * aq.lab) - mat[0, 0] = - 1.0 / (2.0 * pi * r) # log + mat[p, 0] = p / r ** (p + 1) # first value in row is 1/r**p + mat[p, 1:] = ( + scipy.special.kn(p - 1, rolab) + scipy.special.kn(p + 1, rolab) + ) / (2 * aq.lab) + mat[0, 0] = -1.0 / (2.0 * pi * r) # log elif aq.type == aq.semi: for p in range(self.order + 1): - mat[p, :] = (scipy.special.kn(p - 1, rolab) + - scipy.special.kn(p + 1, rolab)) / (2 * aq.lab) + mat[p, :] = ( + scipy.special.kn(p - 1, rolab) + scipy.special.kn(p + 1, rolab) + ) / (2 * aq.lab) mat = mat * self.matRout else: # Somewhere else if self.aqout.type == self.aqout.conf and aq.type == aq.conf: - mat[0, 0] = - 1.0 / (2.0 * pi * r) + mat[0, 0] = -1.0 / (2.0 * pi * r) for p in range(1, self.order + 1): - mat[p, 0] = p / r**(p + 1) # first value in row is 1/r**p + mat[p, 0] = p / r ** (p + 1) # first value in row is 1/r**p mat = mat * self.matRout # Store values in return value - rvrad = zeros((2 * self.order + 1, aq.Naquifers), 'd') + rvrad = zeros((2 * self.order + 1, aq.Naquifers), "d") rvrad[0, :] = mat[0, :] # First row only has cosine part; sin(0)=0 for p in range(1, self.order + 1): rvrad[2 * p - 1, :] = mat[p, :] * cos(p * theta) rvrad[2 * p, :] = mat[p, :] * sin(p * theta) - # Tangential part - mat = zeros((self.order + 1, aq.Naquifers), - 'd') # matrix to store values + # Tangential part + mat = zeros((self.order + 1, aq.Naquifers), "d") # matrix to store values if aq == self.aqin: # Inside cylinder rolab = r / aq.lab # vector with all r/lab values if aq.type == aq.conf: # all values for p=0 are zero (no dependence on theta) for p in range(1, self.order + 1): # first value in row is pr**(p-1) - mat[p, 0] = float(p) * r**(p - 1) + mat[p, 0] = float(p) * r ** (p - 1) mat[p, 1:] = float(p) * scipy.special.iv(p, rolab) / r elif aq.type == aq.semi: # all values for p=0 are zero (no dependence on theta) @@ -237,7 +244,7 @@ def dischargeInfluence(self, aq, x, y): # all values for p=0 are zero (no dependence on theta) for p in range(1, self.order + 1): # first value in row is 1/r**p - mat[p, 0] = float(p) / r**(p + 1) + mat[p, 0] = float(p) / r ** (p + 1) mat[p, 1:] = float(p) * scipy.special.kn(p, rolab) / r elif aq.type == aq.semi: # all values for p=0 are zero (no dependence on theta) @@ -247,22 +254,21 @@ def dischargeInfluence(self, aq, x, y): else: # Somewhere else if self.aqout.type == self.aqout.conf and aq.type == aq.conf: for p in range(1, self.order + 1): - mat[p, 0] = float(p) / r**(p + 1) + mat[p, 0] = float(p) / r ** (p + 1) mat = mat * self.matRout # Store values in return value - rvtan = zeros((2 * self.order + 1, aq.Naquifers), 'd') + rvtan = zeros((2 * self.order + 1, aq.Naquifers), "d") for p in range(1, self.order + 1): rvtan[2 * p - 1, :] = mat[p, :] * sin(p * theta) - rvtan[2 * p, :] = - mat[p, :] * cos(p * theta) + rvtan[2 * p, :] = -mat[p, :] * cos(p * theta) qx = rvrad * cos(theta) - rvtan * sin(theta) qy = rvrad * sin(theta) + rvtan * cos(theta) return [qx, qy] def dischargeInfluenceRad(self, aq, x, y): - r = sqrt((x - self.xc)**2 + (y - self.yc)**2) + r = sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) theta = arctan2((y - self.yc), (x - self.xc)) - mat = zeros((self.order + 1, aq.Naquifers), - 'd') # matrix to store values + mat = zeros((self.order + 1, aq.Naquifers), "d") # matrix to store values if aq == self.aqin: # Inside cylinder rolab = r / aq.lab # vector with all r/lab values for p in range(self.order + 1): @@ -270,25 +276,27 @@ def dischargeInfluenceRad(self, aq, x, y): mat[0, 0] = 0.0 else: # first value in row is pr**(p-1) - mat[p, 0] = - float(p) * r**(p - 1) - mat[p, 1:] = - (scipy.special.iv(p - 1, rolab) + - scipy.special.iv(p + 1, rolab)) / (2 * aq.lab) + mat[p, 0] = -float(p) * r ** (p - 1) + mat[p, 1:] = -( + scipy.special.iv(p - 1, rolab) + scipy.special.iv(p + 1, rolab) + ) / (2 * aq.lab) mat = mat * self.matRin elif aq == self.aqout: # In aquifer outside cylinder rolab = r / aq.lab # vector with all r/lab values for p in range(self.order + 1): - mat[p, 0] = p / r**(p + 1) # first value in row is 1/r**p - mat[p, 1:] = (scipy.special.kn(p - 1, rolab) + - scipy.special.kn(p + 1, rolab)) / (2 * aq.lab) + mat[p, 0] = p / r ** (p + 1) # first value in row is 1/r**p + mat[p, 1:] = ( + scipy.special.kn(p - 1, rolab) + scipy.special.kn(p + 1, rolab) + ) / (2 * aq.lab) mat[0, 0] = 0.0 # no constant on outside mat = mat * self.matRout else: # Somewhere else for p in range(self.order + 1): - mat[p, 0] = p / r**(p + 1) # first value in row is 1/r**p + mat[p, 0] = p / r ** (p + 1) # first value in row is 1/r**p mat[0, 0] = 0.0 mat = mat * self.matRout # Store values in return value - rvrad = zeros((2 * self.order + 1, aq.Naquifers), 'd') + rvrad = zeros((2 * self.order + 1, aq.Naquifers), "d") rvrad[0, :] = mat[0, :] # First row only has cosine part; sin(0)=0 for p in range(1, self.order + 1): rvrad[2 * p - 1, :] = mat[p, :] * cos(p * theta) @@ -296,9 +304,9 @@ def dischargeInfluenceRad(self, aq, x, y): return rvrad def dischargeInfluenceRadInLayer(self, aq, pylayer, x, y): - '''Returns dischargeInfluenceRadInLayer function in aquifer aq in pylayer as list (1 value per parameter) + """Returns dischargeInfluenceRadInLayer function in aquifer aq in pylayer as list (1 value per parameter) Needs to be overloaded because there is no parameter outside the functions - Needs to be modified for inside and outside''' + Needs to be modified for inside and outside""" disInf = self.dischargeInfluenceRad(aq, x, y) rv = [] for d in disInf: @@ -308,11 +316,11 @@ def dischargeInfluenceRadInLayer(self, aq, pylayer, x, y): return rv def dischargeInfluenceRadAllLayers(self, aq, dumlayer, x, y): - '''Returns dischargeInfluenceRadAllLayers function in aquifer aq as an array + """Returns dischargeInfluenceRadAllLayers function in aquifer aq as an array Needs to be overloaded because there is no parameter outside the functions - Needs to be modified for inside and outside''' + Needs to be modified for inside and outside""" disInf = self.dischargeInfluenceRad(aq, x, y) - rv = zeros((aq.Naquifers, 0), 'd') + rv = zeros((aq.Naquifers, 0), "d") for d in disInf: rv = hstack((rv, d * aq.eigvec)) if aq != self.aqin: @@ -320,60 +328,60 @@ def dischargeInfluenceRadAllLayers(self, aq, dumlayer, x, y): return rv def dischargeInfluenceAllLayers(self, aq, dumlayer, x, y): - '''Returns dischargeInfluenceAllLayers function in aquifer aq as an array + """Returns dischargeInfluenceAllLayers function in aquifer aq as an array Needs to be overloaded because there is no parameter outside the functions - Needs to be modified for inside and outside''' + Needs to be modified for inside and outside""" [disx, disy] = self.dischargeInfluence(aq, x, y) - rvx = zeros((aq.Naquifers, 0), 'd') - rvy = zeros((aq.Naquifers, 0), 'd') + rvx = zeros((aq.Naquifers, 0), "d") + rvy = zeros((aq.Naquifers, 0), "d") for d in disx: rvx = hstack((rvx, d * aq.eigvec)) for d in disy: rvy = hstack((rvy, d * aq.eigvec)) if aq == self.aqin: - rvx = hstack((rvx, zeros((aq.Naquifers, self.Nparamout), 'd'))) - rvy = hstack((rvy, zeros((aq.Naquifers, self.Nparamout), 'd'))) + rvx = hstack((rvx, zeros((aq.Naquifers, self.Nparamout), "d"))) + rvy = hstack((rvy, zeros((aq.Naquifers, self.Nparamout), "d"))) else: - rvx = hstack((zeros((aq.Naquifers, self.Nparamin), 'd'), rvx)) - rvy = hstack((zeros((aq.Naquifers, self.Nparamin), 'd'), rvy)) + rvx = hstack((zeros((aq.Naquifers, self.Nparamin), "d"), rvx)) + rvy = hstack((zeros((aq.Naquifers, self.Nparamin), "d"), rvy)) return [rvx, rvy] def dischargeInfluenceInLayer(self, aq, pylayer, x, y): - '''Returns dischargeInfluence in pylayer, modified for paramin and paramout''' + """Returns dischargeInfluence in pylayer, modified for paramin and paramout""" [disx, disy] = self.dischargeInfluence(aq, x, y) rvx = disx * aq.eigvec[pylayer, :] rvy = disy * aq.eigvec[pylayer, :] if aq == self.aqin: - rvx = hstack((rvx.ravel(), zeros(self.Nparamout, 'd'))) - rvy = hstack((rvy.ravel(), zeros(self.Nparamout, 'd'))) + rvx = hstack((rvx.ravel(), zeros(self.Nparamout, "d"))) + rvy = hstack((rvy.ravel(), zeros(self.Nparamout, "d"))) else: - rvx = hstack((zeros(self.Nparamin, 'd'), rvx.ravel())) - rvy = hstack((zeros(self.Nparamin, 'd'), rvy.ravel())) + rvx = hstack((zeros(self.Nparamin, "d"), rvx.ravel())) + rvy = hstack((zeros(self.Nparamin, "d"), rvy.ravel())) return [rvx, rvy] def dischargeInfluenceSpecLayers(self, aq, pylayer, x, y): - '''Returns dischargeInfluenceAllLayers function in aquifer aq as an array + """Returns dischargeInfluenceAllLayers function in aquifer aq as an array Needs to be overloaded because there is no parameter outside the functions - Needs to be modified for inside and outside''' + Needs to be modified for inside and outside""" [disx, disy] = self.dischargeInfluence(aq, x, y) pylen = len(pylayer) - rvx = zeros((pylen, 0), 'd') - rvy = zeros((pylen, 0), 'd') + rvx = zeros((pylen, 0), "d") + rvy = zeros((pylen, 0), "d") eigvec = take(aq.eigvec, pylayer, 0) for d in disx: rvx = hstack((rvx, d * eigvec)) for d in disy: rvy = hstack((rvy, d * eigvec)) if aq == self.aqin: - rvx = hstack((rvx, zeros((pylen, self.Nparamout), 'd'))) - rvy = hstack((rvy, zeros((pylen, self.Nparamout), 'd'))) + rvx = hstack((rvx, zeros((pylen, self.Nparamout), "d"))) + rvy = hstack((rvy, zeros((pylen, self.Nparamout), "d"))) else: - rvx = hstack((zeros((pylen, self.Nparamin), 'd'), rvx)) - rvy = hstack((zeros((pylen, self.Nparamin), 'd'), rvy)) + rvx = hstack((zeros((pylen, self.Nparamin), "d"), rvx)) + rvy = hstack((zeros((pylen, self.Nparamin), "d"), rvy)) return [rvx, rvy] def dischargeContribution(self, aq, x, y): - '''Returns matrix with two rowvectors of dischargeContributions Qx and Qy. Needs to be overloaded cause there is inside and outside''' + """Returns matrix with two rowvectors of dischargeContributions Qx and Qy. Needs to be overloaded cause there is inside and outside""" disInf = self.dischargeInfluence(aq, x, y) if aq == self.aqin: disxInf = sum(self.paramin * disInf[0], 0) @@ -384,53 +392,103 @@ def dischargeContribution(self, aq, x, y): return array([disxInf, disyInf]) def zeroFunction(self, aqdum, ldum, xdum, ydum): - '''Returns list of zeros of length number of parameters''' - return list(zeros(self.Nparamin + self.Nparamout, 'd')) + """Returns list of zeros of length number of parameters""" + return list(zeros(self.Nparamin + self.Nparamout, "d")) def getMatrixRows(self, elementList): rows = [] # Jump in potential for i in range(self.Ncp): # Hardcoded for same number of aquifers in and out - rowin = zeros((self.aqin.Naquifers, 0), 'd') - rowout = zeros((self.aqin.Naquifers, 0), 'd') # Zero columns! + rowin = zeros((self.aqin.Naquifers, 0), "d") + rowout = zeros((self.aqin.Naquifers, 0), "d") # Zero columns! for e in elementList: - rowpart = e.getMatrixCoefficients(self.aqin, self.ldum, self.xcp[i], self.ycp[i], - lambda el, aq, ldum, x, y: el.potentialInfluenceAllLayers(aq, ldum, x, y)) + rowpart = e.getMatrixCoefficients( + self.aqin, + self.ldum, + self.xcp[i], + self.ycp[i], + lambda el, aq, ldum, x, y: el.potentialInfluenceAllLayers( + aq, ldum, x, y + ), + ) if size(rowpart) > 0: rowin = hstack((rowin, rowpart)) for e in elementList: - rowpart = e.getMatrixCoefficients(self.aqout, self.ldum, self.xcp[i], self.ycp[i], - lambda el, aq, ldum, x, y: el.potentialInfluenceAllLayers(aq, ldum, x, y)) + rowpart = e.getMatrixCoefficients( + self.aqout, + self.ldum, + self.xcp[i], + self.ycp[i], + lambda el, aq, ldum, x, y: el.potentialInfluenceAllLayers( + aq, ldum, x, y + ), + ) if size(rowpart) > 0: rowout = hstack((rowout, rowpart)) row = self.aqout.Tcol * rowin - self.aqin.Tcol * rowout - row = hstack((row, - self.aqin.Tcol * self.aqout.Tcol * (self.aqout.hstar - self.aqin.hstar) + - self.aqin.Tcol * self.modelParent.potentialVectorCol(self.xcp[i], self.ycp[i], self.aqout) - - self.aqout.Tcol * self.modelParent.potentialVectorCol(self.xcp[i], self.ycp[i], self.aqin))) + row = hstack( + ( + row, + self.aqin.Tcol + * self.aqout.Tcol + * (self.aqout.hstar - self.aqin.hstar) + + self.aqin.Tcol + * self.modelParent.potentialVectorCol( + self.xcp[i], self.ycp[i], self.aqout + ) + - self.aqout.Tcol + * self.modelParent.potentialVectorCol( + self.xcp[i], self.ycp[i], self.aqin + ), + ) + ) rows = rows + row.tolist() # Jump in radial discharge for i in range(self.Ncp): # Hardcoded for same number of aquifers in and out - rowin = zeros((self.aqin.Naquifers, 0), 'd') - rowout = zeros((self.aqin.Naquifers, 0), 'd') # Zero columns! + rowin = zeros((self.aqin.Naquifers, 0), "d") + rowout = zeros((self.aqin.Naquifers, 0), "d") # Zero columns! for e in elementList: - rowqxqy = e.getMatrixCoefficients(self.aqin, self.ldum, self.xcp[i], self.ycp[i], - lambda el, aq, ldum, x, y: el.dischargeInfluenceAllLayers(aq, ldum, x, y)) + rowqxqy = e.getMatrixCoefficients( + self.aqin, + self.ldum, + self.xcp[i], + self.ycp[i], + lambda el, aq, ldum, x, y: el.dischargeInfluenceAllLayers( + aq, ldum, x, y + ), + ) if size(rowqxqy) > 0: - rowpart = rowqxqy[0] * cos(self.thetacp[i]) + \ - rowqxqy[1] * sin(self.thetacp[i]) + rowpart = rowqxqy[0] * cos(self.thetacp[i]) + rowqxqy[1] * sin( + self.thetacp[i] + ) rowin = hstack((rowin, rowpart)) for e in elementList: - rowqxqy = e.getMatrixCoefficients(self.aqout, self.ldum, self.xcp[i], self.ycp[i], - lambda el, aq, ldum, x, y: el.dischargeInfluenceAllLayers(aq, ldum, x, y)) + rowqxqy = e.getMatrixCoefficients( + self.aqout, + self.ldum, + self.xcp[i], + self.ycp[i], + lambda el, aq, ldum, x, y: el.dischargeInfluenceAllLayers( + aq, ldum, x, y + ), + ) if size(rowqxqy) > 0: - rowpart = rowqxqy[0] * cos(self.thetacp[i]) + \ - rowqxqy[1] * sin(self.thetacp[i]) + rowpart = rowqxqy[0] * cos(self.thetacp[i]) + rowqxqy[1] * sin( + self.thetacp[i] + ) rowout = hstack((rowout, rowpart)) row = rowin - rowout - row = hstack((row, - self.modelParent.dischargeNormVectorCol(self.xcp[i], self.ycp[i], self.thetacp[i], self.aqout) - - self.modelParent.dischargeNormVectorCol(self.xcp[i], self.ycp[i], self.thetacp[i], self.aqin))) + row = hstack( + ( + row, + self.modelParent.dischargeNormVectorCol( + self.xcp[i], self.ycp[i], self.thetacp[i], self.aqout + ) + - self.modelParent.dischargeNormVectorCol( + self.xcp[i], self.ycp[i], self.thetacp[i], self.aqin + ), + ) + ) rows = rows + row.tolist() return rows @@ -438,23 +496,45 @@ def getMatrixCoefficients(self, aq, pylayer, x, y, func): return func(self, aq, pylayer, x, y) def takeParameters(self, xsol, icount): - par = xsol[icount: icount + self.Nparamin] - self.paramin = self.paramin + \ - reshape(par, (2 * self.order + 1, self.aqin.Naquifers)) + par = xsol[icount : icount + self.Nparamin] + self.paramin = self.paramin + reshape( + par, (2 * self.order + 1, self.aqin.Naquifers) + ) icount = icount + self.Nparamin - par = xsol[icount: icount + self.Nparamout] - self.paramout = self.paramout + \ - reshape(par, (2 * self.order + 1, self.aqin.Naquifers)) + par = xsol[icount : icount + self.Nparamout] + self.paramout = self.paramout + reshape( + par, (2 * self.order + 1, self.aqin.Naquifers) + ) icount = icount + self.Nparamout return icount def check(self): for i in range(self.Ncp): - print('Control point ' + str(i)) - print('head inside: ' + str(self.modelParent.headVector(self.xcp[i], self.ycp[i], self.aqin))) - print('head outside: ' + str(self.modelParent.headVector(self.xcp[i], self.ycp[i], self.aqout))) - print('Qrad inside: ' + str(self.modelParent.dischargeNormVector(self.xcp[i], self.ycp[i], self.thetacp[i], self.aqin))) - print('Qrad outside: ' + str(self.modelParent.dischargeNormVector(self.xcp[i], self.ycp[i], self.thetacp[i], self.aqout))) + print("Control point " + str(i)) + print( + "head inside: " + + str(self.modelParent.headVector(self.xcp[i], self.ycp[i], self.aqin)) + ) + print( + "head outside: " + + str(self.modelParent.headVector(self.xcp[i], self.ycp[i], self.aqout)) + ) + print( + "Qrad inside: " + + str( + self.modelParent.dischargeNormVector( + self.xcp[i], self.ycp[i], self.thetacp[i], self.aqin + ) + ) + ) + print( + "Qrad outside: " + + str( + self.modelParent.dischargeNormVector( + self.xcp[i], self.ycp[i], self.thetacp[i], self.aqout + ) + ) + ) def layout(self): return [0] @@ -465,16 +545,24 @@ def parSum(self): def nearElement(self, pyLayer, xyz1, xyz2, step, idir): changed = 0 stop = 0 - xyznew = zeros(3, 'd') - r1sq = (xyz1[0] - self.xc)**2 + (xyz1[1] - self.yc) ** 2 - r2sq = (xyz2[0] - self.xc)**2 + (xyz2[1] - self.yc) ** 2 - if (r1sq < self.Rsq and r2sq > self.Rsq) or (r1sq > self.Rsq and r2sq < self.Rsq): + xyznew = zeros(3, "d") + r1sq = (xyz1[0] - self.xc) ** 2 + (xyz1[1] - self.yc) ** 2 + r2sq = (xyz2[0] - self.xc) ** 2 + (xyz2[1] - self.yc) ** 2 + if (r1sq < self.Rsq and r2sq > self.Rsq) or ( + r1sq > self.Rsq and r2sq < self.Rsq + ): (x1, y1) = xyz1[0:2] (x2, y2) = xyz2[0:2] - a = (x2 - x1)**2 + (y2 - y1)**2 + a = (x2 - x1) ** 2 + (y2 - y1) ** 2 b = 2.0 * ((x2 - x1) * (x1 - self.xc) + (y2 - y1) * (y1 - self.yc)) - c = self.xc**2 + self.yc**2 + x1**2 + y1**2 - \ - 2.0 * (self.xc * x1 + self.yc * y1) - self.Rsq + c = ( + self.xc**2 + + self.yc**2 + + x1**2 + + y1**2 + - 2.0 * (self.xc * x1 + self.yc * y1) + - self.Rsq + ) u1 = (-b - sqrt(b**2 - 4.0 * a * c)) / (2.0 * a) u2 = (-b + sqrt(b**2 - 4.0 * a * c)) / (2.0 * a) if u1 > 0: @@ -484,12 +572,12 @@ def nearElement(self, pyLayer, xyz1, xyz2, step, idir): xn = x1 + u * (x2 - x1) yn = y1 + u * (y2 - y1) zn = xyz1[2] + u * (xyz2[2] - xyz1[2]) - xyznew = array([xn, yn, zn], 'd') + xyznew = array([xn, yn, zn], "d") changed = 1 return [changed, stop, xyznew] def distanceSquaredToElement(self, x, y): - '''Returns distance squared to element. Used for deciding tracing step''' - dis = sqrt((x - self.xc)**2 + (y - self.yc) ** 2) + """Returns distance squared to element. Used for deciding tracing step""" + dis = sqrt((x - self.xc) ** 2 + (y - self.yc) ** 2) dissq = (dis - self.R) ** 2 return dissq diff --git a/timml/constant.py b/timml/constant.py index f76a9f12..561d072f 100644 --- a/timml/constant.py +++ b/timml/constant.py @@ -1,15 +1,28 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np + from .element import Element from .equation import PotentialEquation -__all__ = ['Constant', 'ConstantStar'] +__all__ = ["Constant", "ConstantStar"] + class ConstantBase(Element, PotentialEquation): - def __init__(self, model, xr=0, yr=0, hr=0.0, layer=0, \ - name='ConstantBase', label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=1, layers=layer, \ - name=name, label=label) + def __init__( + self, + model, + xr=0, + yr=0, + hr=0.0, + layer=0, + name="ConstantBase", + label=None, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=1, layers=layer, name=name, label=label + ) self.nparam = 1 # Defined here and not in Element as other elements can have multiple parameters per layers self.nunknowns = 0 self.xr = xr @@ -19,8 +32,9 @@ def __init__(self, model, xr=0, yr=0, hr=0.0, layer=0, \ self.model.add_element(self) def __repr__(self): - return self.name + ' at ' + str( - (self.xr, self.yr)) + ' with head ' + str(self.hr) + return ( + self.name + " at " + str((self.xr, self.yr)) + " with head " + str(self.hr) + ) def initialize(self): if self.aq is None: @@ -33,14 +47,16 @@ def initialize(self): self.parameters = np.atleast_2d(self.pc) def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((1, aq.naq)) if aq == self.aq: rv[0, 0] = 1 return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, 1, aq.naq)) return rv @@ -50,7 +66,7 @@ class Constant(ConstantBase, PotentialEquation): Specify the head at one point in the model in one layer. The head may only be specified in an area of the model where the aquifer system is confined. - + Parameters ---------- model : Model object @@ -65,19 +81,19 @@ class Constant(ConstantBase, PotentialEquation): layer where the head is specified label : string or None (default: None) label of the element - + """ - + def __init__(self, model, xr=0, yr=0, hr=0.0, layer=0, label=None): self.storeinput(inspect.currentframe()) - ConstantBase.__init__(self, model, xr=xr, yr=yr, hr=hr, layer=layer, \ - name='Constant', label=label) + ConstantBase.__init__( + self, model, xr=xr, yr=yr, hr=hr, layer=layer, name="Constant", label=label + ) self.nunknowns = 1 def initialize(self): ConstantBase.initialize(self) - assert self.aq.ilap, 'Constant element added to area that is ' \ - 'semi-confined' + assert self.aq.ilap, "Constant element added to area that is " "semi-confined" self.resfac = np.zeros(1) # required for HeadEquation self.strengthinf = np.zeros(1) # required for HeadEquation @@ -89,9 +105,15 @@ class ConstantInside(Element): # Sets constant at points xc, yc equal to the average of the potential of all elements at points xc, yc # Used for the inside of an inhomogeneity def __init__(self, model, xc=0, yc=0, label=None): - Element.__init__(self, model, nparam=1, nunknowns=1, - layers=list(range(model.aq.naq)), \ - name='ConstantInside', label=label) + Element.__init__( + self, + model, + nparam=1, + nunknowns=1, + layers=list(range(model.aq.naq)), + name="ConstantInside", + label=label, + ) self.xc = np.atleast_1d(xc) self.yc = np.atleast_1d(yc) self.parameters = np.zeros((1, 1)) @@ -106,16 +128,18 @@ def initialize(self): self.ncp = len(self.xc) def potinf(self, x, y, aq=None): - '''Can be called with only one x,y value''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Can be called with only one x,y value""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((1, aq.naq)) if aq == self.aq: rv[0, 0] = 1 return rv def disvecinf(self, x, y, aq=None): - '''Can be called with only one x,y value''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Can be called with only one x,y value""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, 1, aq.naq)) return rv @@ -125,37 +149,44 @@ def equation(self): for icp in range(self.ncp): ieq = 0 for e in self.model.elementlist: - if e. nunknowns > 0: + if e.nunknowns > 0: if e != self: - mat[0:, ieq:ieq + e. nunknowns] += \ - e.potinflayers(self.xc[icp], self.yc[icp], - self.layers).sum(0) - ieq += e. nunknowns + mat[0:, ieq : ieq + e.nunknowns] += e.potinflayers( + self.xc[icp], self.yc[icp], self.layers + ).sum(0) + ieq += e.nunknowns # else: # mat[0, ieq:ieq+e. nunknowns] += -1 else: - rhs[0] -= \ - e.potentiallayers(self.xc[icp], self.yc[icp], - self.layers).sum(0) + rhs[0] -= e.potentiallayers( + self.xc[icp], self.yc[icp], self.layers + ).sum(0) return mat, rhs def setparams(self, sol): self.parameters[:, 0] = sol -#class ConstantStar(Element, PotentialEquation): +# class ConstantStar(Element, PotentialEquation): # I don't think we need the equation class ConstantStar(Element): def __init__(self, model, hstar=0.0, label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=0, \ - name='ConstantStar', label=label) - assert hstar is not None, 'a value for hstar needs to be specified' + Element.__init__( + self, + model, + nparam=1, + nunknowns=0, + layers=0, + name="ConstantStar", + label=label, + ) + assert hstar is not None, "a value for hstar needs to be specified" self.hstar = hstar self.aq = aq self.model.add_element(self) def __repr__(self): - return self.name + ' with head ' + str(self.hstar) + return self.name + " with head " + str(self.hstar) def initialize(self): self.aq.add_element(self) @@ -164,21 +195,24 @@ def initialize(self): self.potstar = self.hstar * self.aq.T def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((1, aq.naq)) return rv def potentiallayers(self, x, y, layers, aq=None): - '''Returns array of size len(layers) only used in building equations + """Returns array of size len(layers) only used in building equations Defined here as it is the particular solution inside a semi-confined aquifer - and cannot be added by using eigen vectors''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + and cannot be added by using eigen vectors""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) pot = np.zeros(len(layers)) if aq == self.aq: pot[:] = self.potstar[layers] return pot def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, 1, aq.naq)) - return rv \ No newline at end of file + return rv diff --git a/timml/controlpoints.py b/timml/controlpoints.py index c2a8f200..d95a8128 100644 --- a/timml/controlpoints.py +++ b/timml/controlpoints.py @@ -1,25 +1,27 @@ import numpy as np + def controlpoints(Ncp, z1, z2, eps=0, include_ends=False): - #thetacp = np.arange(np.pi, 0, -np.pi/self.Ncp) - 0.5 * np.pi/self.Ncp + # thetacp = np.arange(np.pi, 0, -np.pi/self.Ncp) - 0.5 * np.pi/self.Ncp # The following works MUCH better for a uniform head along the line - thetacp = np.linspace(np.pi, 0, Ncp+2)[1:-1] + thetacp = np.linspace(np.pi, 0, Ncp + 2)[1:-1] if include_ends: - Zcp = np.zeros(Ncp+2, 'D') + Zcp = np.zeros(Ncp + 2, "D") Zcp[0] = -1 Zcp[-1] = 1 Zcp[1:-1] = np.cos(thetacp) else: - #thetacp = np.arange(np.pi, 0, -np.pi/Ncp) - 0.5 * np.pi/Ncp - Zcp = np.zeros(Ncp, 'D') + # thetacp = np.arange(np.pi, 0, -np.pi/Ncp) - 0.5 * np.pi/Ncp + Zcp = np.zeros(Ncp, "D") Zcp.real = np.cos(thetacp) Zcp.imag = eps # control point just on positive side (this is handy later on) zcp = Zcp * (z2 - z1) / 2.0 + 0.5 * (z1 + z2) return zcp.real, zcp.imag + def strengthinf_controlpoints(Ncp, Nlayers): # include_ends is False in comparison to function above - thetacp = np.linspace(np.pi, 0, Ncp+2)[1:-1] + thetacp = np.linspace(np.pi, 0, Ncp + 2)[1:-1] Xcp = np.cos(thetacp) s = np.zeros((Ncp, Ncp)) for i in range(Ncp): @@ -28,4 +30,4 @@ def strengthinf_controlpoints(Ncp, Nlayers): for i in range(Ncp): for j in range(Nlayers): rv[i * Nlayers + j, j::Nlayers] = s[i] - return rv \ No newline at end of file + return rv diff --git a/timml/element.py b/timml/element.py index 5127266b..c4a42c0a 100644 --- a/timml/element.py +++ b/timml/element.py @@ -1,11 +1,12 @@ +import inspect # Used for storing the input + import numpy as np -import inspect # Used for storing the input class Element: def __init__(self, model, nparam, nunknowns, layers, name, label): self.model = model - self.aq = None # Set in the initialization function + self.aq = None # Set in the initialization function self.nparam = nparam self.nunknowns = nunknowns self.layers = np.atleast_1d(layers) @@ -13,66 +14,80 @@ def __init__(self, model, nparam, nunknowns, layers, name, label): self.ncp = 0 self.name = name self.label = label - self.inhomelement = False # elements used as part of an inhom boundary are tagged + self.inhomelement = ( + False # elements used as part of an inhom boundary are tagged + ) if self.label is not None: - assert self.label not in list(self.model.elementdict.keys()), \ + assert self.label not in list(self.model.elementdict.keys()), ( "timml error: label " + self.label + " already exists" + ) def initialize(self): # must be overloaded pass def potinf(self, x, y, aq=None): - '''Returns array of size (nparam, naq)''' - raise Exception('Must overload Element.potinf()') + """Returns array of size (nparam, naq)""" + raise Exception("Must overload Element.potinf()") def potential(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) return np.sum(self.parameters * self.potinf(x, y, aq), 0) def potinflayers(self, x, y, layers, aq=None): - '''Returns array of size (len(layers),nparam) - only used in building equations''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Returns array of size (len(layers),nparam) + only used in building equations""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) pot = self.potinf(x, y, aq) # nparam rows, naq cols - rv = np.sum(pot[:,np.newaxis,:] * aq.eigvec, 2).T # Transopose as the first axes needs to be the number of layers - return rv[layers,:] + rv = np.sum( + pot[:, np.newaxis, :] * aq.eigvec, 2 + ).T # Transopose as the first axes needs to be the number of layers + return rv[layers, :] def potentiallayers(self, x, y, layers, aq=None): - '''Returns array of size len(layers) - only used in building equations''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) - pot = np.sum(self.potential(x, y, aq) * aq.eigvec, 1 ) + """Returns array of size len(layers) + only used in building equations""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) + pot = np.sum(self.potential(x, y, aq) * aq.eigvec, 1) return pot[layers] def disvecinf(self, x, y, aq=None): - '''Returns array of size (2, nparam, naq)''' - raise Exception('Must overload Element.disvecinf()') + """Returns array of size (2, nparam, naq)""" + raise Exception("Must overload Element.disvecinf()") def disvec(self, x, y, aq=None): - '''Returns array of size (2, nparam, naq)''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Returns array of size (2, nparam, naq)""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) return np.sum(self.parameters * self.disvecinf(x, y, aq), 1) def disvecinflayers(self, x, y, layers, aq=None): - '''Returns two arrays of size (len(layers),nparam) - only used in building equations''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Returns two arrays of size (len(layers),nparam) + only used in building equations""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) qxqy = self.disvecinf(x, y, aq) # nparam rows, naq cols - qx = np.sum(qxqy[0,:,np.newaxis,:] * aq.eigvec, 2).T # Transpose as the first axes needs to be the number of layers - qy = np.sum(qxqy[1,:,np.newaxis,:] * aq.eigvec, 2).T + qx = np.sum( + qxqy[0, :, np.newaxis, :] * aq.eigvec, 2 + ).T # Transpose as the first axes needs to be the number of layers + qy = np.sum(qxqy[1, :, np.newaxis, :] * aq.eigvec, 2).T return np.array((qx[layers], qy[layers])) def disveclayers(self, x, y, layers, aq=None): - '''Returns two arrays of size len(layers) - only used in building equations''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Returns two arrays of size len(layers) + only used in building equations""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) qxqy = self.disvec(x, y, aq) - rv = np.sum(qxqy[:,np.newaxis,:] * aq.eigvec, 2) - return rv[:,layers] + rv = np.sum(qxqy[:, np.newaxis, :] * aq.eigvec, 2) + return rv[:, layers] def intpot(self, func, x1, y1, x2, y2, layers, aq=None): - if aq is None: print('error, aquifer needs to be given') + if aq is None: + print("error, aquifer needs to be given") z1 = x1 + 1j * y1 z2 = x2 + 1j * y2 z = 0.5 * self.Xleg * (z2 - z1) + 0.5 * (z1 + z2) @@ -84,8 +99,9 @@ def intpot(self, func, x1, y1, x2, y2, layers, aq=None): return pot def intflux(self, func, x1, y1, x2, y2, layers, aq=None): - if aq is None: print('error, aquifer needs to be given') - thetaNormOut = np.arctan2(y2 - y1, x2 - x1) - np.pi/2.0 + if aq is None: + print("error, aquifer needs to be given") + thetaNormOut = np.arctan2(y2 - y1, x2 - x1) - np.pi / 2.0 cosnorm = np.cos(thetaNormOut) sinnorm = np.sin(thetaNormOut) z1 = x1 + 1j * y1 @@ -100,19 +116,20 @@ def intflux(self, func, x1, y1, x2, y2, layers, aq=None): return qtot def headinside(self): - print('headinside not implemented for this element') + print("headinside not implemented for this element") def setparams(self, sol): - raise Exception('Must overload Element.setparams()') + raise Exception("Must overload Element.setparams()") - def storeinput(self,frame): + def storeinput(self, frame): self.inputargs, _, _, self.inputvalues = inspect.getargvalues(frame) - #def stoptrace(self, xyz, layer, ltype, step, direction): + # def stoptrace(self, xyz, layer, ltype, step, direction): # return False, 0 - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, - direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 @@ -125,16 +142,20 @@ def qztop(self, x, y, aq): def plot(self, layer): pass - + def write(self): - rv = self.name + '(' + self.model.modelname + ',\n' + rv = self.name + "(" + self.model.modelname + ",\n" for key in self.inputargs[2:]: # The first two are ignored if isinstance(self.inputvalues[key], np.ndarray): - rv += key + ' = ' + np.array2string(self.inputvalues[key], - separator=',') + ',\n' - elif isinstance(self.inputvalues[key], str): + rv += ( + key + + " = " + + np.array2string(self.inputvalues[key], separator=",") + + ",\n" + ) + elif isinstance(self.inputvalues[key], str): rv += key + " = '" + self.inputvalues[key] + "',\n" else: - rv += key + ' = ' + str(self.inputvalues[key]) + ',\n' - rv += ')\n' + rv += key + " = " + str(self.inputvalues[key]) + ",\n" + rv += ")\n" return rv diff --git a/timml/equation.py b/timml/equation.py index 75d7cfc7..49d94b7f 100644 --- a/timml/equation.py +++ b/timml/equation.py @@ -16,15 +16,18 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ - e.potinflayers(self.xc[icp], self.yc[icp], self.layers) + mat[ + istart : istart + self.nlayers, ieq : ieq + e.nunknowns + ] = e.potinflayers(self.xc[icp], self.yc[icp], self.layers) if e == self: - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] -= self.resfac[icp] + mat[ + istart : istart + self.nlayers, ieq : ieq + e.nunknowns + ] -= self.resfac[icp] ieq += e.nunknowns else: - rhs[istart:istart + self.nlayers] -= \ - e.potentiallayers(self.xc[icp], self.yc[icp], - self.layers) # Pretty cool that this works, really + rhs[istart : istart + self.nlayers] -= e.potentiallayers( + self.xc[icp], self.yc[icp], self.layers + ) # Pretty cool that this works, really return mat, rhs @@ -43,15 +46,20 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ - e.potinflayers(self.xc[icp], self.yc[icp], self.layers) / self.aq.Tcol[self.layers] + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( + e.potinflayers(self.xc[icp], self.yc[icp], self.layers) + / self.aq.Tcol[self.layers] + ) if e == self: - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] -= self.resfac[icp] + mat[ + istart : istart + self.nlayers, ieq : ieq + e.nunknowns + ] -= self.resfac[icp] ieq += e.nunknowns else: - rhs[istart:istart + self.nlayers] -= \ - e.potentiallayers(self.xc[icp], self.yc[icp], self.layers) / self.aq.T[ - self.layers] # Pretty cool that this works, really + rhs[istart : istart + self.nlayers] -= ( + e.potentiallayers(self.xc[icp], self.yc[icp], self.layers) + / self.aq.T[self.layers] + ) # Pretty cool that this works, really return mat, rhs @@ -65,17 +73,18 @@ def equation(self): rhs = np.zeros(self.nunknowns) # Needs to be initialized to zero for icp in range(self.ncp): istart = icp * self.nlayers - rhs[istart:istart + self.nlayers] = self.pc + rhs[istart : istart + self.nlayers] = self.pc ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ - e.potinflayers(self.xc[icp], self.yc[icp], self.layers) + mat[ + istart : istart + self.nlayers, ieq : ieq + e.nunknowns + ] = e.potinflayers(self.xc[icp], self.yc[icp], self.layers) ieq += e.nunknowns else: - rhs[istart:istart + self.nlayers] -= \ - e.potentiallayers(self.xc[icp], self.yc[icp], - self.layers) # Pretty cool that this works, really + rhs[istart : istart + self.nlayers] -= e.potentiallayers( + self.xc[icp], self.yc[icp], self.layers + ) # Pretty cool that this works, really return mat, rhs @@ -88,22 +97,30 @@ def equation(self): """ mat = np.zeros((self.nunknowns, self.model.neq)) rhs = np.zeros(self.nunknowns) # Needs to be initialized to zero - rhs[0:self.nlayers - 1] = 0.0 + rhs[0 : self.nlayers - 1] = 0.0 rhs[self.nlayers - 1] = self.Qc ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - head = e.potinflayers(self.xc, self.yc, self.layers) / self.aq.Tcol[self.layers, :] - mat[0:self.nlayers - 1, ieq:ieq + e.nunknowns] = head[:-1] - head[1:] + head = ( + e.potinflayers(self.xc, self.yc, self.layers) + / self.aq.Tcol[self.layers, :] + ) + mat[0 : self.nlayers - 1, ieq : ieq + e.nunknowns] = ( + head[:-1] - head[1:] + ) if e == self: for i in range(self.nlayers - 1): mat[i, ieq + i] -= self.resfac[i] mat[i, ieq + i + 1] += self.resfac[i + 1] - mat[self.nlayers - 1, ieq:ieq + self.nlayers] = 1.0 + mat[self.nlayers - 1, ieq : ieq + self.nlayers] = 1.0 ieq += e.nunknowns else: - head = e.potentiallayers(self.xc, self.yc, self.layers) / self.aq.T[self.layers] - rhs[0:self.nlayers - 1] -= head[:-1] - head[1:] + head = ( + e.potentiallayers(self.xc, self.yc, self.layers) + / self.aq.T[self.layers] + ) + rhs[0 : self.nlayers - 1] -= head[:-1] - head[1:] return mat, rhs @@ -121,12 +138,15 @@ def equation(self): for e in self.model.elementlist: if e.nunknowns > 0: qx, qy = e.disvecinflayers(self.xc[icp], self.yc[icp], self.layers) - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + ) ieq += e.nunknowns else: qx, qy = e.disveclayers(self.xc[icp], self.yc[icp], self.layers) - rhs[istart:istart + self.nlayers] -= qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + rhs[istart : istart + self.nlayers] -= ( + qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + ) return mat, rhs @@ -144,13 +164,20 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - qx, qy = e.disvecinflayers(self.xcout[icp], self.ycout[icp], self.layers) - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ + qx, qy = e.disvecinflayers( + self.xcout[icp], self.ycout[icp], self.layers + ) + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + ) ieq += e.nunknowns else: - qx, qy = e.disveclayers(self.xcout[icp], self.ycout[icp], self.layers) - rhs[istart:istart + self.nlayers] -= qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + qx, qy = e.disveclayers( + self.xcout[icp], self.ycout[icp], self.layers + ) + rhs[istart : istart + self.nlayers] -= ( + qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + ) return mat, rhs @@ -169,21 +196,45 @@ def equation(self): for e in self.model.elementlist: if e.nunknowns > 0: qx, qy = e.disvecinflayers(self.xc[icp], self.yc[icp], self.layers) - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ - qx * self.cosnorm[icp] + qy * self.sinnorm[icp] - self.resfac[:, np.newaxis] * \ - (e.potinflayers(self.xcin[icp], self.ycin[icp], self.layers, aq=self.aq) / self.aq.Tcol[ - self.layers] - \ - e.potinflayers(self.xcout[icp], self.ycout[icp], self.layers, aq=self.aq) / self.aq.Tcol[ - self.layers]) + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( + qx * self.cosnorm[icp] + + qy * self.sinnorm[icp] + - self.resfac[:, np.newaxis] + * ( + e.potinflayers( + self.xcin[icp], self.ycin[icp], self.layers, aq=self.aq + ) + / self.aq.Tcol[self.layers] + - e.potinflayers( + self.xcout[icp], + self.ycout[icp], + self.layers, + aq=self.aq, + ) + / self.aq.Tcol[self.layers] + ) + ) ieq += e.nunknowns else: qx, qy = e.disveclayers(self.xc[icp], self.yc[icp], self.layers) - rhs[istart:istart + self.nlayers] -= qx * self.cosnorm[icp] + qy * self.sinnorm[icp] + self.resfac * \ - (e.potentiallayers(self.xcin[icp], self.ycin[icp], self.layers, - aq=self.aq) / self.aq.T[self.layers] - - e.potentiallayers(self.xcout[icp], self.ycout[icp], - self.layers, aq=self.aq) / self.aq.T[ - self.layers]) + rhs[istart : istart + self.nlayers] -= ( + qx * self.cosnorm[icp] + + qy * self.sinnorm[icp] + + self.resfac + * ( + e.potentiallayers( + self.xcin[icp], self.ycin[icp], self.layers, aq=self.aq + ) + / self.aq.T[self.layers] + - e.potentiallayers( + self.xcout[icp], + self.ycout[icp], + self.layers, + aq=self.aq, + ) + / self.aq.T[self.layers] + ) + ) return mat, rhs @@ -201,14 +252,28 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ - e.potinflayers(self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin) / self.aqin.Tcol - \ - e.potinflayers(self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout) / self.aqout.Tcol + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( + e.potinflayers( + self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin + ) + / self.aqin.Tcol + - e.potinflayers( + self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout + ) + / self.aqout.Tcol + ) ieq += e.nunknowns else: - rhs[istart:istart + self.nlayers] -= \ - e.potentiallayers(self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin) / self.aqin.T - \ - e.potentiallayers(self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout) / self.aqout.T + rhs[istart : istart + self.nlayers] -= ( + e.potentiallayers( + self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin + ) + / self.aqin.T + - e.potentiallayers( + self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout + ) + / self.aqout.T + ) return mat, rhs @@ -227,22 +292,60 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - headin = self.intpot(e.potinflayers, self.xcin[icp], self.ycin[icp], - self.xcin[icp + 1], self.ycin[icp + 1], self.layers, - aq=self.aqin) / self.aqin.Tcol[self.layers] - headout = self.intpot(e.potinflayers, self.xcout[icp], self.ycout[icp], - self.xcout[icp + 1], self.ycout[icp + 1], self.layers, - aq=self.aqout) / self.aqout.Tcol[self.layers] - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = headin - headout + headin = ( + self.intpot( + e.potinflayers, + self.xcin[icp], + self.ycin[icp], + self.xcin[icp + 1], + self.ycin[icp + 1], + self.layers, + aq=self.aqin, + ) + / self.aqin.Tcol[self.layers] + ) + headout = ( + self.intpot( + e.potinflayers, + self.xcout[icp], + self.ycout[icp], + self.xcout[icp + 1], + self.ycout[icp + 1], + self.layers, + aq=self.aqout, + ) + / self.aqout.Tcol[self.layers] + ) + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( + headin - headout + ) ieq += e.nunknowns else: - headin = self.intpot(e.potentiallayers, self.xcin[icp], self.ycin[icp], - self.xcin[icp + 1], self.ycin[icp + 1], self.layers, - aq=self.aqin) / self.aqin.T[self.layers] - headout = self.intpot(e.potentiallayers, self.xcout[icp], self.ycout[icp], - self.xcout[icp + 1], self.ycout[icp + 1], self.layers, - aq=self.aqout) / self.aqout.T[self.layers] - rhs[istart:istart + self.nlayers] -= headin - headout + headin = ( + self.intpot( + e.potentiallayers, + self.xcin[icp], + self.ycin[icp], + self.xcin[icp + 1], + self.ycin[icp + 1], + self.layers, + aq=self.aqin, + ) + / self.aqin.T[self.layers] + ) + headout = ( + self.intpot( + e.potentiallayers, + self.xcout[icp], + self.ycout[icp], + self.xcout[icp + 1], + self.ycout[icp + 1], + self.layers, + aq=self.aqout, + ) + / self.aqout.T[self.layers] + ) + rhs[istart : istart + self.nlayers] -= headin - headout return mat, rhs @@ -260,16 +363,26 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - qxin, qyin = e.disvecinflayers(self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin) - qxout, qyout = e.disvecinflayers(self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout) - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = \ - (qxin - qxout) * self.cosnorm[icp] + (qyin - qyout) * self.sinnorm[icp] + qxin, qyin = e.disvecinflayers( + self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin + ) + qxout, qyout = e.disvecinflayers( + self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout + ) + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( + qxin - qxout + ) * self.cosnorm[icp] + (qyin - qyout) * self.sinnorm[icp] ieq += e.nunknowns else: - qxin, qyin = e.disveclayers(self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin) - qxout, qyout = e.disveclayers(self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout) - rhs[istart:istart + self.nlayers] -= (qxin - qxout) * self.cosnorm[icp] + (qyin - qyout) * \ - self.sinnorm[icp] + qxin, qyin = e.disveclayers( + self.xcin[icp], self.ycin[icp], self.layers, aq=self.aqin + ) + qxout, qyout = e.disveclayers( + self.xcout[icp], self.ycout[icp], self.layers, aq=self.aqout + ) + rhs[istart : istart + self.nlayers] -= ( + qxin - qxout + ) * self.cosnorm[icp] + (qyin - qyout) * self.sinnorm[icp] return mat, rhs @@ -287,18 +400,48 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - fluxin = self.intflux(e.disvecinflayers, self.xcin[icp], self.ycin[icp], - self.xcin[icp + 1], self.ycin[icp + 1], self.layers, aq=self.aqin) - fluxout = self.intflux(e.disvecinflayers, self.xcout[icp], self.ycout[icp], - self.xcout[icp + 1], self.ycout[icp + 1], self.layers, aq=self.aqout) - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = fluxin - fluxout + fluxin = self.intflux( + e.disvecinflayers, + self.xcin[icp], + self.ycin[icp], + self.xcin[icp + 1], + self.ycin[icp + 1], + self.layers, + aq=self.aqin, + ) + fluxout = self.intflux( + e.disvecinflayers, + self.xcout[icp], + self.ycout[icp], + self.xcout[icp + 1], + self.ycout[icp + 1], + self.layers, + aq=self.aqout, + ) + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = ( + fluxin - fluxout + ) ieq += e.nunknowns else: - fluxin = self.intflux(e.disveclayers, self.xcin[icp], self.ycin[icp], - self.xcin[icp + 1], self.ycin[icp + 1], self.layers, aq=self.aqin) - fluxout = self.intflux(e.disveclayers, self.xcout[icp], self.ycout[icp], - self.xcout[icp + 1], self.ycout[icp + 1], self.layers, aq=self.aqout) - rhs[istart:istart + self.nlayers] -= fluxin - fluxout + fluxin = self.intflux( + e.disveclayers, + self.xcin[icp], + self.ycin[icp], + self.xcin[icp + 1], + self.ycin[icp + 1], + self.layers, + aq=self.aqin, + ) + fluxout = self.intflux( + e.disveclayers, + self.xcout[icp], + self.ycout[icp], + self.xcout[icp + 1], + self.ycout[icp + 1], + self.layers, + aq=self.aqout, + ) + rhs[istart : istart + self.nlayers] -= fluxin - fluxout return mat, rhs @@ -311,14 +454,28 @@ def equation(self): ieq = 0 for e in self.model.elementlist: if e.nunknowns > 0: - flux = self.intflux(e.disvecinflayers, self.xc[icp], self.yc[icp], - self.xc[icp + 1], self.yc[icp + 1], self.layers, aq=self.aq) - mat[istart:istart + self.nlayers, ieq:ieq + e.nunknowns] = flux + flux = self.intflux( + e.disvecinflayers, + self.xc[icp], + self.yc[icp], + self.xc[icp + 1], + self.yc[icp + 1], + self.layers, + aq=self.aq, + ) + mat[istart : istart + self.nlayers, ieq : ieq + e.nunknowns] = flux ieq += e.nunknowns else: - flux = self.intflux(e.disveclayers, self.xc[icp], self.yc[icp], - self.xc[icp + 1], self.yc[icp + 1], self.layers, aq=self.aq) - rhs[istart:istart + self.nlayers] -= flux + flux = self.intflux( + e.disveclayers, + self.xc[icp], + self.yc[icp], + self.xc[icp + 1], + self.yc[icp + 1], + self.layers, + aq=self.aq, + ) + rhs[istart : istart + self.nlayers] -= flux return mat, rhs @@ -333,7 +490,7 @@ def equation(self): for e in self.model.elementlist: if e.nunknowns > 0: flux = self.intflux( - e.disvecinflayers, + e.disvecinflayers, self.xc[icp], self.yc[icp], self.xc[icp + 1], @@ -372,7 +529,7 @@ def equation(self): ieq += e.nunknowns else: flux = self.intflux( - e.disveclayers, + e.disveclayers, self.xc[icp], self.yc[icp], self.xc[icp + 1], @@ -405,7 +562,7 @@ def equation(self): / self.aqout.T[self.layers] ) - rhs[istart : istart + self.nlayers] += (-flux + - self.resfac * (headin - headout) + rhs[istart : istart + self.nlayers] += -flux + self.resfac * ( + headin - headout ) return mat, rhs diff --git a/timml/inhomogeneity.py b/timml/inhomogeneity.py index 158da73f..84852790 100644 --- a/timml/inhomogeneity.py +++ b/timml/inhomogeneity.py @@ -1,25 +1,27 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np + from .aquifer import AquiferData -from .aquifer_parameters import param_maq, param_3d -from .element import Element +from .aquifer_parameters import param_3d, param_maq from .constant import ConstantInside, ConstantStar +from .element import Element from .intlinesink import ( - IntHeadDiffLineSink, IntFluxDiffLineSink, IntFluxLineSink, + IntHeadDiffLineSink, LeakyIntHeadDiffLineSink, ) -__all__ = ['PolygonInhomMaq'] +__all__ = ["PolygonInhomMaq"] + class PolygonInhom(AquiferData): tiny = 1e-8 - def __init__(self, model, xy, kaq, c, z, npor, ltype, hstar, N, - order, ndeg): + def __init__(self, model, xy, kaq, c, z, npor, ltype, hstar, N, order, ndeg): # All input variables except model should be numpy arrays - # That should be checked outside this function): + # That should be checked outside this function): AquiferData.__init__(self, model, kaq, c, z, npor, ltype) self.order = order self.ndeg = ndeg @@ -31,9 +33,11 @@ def __init__(self, model, xy, kaq, c, z, npor, ltype, hstar, N, Zin = 1e-6j Zout = -1e-6j self.zcin = 0.5 * (self.z2 - self.z1) * Zin + 0.5 * ( - self.z1 + self.z2) # point at center on inside + self.z1 + self.z2 + ) # point at center on inside self.zcout = 0.5 * (self.z2 - self.z1) * Zout + 0.5 * ( - self.z1 + self.z2) # point at center on outside + self.z1 + self.z2 + ) # point at center on outside self.zcenter = np.mean(self.z1) self.xcenter, self.ycenter = self.zcenter.real, self.zcenter.imag self.x = np.hstack((self.z1.real, self.z2[-1].real)) @@ -44,12 +48,16 @@ def __init__(self, model, xy, kaq, c, z, npor, ltype, hstar, N, self.ymax = max(self.y) def __repr__(self): - return 'PolygonInhom: ' + str(list(zip(self.x, self.y))) + return "PolygonInhom: " + str(list(zip(self.x, self.y))) def isinside(self, x, y): rv = 0 - if (x >= self.xmin) and (x <= self.xmax) and (y >= self.ymin) and ( - y <= self.ymax): + if ( + (x >= self.xmin) + and (x <= self.xmax) + and (y >= self.ymin) + and (y <= self.ymax) + ): z = complex(x, y) bigZ = (2.0 * z - (self.z1 + self.z2)) / (self.z2 - self.z1) bigZmin1 = bigZ - 1.0 @@ -61,49 +69,67 @@ def isinside(self, x, y): return rv angles = np.log(bigZmin1 / bigZplus1).imag angle = np.sum(angles) - if angle > np.pi: rv = 1 + if angle > np.pi: + rv = 1 return rv def create_elements(self): - aqin = self.model.aq.find_aquifer_data(self.zcin[0].real, - self.zcin[0].imag) + aqin = self.model.aq.find_aquifer_data(self.zcin[0].real, self.zcin[0].imag) for i in range(self.Nsides): - aqout = self.model.aq.find_aquifer_data(self.zcout[i].real, - self.zcout[i].imag) - if (aqout == self.model.aq) or ( - aqout.inhom_number > self.inhom_number): - ls = IntHeadDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], \ - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, \ - aq=aqin, aqin=aqin, aqout=aqout) - ls = IntFluxDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], \ - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, \ - aq=aqout, aqin=aqin, aqout=aqout) - if aqin.ltype[0] == 'a': # add constant on inside + aqout = self.model.aq.find_aquifer_data( + self.zcout[i].real, self.zcout[i].imag + ) + if (aqout == self.model.aq) or (aqout.inhom_number > self.inhom_number): + ls = IntHeadDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqin, + aqin=aqin, + aqout=aqout, + ) + ls = IntFluxDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqout, + aqin=aqin, + aqout=aqout, + ) + if aqin.ltype[0] == "a": # add constant on inside c = ConstantInside(self.model, self.zcin.real, self.zcin.imag) c.inhomelement = True if self.N is not None: - a = AreaSinkInhom(self.model, self.N, self.xcenter, aq=aqin) + a = AreaSinkInhom(self.model, self.N, self.xcenter, aq=aqin) a.inhomelement = True - if aqin.ltype[0] == 'l': - assert self.hstar is not None, 'Error: hstar needs to be set' + if aqin.ltype[0] == "l": + assert self.hstar is not None, "Error: hstar needs to be set" c = ConstantStar(self.model, self.hstar, aq=aqin) c.inhomelement = True class PolygonInhomMaq(PolygonInhom): """Create a polygonal inhomogeneity - + Parameters ---------- model : Model object model to which the element is added xy : array or list list or array of (x,y) pairs of coordinates of corners of the - inhomogeneity. polygonal boundary is automatically closed (so first + inhomogeneity. polygonal boundary is automatically closed (so first point is not repeated) kaq : float, array or list hydraulic conductivity of each aquifer from the top down @@ -130,7 +156,7 @@ class PolygonInhomMaq(PolygonInhom): hstar : float or None (default is None) head value above semi-confining top, only read if topboundary='semi' N : float or None (default is None) - infiltration rate (L/T) inside inhomogeneity. Only possible if + infiltration rate (L/T) inside inhomogeneity. Only possible if topboundary='conf' order : int polynomial order of flux along each segment @@ -139,18 +165,37 @@ class PolygonInhomMaq(PolygonInhom): integrate normal discharge """ - + tiny = 1e-8 - def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, - topboundary='conf', hstar=None, N=None, order=3, ndeg=3): + def __init__( + self, + model, + xy, + kaq=1, + z=[1, 0], + c=[], + npor=0.3, + topboundary="conf", + hstar=None, + N=None, + order=3, + ndeg=3, + ): if N is not None: - assert topboundary[:4] == 'conf', \ - "Error: infiltration can only be added if topboundary='conf'" + assert ( + topboundary[:4] == "conf" + ), "Error: infiltration can only be added if topboundary='conf'" self.storeinput(inspect.currentframe()) - kaq, c, npor, ltype, = param_maq(kaq, z, c, npor, topboundary) - PolygonInhom.__init__(self, model, xy, kaq, c, z, npor, ltype, - hstar, N, order, ndeg) + ( + kaq, + c, + npor, + ltype, + ) = param_maq(kaq, z, c, npor, topboundary) + PolygonInhom.__init__( + self, model, xy, kaq, c, z, npor, ltype, hstar, N, order, ndeg + ) class PolygonInhom3D(PolygonInhom): @@ -158,14 +203,14 @@ class PolygonInhom3D(PolygonInhom): Model3D Class to create a multi-layer model object consisting of many aquifer layers. The resistance between the layers is computed from the vertical hydraulic conductivity of the layers. - + Parameters ---------- model : Model object model to which the element is added xy : array or list list or array of (x,y) pairs of coordinates of corners of the - inhomogeneity. polygonal boundary is automatically closed (so first + inhomogeneity. polygonal boundary is automatically closed (so first point is not repeated) kaq : float, array or list hydraulic conductivity of each layer from the top down @@ -195,36 +240,50 @@ class PolygonInhom3D(PolygonInhom): hstar : float or None (default is None) head value above semi-confining top (read if topboundary='semi') N : float or None (default is None) - infiltration rate (L/T) inside inhomogeneity. Only possible if + infiltration rate (L/T) inside inhomogeneity. Only possible if topboundary='conf' order : int polynomial order of flux along each segment ndeg : int number of points used between two segments to numerically integrate normal discharge - + """ - - def __init__(self, model, xy, kaq=1, z=[1, 0], kzoverkh=1, npor=0.3, - topboundary='conf', topres=0, topthick=0, hstar=0, - N=None, order=3, ndeg=3): + + def __init__( + self, + model, + xy, + kaq=1, + z=[1, 0], + kzoverkh=1, + npor=0.3, + topboundary="conf", + topres=0, + topthick=0, + hstar=0, + N=None, + order=3, + ndeg=3, + ): if N is not None: - assert topboundary[:4] == 'conf', \ - "Error: infiltration can only be added if topboundary='conf'" + assert ( + topboundary[:4] == "conf" + ), "Error: infiltration can only be added if topboundary='conf'" self.storeinput(inspect.currentframe()) - kaq, c, npor, ltype = param_3d(kaq, z, kzoverkh, npor, topboundary, - topres) - if topboundary == 'semi': + kaq, c, npor, ltype = param_3d(kaq, z, kzoverkh, npor, topboundary, topres) + if topboundary == "semi": z = np.hstack((z[0] + topthick, z)) - PolygonInhom.__init__(self, model, xy, kaq, c, z, npor, ltype, - hstar, N, order, ndeg) + PolygonInhom.__init__( + self, model, xy, kaq, c, z, npor, ltype, hstar, N, order, ndeg + ) def compute_z1z2(xy): # Returns z1 and z2 of polygon, in clockwise order x, y = list(zip(*xy)) if x[0] == x[-1] and y[0] == y[-1]: # In case last point is repeated - x = x[:-1]; + x = x[:-1] y = y[:-1] z1 = np.array(x) + np.array(y) * 1j index = list(range(1, len(z1))) + [0] @@ -244,9 +303,20 @@ def compute_z1z2(xy): class BuildingPit(AquiferData): tiny = 1e-8 - def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, - topboundary="conf", hstar=None, order=3, - ndeg=3, layers=[0]): + def __init__( + self, + model, + xy, + kaq=1, + z=[1, 0], + c=[], + npor=0.3, + topboundary="conf", + hstar=None, + order=3, + ndeg=3, + layers=[0], + ): """Element to simulate a building pit surrounded by an impermeable wall. Layers with wall are provided with layers argument. @@ -296,13 +366,20 @@ def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, """ # All input variables except model should be numpy arrays # That should be checked outside this function): - kaq, c, npor, ltype, = param_maq(kaq, z, c, npor, topboundary) + ( + kaq, + c, + npor, + ltype, + ) = param_maq(kaq, z, c, npor, topboundary) AquiferData.__init__(self, model, kaq, c, z, npor, ltype) self.order = order self.ndeg = ndeg self.layers = layers # layers with impermeable wall - self.nonimplayers = list(set(range(self.model.aq.naq)) - set(self.layers)) # layers without wall + self.nonimplayers = list( + set(range(self.model.aq.naq)) - set(self.layers) + ) # layers without wall self.hstar = hstar @@ -312,9 +389,11 @@ def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, Zin = 1e-6j Zout = -1e-6j self.zcin = 0.5 * (self.z2 - self.z1) * Zin + 0.5 * ( - self.z1 + self.z2) # point at center on inside + self.z1 + self.z2 + ) # point at center on inside self.zcout = 0.5 * (self.z2 - self.z1) * Zout + 0.5 * ( - self.z1 + self.z2) # point at center on outside + self.z1 + self.z2 + ) # point at center on outside self.x = np.hstack((self.z1.real, self.z2[-1].real)) self.y = np.hstack((self.z1.imag, self.z2[-1].imag)) self.xmin = min(self.x) @@ -324,8 +403,12 @@ def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, def isinside(self, x, y): rv = 0 - if (x >= self.xmin) and (x <= self.xmax) and (y >= self.ymin) and ( - y <= self.ymax): + if ( + (x >= self.xmin) + and (x <= self.xmax) + and (y >= self.ymin) + and (y <= self.ymax) + ): z = complex(x, y) bigZ = (2.0 * z - (self.z1 + self.z2)) / (self.z2 - self.z1) bigZmin1 = bigZ - 1.0 @@ -337,60 +420,106 @@ def isinside(self, x, y): return rv angles = np.log(bigZmin1 / bigZplus1).imag angle = np.sum(angles) - if angle > np.pi: + if angle > np.pi: rv = 1 return rv def create_elements(self): - aqin = self.model.aq.find_aquifer_data(self.zcin[0].real, - self.zcin[0].imag) + aqin = self.model.aq.find_aquifer_data(self.zcin[0].real, self.zcin[0].imag) for i in range(self.Nsides): - aqout = self.model.aq.find_aquifer_data(self.zcout[i].real, - self.zcout[i].imag) - if (aqout == self.model.aq) or ( - aqout.inhom_number > self.inhom_number): - + aqout = self.model.aq.find_aquifer_data( + self.zcout[i].real, self.zcout[i].imag + ) + if (aqout == self.model.aq) or (aqout.inhom_number > self.inhom_number): # Conditions for layers with impermeable walls - IntFluxLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - layers=self.layers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqin, aqin=aqin, aqout=aqout) - IntFluxLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - layers=self.layers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqout, aqin=aqin, aqout=aqout) + IntFluxLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + layers=self.layers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqin, + aqin=aqin, + aqout=aqout, + ) + IntFluxLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + layers=self.layers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqout, + aqin=aqin, + aqout=aqout, + ) if len(self.nonimplayers) > 0: # use these conditions for layers without impermeable or leaky walls - IntHeadDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - layers=self.nonimplayers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqin, aqin=aqin, aqout=aqout) - IntFluxDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - layers=self.nonimplayers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqout, aqin=aqin, aqout=aqout) - - if aqin.ltype[0] == 'a': # add constant on inside + IntHeadDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + layers=self.nonimplayers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqin, + aqin=aqin, + aqout=aqout, + ) + IntFluxDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + layers=self.nonimplayers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqout, + aqin=aqin, + aqout=aqout, + ) + + if aqin.ltype[0] == "a": # add constant on inside c = ConstantInside(self.model, self.zcin.real, self.zcin.imag) c.inhomelement = True - if aqin.ltype[0] == 'l': - assert self.hstar is not None, 'Error: hstar needs to be set' + if aqin.ltype[0] == "l": + assert self.hstar is not None, "Error: hstar needs to be set" c = ConstantStar(self.model, self.hstar, aq=aqin) c.inhomelement = True class LeakyBuildingPit(BuildingPit): - def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, - topboundary="conf", hstar=None, order=3, - ndeg=3, layers=[0], res=np.inf): + def __init__( + self, + model, + xy, + kaq=1, + z=[1, 0], + c=[], + npor=0.3, + topboundary="conf", + hstar=None, + order=3, + ndeg=3, + layers=[0], + res=np.inf, + ): super().__init__( model=model, xy=xy, @@ -407,62 +536,98 @@ def __init__(self, model, xy, kaq=1, z=[1, 0], c=[], npor=0.3, self.res = res def create_elements(self): - aqin = self.model.aq.find_aquifer_data(self.zcin[0].real, - self.zcin[0].imag) + aqin = self.model.aq.find_aquifer_data(self.zcin[0].real, self.zcin[0].imag) for i in range(self.Nsides): - aqout = self.model.aq.find_aquifer_data(self.zcout[i].real, - self.zcout[i].imag) - if (aqout == self.model.aq) or ( - aqout.inhom_number > self.inhom_number): - + aqout = self.model.aq.find_aquifer_data( + self.zcout[i].real, self.zcout[i].imag + ) + if (aqout == self.model.aq) or (aqout.inhom_number > self.inhom_number): # Conditions for layers with impermeable walls - LeakyIntHeadDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - res=self.res, layers=self.layers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqin, aqin=aqin, aqout=aqout) - - LeakyIntHeadDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - res=self.res, layers=self.layers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqout, aqin=aqin, aqout=aqout) - + LeakyIntHeadDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + res=self.res, + layers=self.layers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqin, + aqin=aqin, + aqout=aqout, + ) + + LeakyIntHeadDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + res=self.res, + layers=self.layers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqout, + aqin=aqin, + aqout=aqout, + ) + if len(self.nonimplayers) > 0: # use these conditions for layers without impermeable or leaky walls - IntHeadDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - layers=self.nonimplayers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqin, aqin=aqin, aqout=aqout) - IntFluxDiffLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - layers=self.nonimplayers, - order=self.order, ndeg=self.ndeg, - label=None, addtomodel=True, - aq=aqout, aqin=aqin, aqout=aqout) - - if aqin.ltype[0] == 'a': # add constant on inside + IntHeadDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + layers=self.nonimplayers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqin, + aqin=aqin, + aqout=aqout, + ) + IntFluxDiffLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + layers=self.nonimplayers, + order=self.order, + ndeg=self.ndeg, + label=None, + addtomodel=True, + aq=aqout, + aqin=aqin, + aqout=aqout, + ) + + if aqin.ltype[0] == "a": # add constant on inside c = ConstantInside(self.model, self.zcin.real, self.zcin.imag) c.inhomelement = True - if aqin.ltype[0] == 'l': - assert self.hstar is not None, 'Error: hstar needs to be set' + if aqin.ltype[0] == "l": + assert self.hstar is not None, "Error: hstar needs to be set" c = ConstantStar(self.model, self.hstar, aq=aqin) c.inhomelement = True - + class AreaSinkInhom(Element): - def __init__(self, model, N, xc, \ - name='AreaSinkInhom', label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=0, \ - name=name, label=label) + def __init__(self, model, N, xc, name="AreaSinkInhom", label=None, aq=None): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=0, name=name, label=label + ) self.N = N - self.xc = xc # x-center of area-sink - #self.nparam = 1 # Defined here and not in Element as other elements can have multiple parameters per layers - #self.nunknowns = 0 + self.xc = xc # x-center of area-sink + # self.nparam = 1 # Defined here and not in Element as other elements can have multiple parameters per layers + # self.nunknowns = 0 self.aq = aq self.model.add_element(self) @@ -470,13 +635,14 @@ def __repr__(self): return self.name def initialize(self): - assert self.aq is not None, 'Error: no aquifer passed' + assert self.aq is not None, "Error: no aquifer passed" self.aq.add_element(self) self.plabsq = self.aq.coef[self.layers, 1:] * self.aq.lab[1:] ** 2 self.parameters = np.atleast_2d(self.N) def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((1, aq.naq)) if aq == self.aq: rv[0, 0] = -0.5 * (x - self.xc) ** 2 @@ -484,17 +650,17 @@ def potinf(self, x, y, aq=None): return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: rv[0, 0, 0] = x - self.xc return rv - + def qztop(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = 0.0 if aq == self.aq: rv = -self.parameters[0, 0] return rv - - diff --git a/timml/inhomogeneity1d.py b/timml/inhomogeneity1d.py index c76fcfb0..8daee2a4 100644 --- a/timml/inhomogeneity1d.py +++ b/timml/inhomogeneity1d.py @@ -1,16 +1,19 @@ -import numpy as np import inspect # user for storing the input + +import numpy as np + from .aquifer import AquiferData -from .aquifer_parameters import param_maq, param_3d +from .aquifer_parameters import param_3d, param_maq from .constant import ConstantStar -from .linesink1d import HeadDiffLineSink1D, FluxDiffLineSink1D +from .linesink1d import FluxDiffLineSink1D, HeadDiffLineSink1D from .stripareasink import StripAreaSinkInhom -__all__ = ['StripInhomMaq', 'StripInhom3D'] +__all__ = ["StripInhomMaq", "StripInhom3D"] + class StripInhom(AquiferData): tiny = 1e-12 - + def __init__(self, model, x1, x2, kaq, c, z, npor, ltype, hstar, N): AquiferData.__init__(self, model, kaq, c, z, npor, ltype) self.x1 = x1 @@ -19,10 +22,10 @@ def __init__(self, model, x1, x2, kaq, c, z, npor, ltype, hstar, N): self.N = N self.inhom_number = self.model.aq.add_inhom(self) self.addlinesinks = True # Set to False not to add line-sinks - + def __repr__(self): return "Inhom1D: " + str(list([self.x1, self.x2])) - + def isinside(self, x, y): return (x >= self.x1) and (x < self.x2) @@ -34,16 +37,23 @@ def create_elements(self): aqin = self.model.aq.find_aquifer_data(xin, 0) aqoutright = self.model.aq.find_aquifer_data(xoutright, 0) if self.addlinesinks: - HeadDiffLineSink1D(self.model, self.x2, label=None, - aq=aqin, aqin=aqin, aqout=aqoutright) + HeadDiffLineSink1D( + self.model, + self.x2, + label=None, + aq=aqin, + aqin=aqin, + aqout=aqoutright, + ) elif self.x2 == np.inf: xin = self.x1 + self.tiny * abs(self.x1) + self.tiny xoutleft = self.x1 - self.tiny * abs(self.x1) - self.tiny aqin = self.model.aq.find_aquifer_data(xin, 0) aqoutleft = self.model.aq.find_aquifer_data(xoutleft, 0) - if self.addlinesinks: - FluxDiffLineSink1D(self.model, self.x1, label=None, - aq=aqin, aqin=aqin, aqout=aqoutleft) + if self.addlinesinks: + FluxDiffLineSink1D( + self.model, self.x1, label=None, aq=aqin, aqin=aqin, aqout=aqoutleft + ) else: xin = 0.5 * (self.x1 + self.x2) xoutleft = self.x1 - self.tiny * abs(self.x1) - self.tiny @@ -52,23 +62,27 @@ def create_elements(self): aqleft = self.model.aq.find_aquifer_data(xoutleft, 0) aqright = self.model.aq.find_aquifer_data(xoutright, 0) if self.addlinesinks: - HeadDiffLineSink1D(self.model, self.x2, label=None, - aq=aqin, aqin=aqin, aqout=aqright) - FluxDiffLineSink1D(self.model, self.x1, label=None, - aq=aqin, aqin=aqin, aqout=aqleft) + HeadDiffLineSink1D( + self.model, self.x2, label=None, aq=aqin, aqin=aqin, aqout=aqright + ) + FluxDiffLineSink1D( + self.model, self.x1, label=None, aq=aqin, aqin=aqin, aqout=aqleft + ) if self.N is not None: - assert aqin.ilap, "Error: infiltration can only be added if topboundary='conf'" + assert ( + aqin.ilap + ), "Error: infiltration can only be added if topboundary='conf'" StripAreaSinkInhom(self.model, self.x1, self.x2, self.N, layer=0) - if aqin.ltype[0] == 'l': + if aqin.ltype[0] == "l": assert self.hstar is not None, "Error: hstar needs to be set" c = ConstantStar(self.model, self.hstar, aq=aqin) c.inhomelement = True - + class StripInhomMaq(StripInhom): """Create a strip inhomogeneity for a mult-aquifer sequence of aquifer-leakylayer-aquifer-leakylayer-aquifer etc - + Parameters ---------- model : Model object @@ -105,11 +119,27 @@ class StripInhomMaq(StripInhom): infiltration rate, only read if topboundary='conf' """ - - def __init__(self, model, x1, x2, kaq=1, z=[1, 0], c=[], npor=0.3, - topboundary='conf', hstar=None, N=None): + + def __init__( + self, + model, + x1, + x2, + kaq=1, + z=[1, 0], + c=[], + npor=0.3, + topboundary="conf", + hstar=None, + N=None, + ): self.storeinput(inspect.currentframe()) - kaq, c, npor, ltype, = param_maq(kaq, z, c, npor, topboundary) + ( + kaq, + c, + npor, + ltype, + ) = param_maq(kaq, z, c, npor, topboundary) StripInhom.__init__(self, model, x1, x2, kaq, c, z, npor, ltype, hstar, N) @@ -117,7 +147,7 @@ class StripInhom3D(StripInhom): """Create a strip inhomogeneity for a multi-layer model consisting of many aquifer layers. The resistance between the layers is computed from the vertical hydraulic conductivity of the layers. - + Parameters ---------- model : Model object @@ -156,13 +186,31 @@ class StripInhom3D(StripInhom): head value above semi-confining top, only read if topboundary='semi' N : float (default is None) infiltration rate, only read if topboundary='conf' - + """ - - def __init__(self, model, x1, x2, kaq, z=[1, 0], kzoverkh=1, npor=0.3, - topboundary='conf', hstar=None, topres=None, topthick=0.0, N=None): + + def __init__( + self, + model, + x1, + x2, + kaq, + z=[1, 0], + kzoverkh=1, + npor=0.3, + topboundary="conf", + hstar=None, + topres=None, + topthick=0.0, + N=None, + ): self.storeinput(inspect.currentframe()) - kaq, c, npor, ltype, = param_3d(kaq, z, kzoverkh, npor, topboundary, topres) - if topboundary== 'semi': + ( + kaq, + c, + npor, + ltype, + ) = param_3d(kaq, z, kzoverkh, npor, topboundary, topres) + if topboundary == "semi": z = np.hstack((z[0] + topthick, z)) StripInhom.__init__(self, model, x1, x2, kaq, c, z, npor, ltype, hstar, N) diff --git a/timml/intlinesink.py b/timml/intlinesink.py index 6ac64fa0..7dd10d26 100644 --- a/timml/intlinesink.py +++ b/timml/intlinesink.py @@ -1,26 +1,52 @@ import numpy as np -from .linesink import LineSinkHoBase + +from .controlpoints import controlpoints from .equation import ( - HeadDiffEquation2, - DisvecDiffEquation2, - IntDisVecEquation, + DisvecDiffEquation2, + HeadDiffEquation2, + IntDisVecEquation, IntLeakyWallEquation, ) -from .controlpoints import controlpoints +from .linesink import LineSinkHoBase + # needed for testing # from .equation import DisvecDiffEquation class IntHeadDiffLineSink(LineSinkHoBase, HeadDiffEquation2): - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, - order=0, ndeg=3, layers=None, label=None, addtomodel=True, - aq=None, aqin=None, aqout=None): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + order=0, + ndeg=3, + layers=None, + label=None, + addtomodel=True, + aq=None, + aqin=None, + aqout=None, + ): if layers is None: layers = np.arange(model.aq.naq) - LineSinkHoBase.__init__(self, model, x1, y1, x2, y2, Qls=0, \ - layers=layers, order=order, \ - name='IntHeadDiffLineSink', label=label, \ - addtomodel=addtomodel, aq=aq) + LineSinkHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + Qls=0, + layers=layers, + order=order, + name="IntHeadDiffLineSink", + label=label, + addtomodel=addtomodel, + aq=aq, + ) self.inhomelement = True self.ndeg = ndeg self.Xleg, self.wleg = np.polynomial.legendre.leggauss(self.ndeg) @@ -30,27 +56,29 @@ def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, def initialize(self): LineSinkHoBase.initialize(self) - self.xcin, self.ycin = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=1e-6, include_ends=True) - self.xcout, self.ycout = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=-1e-6, include_ends=True) + self.xcin, self.ycin = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=1e-6, include_ends=True + ) + self.xcout, self.ycout = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=-1e-6, include_ends=True + ) if self.aqin is None: - self.aqin = self.model.aq.find_aquifer_data(self.xcin[1], - self.ycin[1]) + self.aqin = self.model.aq.find_aquifer_data(self.xcin[1], self.ycin[1]) if self.aqout is None: - self.aqout = self.model.aq.find_aquifer_data(self.xcout[1], - self.ycout[1]) + self.aqout = self.model.aq.find_aquifer_data(self.xcout[1], self.ycout[1]) def setparams(self, sol): self.parameters[:, 0] = sol - #def changetrace(self, xyzt1, xyzt2, layer, ltype): - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax): + # def changetrace(self, xyzt1, xyzt2, layer, ltype): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 message = None - if (ltype == 'a'): + if ltype == "a": eps = 1e-8 za = xyzt1[0] + xyzt1[1] * 1j zb = xyzt2[0] + xyzt2[1] * 1j @@ -74,15 +102,39 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst class IntFluxDiffLineSink(LineSinkHoBase, DisvecDiffEquation2): - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, layers=None, - order=0, ndeg=3, label=None, addtomodel=True, aq=None, - aqin=None, aqout=None): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + layers=None, + order=0, + ndeg=3, + label=None, + addtomodel=True, + aq=None, + aqin=None, + aqout=None, + ): if layers is None: layers = list(range(model.aq.naq)) - LineSinkHoBase.__init__(self, model, x1, y1, x2, y2, Qls=0, - layers=layers, order=order, - name='IntFluxDiffLineSink', label=label, - addtomodel=addtomodel, aq=aq) + LineSinkHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + Qls=0, + layers=layers, + order=order, + name="IntFluxDiffLineSink", + label=label, + addtomodel=addtomodel, + aq=aq, + ) self.inhomelement = True self.ndeg = ndeg self.Xleg, self.wleg = np.polynomial.legendre.leggauss(self.ndeg) @@ -92,27 +144,29 @@ def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, layers=None, def initialize(self): LineSinkHoBase.initialize(self) - self.xcin, self.ycin = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=1e-6, include_ends=True) - self.xcout, self.ycout = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=-1e-6, include_ends=True) + self.xcin, self.ycin = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=1e-6, include_ends=True + ) + self.xcout, self.ycout = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=-1e-6, include_ends=True + ) if self.aqin is None: - self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], - self.ycin[0]) + self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], self.ycin[0]) if self.aqout is None: - self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], - self.ycout[0]) + self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], self.ycout[0]) def setparams(self, sol): self.parameters[:, 0] = sol - #def changetrace(self, xyzt1, xyzt2, layer, ltype): - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax): + # def changetrace(self, xyzt1, xyzt2, layer, ltype): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 message = None - if (ltype == 'a'): + if ltype == "a": eps = 1e-8 za = xyzt1[0] + xyzt1[1] * 1j zb = xyzt2[0] + xyzt2[1] * 1j @@ -132,7 +186,7 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst tnew = xyzt1[3] + dnew / dold * (xyzt2[3] - xyzt1[3]) xyztnew = np.array([xnew, ynew, znew, tnew]) changed = True - #return True, False, xyztnew + # return True, False, xyztnew return changed, terminate, [xyztnew], message @@ -141,15 +195,39 @@ class IntFluxLineSink(LineSinkHoBase, IntDisVecEquation): along linesink to 0. Used in BuildingPit element """ - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, layers=None, - order=0, ndeg=3, label=None, addtomodel=True, aq=None, - aqin=None, aqout=None): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + layers=None, + order=0, + ndeg=3, + label=None, + addtomodel=True, + aq=None, + aqin=None, + aqout=None, + ): if layers is None: layers = list(range(model.aq.naq)) - LineSinkHoBase.__init__(self, model, x1, y1, x2, y2, Qls=0, - layers=layers, order=order, - name='IntFluxDiffLineSink', label=label, - addtomodel=addtomodel, aq=aq) + LineSinkHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + Qls=0, + layers=layers, + order=order, + name="IntFluxDiffLineSink", + label=label, + addtomodel=addtomodel, + aq=aq, + ) self.inhomelement = True self.ndeg = ndeg self.Xleg, self.wleg = np.polynomial.legendre.leggauss(self.ndeg) @@ -161,17 +239,17 @@ def initialize(self): LineSinkHoBase.initialize(self) # recalculated with ncp - 1 points instead of ncp points - self.xcin, self.ycin = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=1e-6, include_ends=True) - self.xcout, self.ycout = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=-1e-6, include_ends=True) + self.xcin, self.ycin = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=1e-6, include_ends=True + ) + self.xcout, self.ycout = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=-1e-6, include_ends=True + ) if self.aqin is None: - self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], - self.ycin[0]) + self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], self.ycin[0]) if self.aqout is None: - self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], - self.ycout[0]) + self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], self.ycout[0]) # set control points x,y depending on which side of # the boundary the element is for if self.aq == self.aqin: @@ -192,15 +270,40 @@ class LeakyIntHeadDiffLineSink(LineSinkHoBase, IntLeakyWallEquation): Used in LeakyBuildingPit element """ - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, res=np.inf, layers=None, - order=0, ndeg=3, label=None, addtomodel=True, aq=None, - aqin=None, aqout=None): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + res=np.inf, + layers=None, + order=0, + ndeg=3, + label=None, + addtomodel=True, + aq=None, + aqin=None, + aqout=None, + ): if layers is None: layers = list(range(model.aq.naq)) - LineSinkHoBase.__init__(self, model, x1, y1, x2, y2, Qls=0, - layers=layers, order=order, - name='LeakyIntHeadDiffLineSink', label=label, - addtomodel=addtomodel, aq=aq) + LineSinkHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + Qls=0, + layers=layers, + order=order, + name="LeakyIntHeadDiffLineSink", + label=label, + addtomodel=addtomodel, + aq=aq, + ) self.res = res self.inhomelement = True self.ndeg = ndeg @@ -213,17 +316,17 @@ def initialize(self): LineSinkHoBase.initialize(self) # recalculated with ncp - 1 points instead of ncp points - self.xcin, self.ycin = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=1e-6, include_ends=True) - self.xcout, self.ycout = controlpoints(self.ncp - 1, self.z1, self.z2, - eps=-1e-6, include_ends=True) + self.xcin, self.ycin = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=1e-6, include_ends=True + ) + self.xcout, self.ycout = controlpoints( + self.ncp - 1, self.z1, self.z2, eps=-1e-6, include_ends=True + ) if self.aqin is None: - self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], - self.ycin[0]) + self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], self.ycin[0]) if self.aqout is None: - self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], - self.ycout[0]) + self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], self.ycout[0]) # set control points x,y depending on which side of # the boundary the element is for if self.aq == self.aqin: @@ -237,4 +340,4 @@ def initialize(self): self.resfac = self.aq.Haq[self.layers] / self.res def setparams(self, sol): - self.parameters[:, 0] = sol \ No newline at end of file + self.parameters[:, 0] = sol diff --git a/timml/linedoublet.py b/timml/linedoublet.py index df8f20a8..8a444f11 100644 --- a/timml/linedoublet.py +++ b/timml/linedoublet.py @@ -1,59 +1,89 @@ -import numpy as np -import matplotlib.pyplot as plt import inspect # Used for storing the input -from .element import Element + +import matplotlib.pyplot as plt +import numpy as np + +from . import bessel from .controlpoints import controlpoints +from .element import Element from .equation import DisvecEquation, LeakyWallEquation -from . import bessel -__all__ = ['ImpLineDoublet', 'ImpLineDoubletString', 'LeakyLineDoublet', - 'LeakyLineDoubletString'] +__all__ = [ + "ImpLineDoublet", + "ImpLineDoubletString", + "LeakyLineDoublet", + "LeakyLineDoubletString", +] class LineDoubletHoBase(Element): - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, delp=0.0, res=0.0, - layers=0, order=0, name='LineDoubletHoBase', - label=None, addtomodel=True, aq=None, zcinout=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, - name=name, label=label) + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + delp=0.0, + res=0.0, + layers=0, + order=0, + name="LineDoubletHoBase", + label=None, + addtomodel=True, + aq=None, + zcinout=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) self.x1 = float(x1) self.y1 = float(y1) self.x2 = float(x2) self.y2 = float(y2) - self.delp = np.atleast_1d(delp).astype('d') - self.res = np.atleast_1d(res).astype('d') + self.delp = np.atleast_1d(delp).astype("d") + self.res = np.atleast_1d(res).astype("d") self.order = order self.nparam = self.nlayers * (self.order + 1) self.addtomodel = addtomodel - if addtomodel: self.model.add_element(self) + if addtomodel: + self.model.add_element(self) self.aq = aq self.zcinout = zcinout - + def __repr__(self): - return self.name + ' from ' + str((self.x1, self.y1)) + ' to ' + str( - (self.x2, self.y2)) + return ( + self.name + + " from " + + str((self.x1, self.y1)) + + " to " + + str((self.x2, self.y2)) + ) def initialize(self): self.ncp = self.order + 1 self.z1 = self.x1 + 1j * self.y1 self.z2 = self.x2 + 1j * self.y2 self.L = np.abs(self.z1 - self.z2) - self.thetaNormOut = np.arctan2(self.y2 - self.y1, - self.x2 - self.x1) - np.pi / 2.0 + self.thetaNormOut = ( + np.arctan2(self.y2 - self.y1, self.x2 - self.x1) - np.pi / 2.0 + ) self.cosnorm = np.cos(self.thetaNormOut) * np.ones(self.ncp) self.sinnorm = np.sin(self.thetaNormOut) * np.ones(self.ncp) # self.xc, self.yc = controlpoints(self.ncp, self.z1, self.z2, eps=0) if self.zcinout is not None: - self.xcin, self.ycin = controlpoints(self.ncp, self.zcinout[0], - self.zcinout[1], eps=0) - self.xcout, self.ycout = controlpoints(self.ncp, self.zcinout[2], - self.zcinout[3], eps=0) + self.xcin, self.ycin = controlpoints( + self.ncp, self.zcinout[0], self.zcinout[1], eps=0 + ) + self.xcout, self.ycout = controlpoints( + self.ncp, self.zcinout[2], self.zcinout[3], eps=0 + ) else: - self.xcin, self.ycin = controlpoints(self.ncp, self.z1, self.z2, - eps=1e-6) - self.xcout, self.ycout = controlpoints(self.ncp, self.z1, self.z2, - eps=-1e-6) + self.xcin, self.ycin = controlpoints(self.ncp, self.z1, self.z2, eps=1e-6) + self.xcout, self.ycout = controlpoints( + self.ncp, self.z1, self.z2, eps=-1e-6 + ) if self.aq is None: self.aq = self.model.aq.find_aquifer_data(self.xc[0], self.yc[0]) self.resfac = self.aq.Haq[self.layers] / self.res @@ -64,7 +94,7 @@ def initialize(self): self.parameters[:, 0] = self.delp def potinf(self, x, y, aq=None): - '''Can be called with only one x,y value + """Can be called with only one x,y value Returns array(nparam, self.aq.naq) with order order 0, layer[0] order 0, layer[1] @@ -72,20 +102,30 @@ def potinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] etc - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: - potrv = rv.reshape((self.order + 1, self.nlayers, - aq.naq)) # clever way of using a reshaped rv here + potrv = rv.reshape( + (self.order + 1, self.nlayers, aq.naq) + ) # clever way of using a reshaped rv here pot = np.zeros((self.order + 1, aq.naq)) - pot[:, :] = bessel.bessel.potbesldv(float(x), float(y), self.z1, self.z2, aq.lab, - self.order, aq.ilap, aq.naq) + pot[:, :] = bessel.bessel.potbesldv( + float(x), + float(y), + self.z1, + self.z2, + aq.lab, + self.order, + aq.ilap, + aq.naq, + ) potrv[:] = self.aq.coef[self.layers] * pot[:, np.newaxis, :] return rv def disvecinf(self, x, y, aq=None): - '''Can be called with only one x,y value + """Can be called with only one x,y value Returns array(nparam, self.aq.naq) with order order 0, layer[0] order 0, layer[1] @@ -93,33 +133,46 @@ def disvecinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] etc - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: - qxqyrv = rv.reshape((2, self.order + 1, self.nlayers, - aq.naq)) # clever way of using a reshaped rv here + qxqyrv = rv.reshape( + (2, self.order + 1, self.nlayers, aq.naq) + ) # clever way of using a reshaped rv here qxqy = np.zeros((2 * (self.order + 1), aq.naq)) - qxqy[:, :] = bessel.bessel.disbesldv(float(x), float(y), self.z1, self.z2, aq.lab, - self.order, aq.ilap, aq.naq) - qxqyrv[0, :] = self.aq.coef[self.layers] * qxqy[:self.order + 1, - np.newaxis, :] - qxqyrv[1, :] = self.aq.coef[self.layers] * qxqy[self.order + 1:, - np.newaxis, :] + qxqy[:, :] = bessel.bessel.disbesldv( + float(x), + float(y), + self.z1, + self.z2, + aq.lab, + self.order, + aq.ilap, + aq.naq, + ) + qxqyrv[0, :] = ( + self.aq.coef[self.layers] * qxqy[: self.order + 1, np.newaxis, :] + ) + qxqyrv[1, :] = ( + self.aq.coef[self.layers] * qxqy[self.order + 1 :, np.newaxis, :] + ) return rv def plot(self, layer=None): if (layer is None) or (layer in self.layers): - plt.plot([self.x1, self.x2], [self.y1, self.y2], 'k') + plt.plot([self.x1, self.x2], [self.y1, self.y2], "k") + class ImpLineDoublet(LineDoubletHoBase, DisvecEquation): """ Create a segment of an impermeable wall, which is simulated with a line-doublet - + Parameters ---------- - + model : Model object Model to which the element is added x1 : scalar @@ -136,24 +189,45 @@ class ImpLineDoublet(LineDoubletHoBase, DisvecEquation): layers : scalar, list or array layer(s) in which element is placed if scalar: element is placed in this layer - if list or array: element is placed in all these layers + if list or array: element is placed in all these layers label: str or None label of element - + See Also -------- - + :class:`.ImpLineDoubletString` - + """ - - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, \ - order=0, layers=0, label=None, addtomodel=True): + + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + order=0, + layers=0, + label=None, + addtomodel=True, + ): self.storeinput(inspect.currentframe()) - LineDoubletHoBase.__init__(self, model, x1, y1, x2, y2, delp=0, \ - res = np.inf, layers=layers, order=order, - name='ImpLineDoublet', label=label, \ - addtomodel=addtomodel) + LineDoubletHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + delp=0, + res=np.inf, + layers=layers, + order=order, + name="ImpLineDoublet", + label=label, + addtomodel=addtomodel, + ) self.nunknowns = self.nparam def initialize(self): @@ -161,17 +235,18 @@ def initialize(self): def setparams(self, sol): self.parameters[:, 0] = sol - + + class LeakyLineDoublet(LineDoubletHoBase, LeakyWallEquation): """ Create a segment of a leaky wall, which is simulated with a line-doublet. The specific discharge through the wall is equal to the head difference across the wall - divided by the resistance of the wall. - + divided by the resistance of the wall. + Parameters ---------- - + model : Model object Model to which the element is added x1 : scalar @@ -190,24 +265,46 @@ class LeakyLineDoublet(LineDoubletHoBase, LeakyWallEquation): layers : scalar, list or array layer(s) in which element is placed if scalar: element is placed in this layer - if list or array: element is placed in all these layers + if list or array: element is placed in all these layers label: str or None label of element - + See Also -------- - + :class:`.LeakyLineDoubletString` - + """ - - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, res=0,\ - order=0, layers=0, label=None, addtomodel=True): + + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + res=0, + order=0, + layers=0, + label=None, + addtomodel=True, + ): self.storeinput(inspect.currentframe()) - LineDoubletHoBase.__init__(self, model, x1, y1, x2, y2, delp=0, \ - res=res, layers=layers, order=order, - name='ImpLineDoublet', label=label, \ - addtomodel=addtomodel) + LineDoubletHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + delp=0, + res=res, + layers=layers, + order=order, + name="ImpLineDoublet", + label=label, + addtomodel=addtomodel, + ) self.nunknowns = self.nparam def initialize(self): @@ -218,12 +315,24 @@ def setparams(self, sol): class LineDoubletStringBase(Element): - def __init__(self, model, xy, closed=False, layers=0, order=0, res=0, - name='LineDoubletStringBase', label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, \ - name=name, label=label) - self.xy = np.atleast_2d(xy).astype('d') - if closed: self.xy = np.vstack((self.xy, self.xy[0])) + def __init__( + self, + model, + xy, + closed=False, + layers=0, + order=0, + res=0, + name="LineDoubletStringBase", + label=None, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) + self.xy = np.atleast_2d(xy).astype("d") + if closed: + self.xy = np.vstack((self.xy, self.xy[0])) self.order = order self.aq = aq self.ldlist = [] @@ -231,18 +340,31 @@ def __init__(self, model, xy, closed=False, layers=0, order=0, res=0, self.Nld = len(self.x) - 1 for i in range(self.Nld): self.ldlist.append( - LineDoubletHoBase(model, x1=self.x[i], y1=self.y[i], x2=self.x[i + 1], - y2=self.y[i + 1], delp=0.0, res=res, layers=layers, - order=order, label=label, addtomodel=False, aq=aq)) + LineDoubletHoBase( + model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + delp=0.0, + res=res, + layers=layers, + order=order, + label=label, + addtomodel=False, + aq=aq, + ) + ) def __repr__(self): - return self.name + ' with nodes ' + str(self.xy) + return self.name + " with nodes " + str(self.xy) def initialize(self): for ld in self.ldlist: ld.initialize() - self.ncp = self.Nld * self.ldlist[ - 0].ncp # Same order for all elements in string + self.ncp = ( + self.Nld * self.ldlist[0].ncp + ) # Same order for all elements in string self.nparam = self.Nld * self.ldlist[0].nparam self.nunknowns = self.nparam self.xld = np.empty((self.Nld, 2)) @@ -251,8 +373,9 @@ def initialize(self): self.xld[i, :] = [ld.x1, ld.x2] self.yld[i, :] = [ld.y1, ld.y2] if self.aq is None: - self.aq = self.model.aq.find_aquifer_data(self.ldlist[0].xc[0], - self.ldlist[0].yc[0]) + self.aq = self.model.aq.find_aquifer_data( + self.ldlist[0].xc[0], self.ldlist[0].yc[0] + ) self.parameters = np.zeros((self.nparam, 1)) ## As parameters are only stored for the element not the list, we need to combine the following self.xc = np.array([ld.xc for ld in self.ldlist]).flatten() @@ -264,12 +387,12 @@ def initialize(self): self.cosnorm = np.array([ld.cosnorm for ld in self.ldlist]).flatten() self.sinnorm = np.array([ld.sinnorm for ld in self.ldlist]).flatten() self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], self.ycin[0]) - self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], - self.ycout[0]) + self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], self.ycout[0]) self.resfac = self.ldlist[0].resfac def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.Nld, self.ldlist[0].nparam, aq.naq)) for i in range(self.Nld): rv[i] = self.ldlist[i].potinf(x, y, aq) @@ -277,26 +400,27 @@ def potinf(self, x, y, aq=None): return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.Nld, self.ldlist[0].nparam, aq.naq)) for i in range(self.Nld): rv[:, i] = self.ldlist[i].disvecinf(x, y, aq) rv.shape = (2, self.nparam, aq.naq) return rv - + def plot(self, layer=None): if (layer is None) or (layer in self.layers): - plt.plot(self.x, self.y, 'k') + plt.plot(self.x, self.y, "k") class ImpLineDoubletString(LineDoubletStringBase, DisvecEquation): """ Create a string of impermeable wall segements consisting of line-doublets - + Parameters ---------- - + model : Model object Model to which the element is added xy : array or list @@ -311,22 +435,28 @@ class ImpLineDoubletString(LineDoubletStringBase, DisvecEquation): (head jump if transmissivity is equal on each side of wall) label: str or None label of element - + See Also -------- - + :class:`.ImpLineDoublet` - + """ - - - def __init__(self, model, xy=[(-1, 0), (1, 0)], \ - layers=0, order=0, label=None): + + def __init__(self, model, xy=[(-1, 0), (1, 0)], layers=0, order=0, label=None): self.storeinput(inspect.currentframe()) - LineDoubletStringBase.__init__(self, model, xy, closed=False, - res=np.inf, layers=layers, order=order, \ - name='ImpLineDoubletString', label=label, - aq=None) + LineDoubletStringBase.__init__( + self, + model, + xy, + closed=False, + res=np.inf, + layers=layers, + order=order, + name="ImpLineDoubletString", + label=label, + aq=None, + ) self.model.add_element(self) def initialize(self): @@ -335,15 +465,16 @@ def initialize(self): def setparams(self, sol): self.parameters[:, 0] = sol - + + class LeakyLineDoubletString(LineDoubletStringBase, LeakyWallEquation): """ Create a string of leaky wall segements consisting of line-doublets - + Parameters ---------- - + model : Model object Model to which the element is added xy : array or list @@ -360,21 +491,30 @@ class LeakyLineDoubletString(LineDoubletStringBase, LeakyWallEquation): (head jump if transmissivity is equal on each side of wall) label: str or None label of element - + See Also -------- - + :class:`.ImpLineDoublet` - + """ - - def __init__(self, model, xy=[(-1, 0), (1, 0)], res=np.inf,\ - layers=0, order=0, label=None): + + def __init__( + self, model, xy=[(-1, 0), (1, 0)], res=np.inf, layers=0, order=0, label=None + ): self.storeinput(inspect.currentframe()) - LineDoubletStringBase.__init__(self, model, xy, closed=False, - layers=layers, order=order, res=res,\ - name='ImpLineDoubletString', label=label, - aq=None) + LineDoubletStringBase.__init__( + self, + model, + xy, + closed=False, + layers=layers, + order=order, + res=res, + name="ImpLineDoubletString", + label=label, + aq=None, + ) self.model.add_element(self) def initialize(self): diff --git a/timml/linedoublet1d.py b/timml/linedoublet1d.py index cd33b07e..9a50be93 100644 --- a/timml/linedoublet1d.py +++ b/timml/linedoublet1d.py @@ -1,28 +1,41 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np + from .element import Element from .equation import DisvecEquation, LeakyWallEquation -__all__ = ['ImpLineDoublet1D', 'LeakyLineDoublet1D'] +__all__ = ["ImpLineDoublet1D", "LeakyLineDoublet1D"] -class LineDoublet1D(Element): - def __init__(self, model, xld, delp=1, layers=0, name="LineDoublet1DBase", label=None, - addtomodel=True, res=0, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, - name=name, label=label) +class LineDoublet1D(Element): + def __init__( + self, + model, + xld, + delp=1, + layers=0, + name="LineDoublet1DBase", + label=None, + addtomodel=True, + res=0, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) self.xld = float(xld) self.delp = np.atleast_1d(delp) self.res = float(res) self.aq = aq self.addtomodel = addtomodel - if self.addtomodel: + if self.addtomodel: self.model.add_element(self) self.nparam = self.nlayers - + def __repr__(self): return self.name + " at " + str(self.xld) + " in layers: " + str(self.layers) - + def initialize(self): self.xc = np.array([self.xld]) self.yc = np.zeros(1) @@ -39,60 +52,70 @@ def initialize(self): self.resfac = self.aq.Haq[self.layers] / self.res def potinf(self, x, y, aq=None): - if aq is None: + if aq is None: aq = self.model.aq.find_aquifer_data(x, 0) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: pot = np.zeros(aq.naq) if aq.ilap: - if x - self.xld < 0.: - #pot[0] = -0.5 * (x - self.xld - 1) # so that pot = 0.5 at x=xld - pot[0] = -0.5 # so that pot = 0.5 at x=xld + if x - self.xld < 0.0: + # pot[0] = -0.5 * (x - self.xld - 1) # so that pot = 0.5 at x=xld + pot[0] = -0.5 # so that pot = 0.5 at x=xld pot[1:] = -0.5 * np.exp((x - self.xld) / aq.lab[1:]) - elif x - self.xld >= 0.: - #pot[0] = 0.5 * (x - self.xld + 1) + elif x - self.xld >= 0.0: + # pot[0] = 0.5 * (x - self.xld + 1) pot[0] = 0.5 pot[1:] = 0.5 * np.exp(-(x - self.xld) / aq.lab[1:]) else: - if x - self.xld < 0.: + if x - self.xld < 0.0: pot[:] = -0.5 * np.exp((x - self.xld) / aq.lab) - elif x - self.xld >= 0.: + elif x - self.xld >= 0.0: pot[:] = 0.5 * np.exp(-(x - self.xld) / aq.lab) rv[:] = self.aq.coef[self.layers] * pot return rv - + def disvecinf(self, x, y, aq=None): - if aq is None: + if aq is None: aq = self.model.aq.find_aquifer_data(x, 0) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: qx = np.zeros(aq.naq) if aq.ilap: - if x - self.xld < 0.: + if x - self.xld < 0.0: qx[0] = 0.0 qx[1:] = 0.5 / aq.lab[1:] * np.exp((x - self.xld) / aq.lab[1:]) - elif x - self.xld >= 0.: + elif x - self.xld >= 0.0: qx[0] = 0.0 qx[1:] = 0.5 / aq.lab[1:] * np.exp(-(x - self.xld) / aq.lab[1:]) else: - if x - self.xld < 0.: + if x - self.xld < 0.0: qx[:] = 0.5 / aq.lab * np.exp((x - self.xld) / aq.lab) - elif x - self.xld >= 0.: + elif x - self.xld >= 0.0: qx[:] = 0.5 / aq.lab * np.exp(-(x - self.xld) / aq.lab) rv[0] = self.aq.coef[self.layers] * qx return rv - + + class ImpLineDoublet1D(LineDoublet1D, DisvecEquation): """ Create 1D impermeable wall - + """ - + def __init__(self, model, xld=0, layers=0, label=None): self.storeinput(inspect.currentframe()) - LineDoublet1D.__init__(self, model, xld, delp=0, layers=layers, \ - name="ImpLineDoublet1D", label=label, \ - addtomodel=True, res=np.inf, aq=None) + LineDoublet1D.__init__( + self, + model, + xld, + delp=0, + layers=layers, + name="ImpLineDoublet1D", + label=label, + addtomodel=True, + res=np.inf, + aq=None, + ) self.nunknowns = self.nparam def initialize(self): @@ -105,10 +128,10 @@ def setparams(self, sol): class LeakyLineDoublet1D(LineDoublet1D, LeakyWallEquation): """ Create an infinitely long leaky or impermeable wall - + Parameters ---------- - + model : Model object Model to which the element is added xld : scalar @@ -116,11 +139,11 @@ class LeakyLineDoublet1D(LineDoublet1D, LeakyWallEquation): hls : scalar head in line-sink res : scalar (default is 0) - resistance of leaky wall. use np.inf to create impermeable wall + resistance of leaky wall. use np.inf to create impermeable wall layers : scalar, list or array layer(s) in which element is placed if scalar: element is placed in this layer - if list or array: element is placed in all these layers + if list or array: element is placed in all these layers label: str or None label of element @@ -130,9 +153,18 @@ class LeakyLineDoublet1D(LineDoublet1D, LeakyWallEquation): def __init__(self, model, xld=0, res=np.inf, layers=0, label=None): self.storeinput(inspect.currentframe()) - LineDoublet1D.__init__(self, model, xld, delp=0, layers=layers, - name="LeakyLineDoublet1D", label=label, - addtomodel=True, res=res, aq=None) + LineDoublet1D.__init__( + self, + model, + xld, + delp=0, + layers=layers, + name="LeakyLineDoublet1D", + label=label, + addtomodel=True, + res=res, + aq=None, + ) self.nunknowns = self.nparam def initialize(self): diff --git a/timml/linesink.py b/timml/linesink.py index f18436c0..fad392ca 100644 --- a/timml/linesink.py +++ b/timml/linesink.py @@ -1,30 +1,48 @@ -import numpy as np -import matplotlib.pyplot as plt import inspect # Used for storing the input + +import matplotlib.pyplot as plt +import numpy as np + +from . import bessel +from .controlpoints import controlpoints, strengthinf_controlpoints from .element import Element from .equation import HeadEquation, PotentialEquation -from .controlpoints import controlpoints, strengthinf_controlpoints -from . import bessel - -__all__ = ['LineSinkBase', 'HeadLineSinkZero', 'HeadLineSink', 'LineSinkDitch', - 'HeadLineSinkString', 'LineSinkDitchString'] +__all__ = [ + "LineSinkBase", + "HeadLineSinkZero", + "HeadLineSink", + "LineSinkDitch", + "HeadLineSinkString", + "LineSinkDitchString", +] class LineSinkChangeTrace: - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax, verbose=False): + def changetrace( + self, + xyzt1, + xyzt2, + aq, + layer, + ltype, + modellayer, + direction, + hstepmax, + verbose=False, + ): changed = False terminate = False xyztnew = 0 message = None - if (ltype == 'a'): + if ltype == "a": if True: -# if (layer == self.layers).any(): # in layer where line-sink is screened -# not needed anymore, I thin this is all taken care of with checking Qn1 and Qn2 + # if (layer == self.layers).any(): # in layer where line-sink is screened + # not needed anymore, I thin this is all taken care of with checking Qn1 and Qn2 if verbose: - print('hello changetrace') - print('xyz1:', xyzt1[:-1]) - print('xyz2:', xyzt2[:-1]) + print("hello changetrace") + print("xyz1:", xyzt1[:-1]) + print("xyz2:", xyzt2[:-1]) x1, y1, z1, t1 = xyzt1 x2, y2, z2, t2 = xyzt2 eps = 1e-8 @@ -33,15 +51,17 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst Za = (2 * za - (self.z1 + self.z2)) / (self.z2 - self.z1) Zb = (2 * zb - (self.z1 + self.z2)) / (self.z2 - self.z1) if verbose: - print('Za', Za) - print('Zb', Zb) + print("Za", Za) + print("Zb", Zb) if Za.imag * Zb.imag < 0: Xa, Ya = Za.real, Za.imag Xb, Yb = Zb.real, Zb.imag X = Xa - Ya * (Xb - Xa) / (Yb - Ya) - if verbose: print('X', X) + if verbose: + print("X", X) if abs(X) <= 1: # crosses line-sink - if verbose: print('crosses line-sink') + if verbose: + print("crosses line-sink") Znew1 = X - eps * np.sign(Yb) * 1j # steps to side of Ya Znew2 = X + eps * np.sign(Yb) * 1j # steps to side of Yb znew1 = 0.5 * ((self.z2 - self.z1) * Znew1 + self.z1 + self.z2) @@ -57,12 +77,15 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst Qx2, Qy2 = self.model.disvec(xnew2, ynew2)[:, layer] * direction Qn2 = Qx2 * np.cos(theta) + Qy2 * np.sin(theta) if verbose: - print('xnew1, ynew1:', xnew1, ynew1) - print('xnew2, ynew2:', xnew2, ynew2) - print('Qn1, Qn2', Qn1, Qn2) - print('Qn2 > Qn1:', Qn2 > Qn1) - if Qn1 < 0: # trying to cross line-sink that infiltrates, stay on bottom, don't terminate - if verbose: print('change 1') + print("xnew1, ynew1:", xnew1, ynew1) + print("xnew2, ynew2:", xnew2, ynew2) + print("Qn1, Qn2", Qn1, Qn2) + print("Qn2 > Qn1:", Qn2 > Qn1) + if ( + Qn1 < 0 + ): # trying to cross line-sink that infiltrates, stay on bottom, don't terminate + if verbose: + print("change 1") xnew = xnew1 ynew = ynew1 dold = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) @@ -72,7 +95,8 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst changed = True xyztnew = [np.array([xnew, ynew, znew, tnew])] elif Qn2 < 0: # all water is taken out, terminate - if verbose: print('change 2') + if verbose: + print("change 2") xnew = xnew2 ynew = ynew2 dold = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) @@ -83,49 +107,75 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst terminate = True xyztnew = [np.array([xnew, ynew, znew, tnew])] elif Qn2 > Qn1: # line-sink infiltrates - if verbose: print('change 3') + if verbose: + print("change 3") xnew = xnew2 ynew = ynew2 dold = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) dnew = np.sqrt((x1 - xnew) ** 2 + (y1 - ynew) ** 2) - znew = z1 + dnew / dold * (z2 - z1) # elevation just before jump + znew = z1 + dnew / dold * ( + z2 - z1 + ) # elevation just before jump tnew = t1 + dnew / dold * (t2 - t1) Qbelow = (znew - aq.z[modellayer + 1]) / aq.Haq[layer] * Qn1 znew2 = aq.z[modellayer + 1] + Qbelow / Qn2 * aq.Haq[layer] changed = True - xyztnew = [np.array([xnew, ynew, znew, tnew]), - np.array([xnew, ynew, znew2, tnew])] + xyztnew = [ + np.array([xnew, ynew, znew, tnew]), + np.array([xnew, ynew, znew2, tnew]), + ] else: # line-sink takes part of water out - if verbose: print('change 4') + if verbose: + print("change 4") xnew = xnew2 ynew = ynew2 dold = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) dnew = np.sqrt((x1 - xnew) ** 2 + (y1 - ynew) ** 2) - znew = z1 + dnew / dold * (z2 - z1) # elevation just before jump + znew = z1 + dnew / dold * ( + z2 - z1 + ) # elevation just before jump tnew = t1 + dnew / dold * (t2 - t1) Qbelow = (znew - aq.z[modellayer + 1]) / aq.Haq[layer] * Qn1 if Qbelow > Qn2: # taken out terminate = True xyztnew = [np.array([xnew, ynew, znew, tnew])] else: - znew2 = aq.z[modellayer + 1] + Qbelow / Qn2 * aq.Haq[layer] - xyztnew = [np.array([xnew, ynew, znew, tnew]), np.array([xnew, ynew, znew2, tnew])] + znew2 = ( + aq.z[modellayer + 1] + Qbelow / Qn2 * aq.Haq[layer] + ) + xyztnew = [ + np.array([xnew, ynew, znew, tnew]), + np.array([xnew, ynew, znew2, tnew]), + ] changed = True if terminate: - message = 'reached element of type linesink' + message = "reached element of type linesink" if self.label is not None: - message += ' ({lab})'.format(lab=self.label) + message += " ({lab})".format(lab=self.label) if verbose: - print('xyztnew, changed', xyztnew, changed) + print("xyztnew, changed", xyztnew, changed) return changed, terminate, xyztnew, message class LineSinkBase(LineSinkChangeTrace, Element): - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, Qls=100.0, \ - res=0, wh=1, layers=0, name='LineSinkBase', label=None, \ - addtomodel=True): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, \ - name=name, label=label) + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + Qls=100.0, + res=0, + wh=1, + layers=0, + name="LineSinkBase", + label=None, + addtomodel=True, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) self.nparam = len(self.layers) self.x1 = float(x1) self.y1 = float(y1) @@ -135,11 +185,17 @@ def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, Qls=100.0, \ self.res = float(res) self.wh = wh self.addtomodel = addtomodel - if self.addtomodel: self.model.add_element(self) + if self.addtomodel: + self.model.add_element(self) def __repr__(self): - return self.name + ' from ' + str((self.x1, self.y1)) + ' to ' + str( - (self.x2, self.y2)) + return ( + self.name + + " from " + + str((self.x1, self.y1)) + + " to " + + str((self.x2, self.y2)) + ) def initialize(self): self.xc = np.array([0.5 * (self.x1 + self.x2)]) @@ -148,40 +204,46 @@ def initialize(self): self.z1 = self.x1 + 1j * self.y1 self.z2 = self.x2 + 1j * self.y2 self.L = np.abs(self.z1 - self.z2) - self.theta_norm_out = np.arctan2(self.y2 - self.y1, - self.x2 - self.x1) + np.pi / 2 + self.theta_norm_out = ( + np.arctan2(self.y2 - self.y1, self.x2 - self.x1) + np.pi / 2 + ) self.order = 0 # This is for uniform strength only self.aq = self.model.aq.find_aquifer_data(self.xc, self.yc) - if self.addtomodel: self.aq.add_element(self) + if self.addtomodel: + self.aq.add_element(self) self.parameters = np.empty((self.nparam, 1)) self.parameters[:, 0] = self.Qls / self.L - if self.wh == 'H': + if self.wh == "H": self.whfac = self.aq.Haq[self.layers] - elif self.wh == '2H': + elif self.wh == "2H": self.whfac = 2.0 * self.aq.Haq[self.layers] elif np.isscalar(self.wh): self.whfac = self.wh * np.ones(self.nlayers) self.resfac = self.aq.Haq[self.layers] * self.res / self.whfac def potinf(self, x, y, aq=None): - '''Can be called with only one x,y value''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Can be called with only one x,y value""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: pot = np.zeros(aq.naq) - pot[:] = bessel.bessel.potbeslsho(float(x), float(y), self.z1, - self.z2, aq.lab, 0, aq.ilap, aq.naq) + pot[:] = bessel.bessel.potbeslsho( + float(x), float(y), self.z1, self.z2, aq.lab, 0, aq.ilap, aq.naq + ) rv[:] = self.aq.coef[self.layers] * pot return rv def disvecinf(self, x, y, aq=None): - '''Can be called with only one x,y value''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """Can be called with only one x,y value""" + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: qxqy = np.zeros((2, aq.naq)) - qxqy[:, :] = bessel.bessel.disbeslsho(float(x), float(y), self.z1, - self.z2, aq.lab, 0, aq.ilap, aq.naq) + qxqy[:, :] = bessel.bessel.disbeslsho( + float(x), float(y), self.z1, self.z2, aq.lab, 0, aq.ilap, aq.naq + ) rv[0] = self.aq.coef[self.layers] * qxqy[0] rv[1] = self.aq.coef[self.layers] * qxqy[1] return rv @@ -194,16 +256,40 @@ def discharge(self): def plot(self, layer=None): if (layer is None) or (layer in self.layers): - plt.plot([self.x1, self.x2], [self.y1, self.y2], 'k') + plt.plot([self.x1, self.x2], [self.y1, self.y2], "k") + class HeadLineSinkZero(LineSinkBase, HeadEquation): - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, hls=1.0, \ - res=0, wh=1, layers=0, label=None, addtomodel=True): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + hls=1.0, + res=0, + wh=1, + layers=0, + label=None, + addtomodel=True, + ): self.storeinput(inspect.currentframe()) - LineSinkBase.__init__(self, model, x1, y1, x2, y2, Qls=0, \ - res=res, wh=wh, layers=layers, - name='HeadLineSink', label=label, \ - addtomodel=addtomodel) + LineSinkBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + Qls=0, + res=res, + wh=wh, + layers=layers, + name="HeadLineSink", + label=label, + addtomodel=addtomodel, + ) self.hc = np.atleast_1d(float(hls)) self.nunknowns = self.nparam @@ -216,11 +302,25 @@ def setparams(self, sol): class LineSinkHoBase(LineSinkChangeTrace, Element): - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, \ - Qls=0.0, layers=0, order=0, name='LineSinkHoBase', \ - label=None, addtomodel=True, aq=None, zcinout=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, \ - name=name, label=label) + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + Qls=0.0, + layers=0, + order=0, + name="LineSinkHoBase", + label=None, + addtomodel=True, + aq=None, + zcinout=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) self.x1 = float(x1) self.y1 = float(y1) self.x2 = float(x2) @@ -229,38 +329,47 @@ def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, \ self.order = order self.nparam = self.nlayers * (self.order + 1) self.addtomodel = addtomodel - if addtomodel: self.model.add_element(self) + if addtomodel: + self.model.add_element(self) self.aq = aq self.zcinout = zcinout - + def __repr__(self): - return self.name + ' from ' + str((self.x1, self.y1)) + ' to ' + str( - (self.x2, self.y2)) + return ( + self.name + + " from " + + str((self.x1, self.y1)) + + " to " + + str((self.x2, self.y2)) + ) def initialize(self): self.ncp = self.order + 1 self.z1 = self.x1 + 1j * self.y1 self.z2 = self.x2 + 1j * self.y2 self.L = np.abs(self.z1 - self.z2) - #bchanged minus to plus - self.theta_norm_out = np.arctan2(self.y2 - self.y1, - self.x2 - self.x1) + np.pi / 2.0 + # bchanged minus to plus + self.theta_norm_out = ( + np.arctan2(self.y2 - self.y1, self.x2 - self.x1) + np.pi / 2.0 + ) self.cosnorm = np.cos(self.theta_norm_out) * np.ones(self.ncp) self.sinnorm = np.sin(self.theta_norm_out) * np.ones(self.ncp) # array of ncp by nlayers * (order + 1) - self.strengthinf = strengthinf_controlpoints(self.ncp, self.nlayers) + self.strengthinf = strengthinf_controlpoints(self.ncp, self.nlayers) # self.xc, self.yc = controlpoints(self.ncp, self.z1, self.z2, eps=0) if self.zcinout is not None: - self.xcin, self.ycin = controlpoints(self.ncp, self.zcinout[0], - self.zcinout[1], eps=0) - self.xcout, self.ycout = controlpoints(self.ncp, self.zcinout[2], - self.zcinout[3], eps=0) + self.xcin, self.ycin = controlpoints( + self.ncp, self.zcinout[0], self.zcinout[1], eps=0 + ) + self.xcout, self.ycout = controlpoints( + self.ncp, self.zcinout[2], self.zcinout[3], eps=0 + ) else: - self.xcin, self.ycin = controlpoints(self.ncp, self.z1, self.z2, - eps=1e-6) - self.xcout, self.ycout = controlpoints(self.ncp, self.z1, self.z2, - eps=-1e-6) + self.xcin, self.ycin = controlpoints(self.ncp, self.z1, self.z2, eps=1e-6) + self.xcout, self.ycout = controlpoints( + self.ncp, self.z1, self.z2, eps=-1e-6 + ) if self.aq is None: self.aq = self.model.aq.find_aquifer_data(self.xc[0], self.yc[0]) if self.addtomodel: @@ -270,7 +379,7 @@ def initialize(self): self.parameters[:, 0] = self.Qls / self.L def potinf(self, x, y, aq=None): - '''Can be called with only one x,y value + """Can be called with only one x,y value Returns array(nparam, self.aq.naq) with order order 0, layer[0] order 0, layer[1] @@ -278,20 +387,29 @@ def potinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] etc - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: # clever way of using a reshaped rv here potrv = rv.reshape((self.order + 1, self.nlayers, aq.naq)) pot = np.zeros((self.order + 1, aq.naq)) - pot[:, :] = bessel.bessel.potbeslsv(float(x), float(y), self.z1, - self.z2, aq.lab, self.order, aq.ilap, aq.naq) + pot[:, :] = bessel.bessel.potbeslsv( + float(x), + float(y), + self.z1, + self.z2, + aq.lab, + self.order, + aq.ilap, + aq.naq, + ) potrv[:] = self.aq.coef[self.layers] * pot[:, np.newaxis, :] return rv def disvecinf(self, x, y, aq=None): - '''Can be called with only one x,y value + """Can be called with only one x,y value Returns array(nparam, self.aq.naq) with order order 0, layer[0] order 0, layer[1] @@ -299,30 +417,41 @@ def disvecinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] etc - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: qxqyrv = rv.reshape((2, self.order + 1, self.nlayers, aq.naq)) qxqy = np.zeros((2 * (self.order + 1), aq.naq)) - qxqy[:, :] = bessel.bessel.disbeslsv(float(x), float(y), self.z1, - self.z2, aq.lab, self.order, aq.ilap, aq.naq) - qxqyrv[0, :] = self.aq.coef[self.layers] * qxqy[:self.order + 1, - np.newaxis, :] - qxqyrv[1, :] = self.aq.coef[self.layers] * qxqy[self.order + 1:, - np.newaxis, :] + qxqy[:, :] = bessel.bessel.disbeslsv( + float(x), + float(y), + self.z1, + self.z2, + aq.lab, + self.order, + aq.ilap, + aq.naq, + ) + qxqyrv[0, :] = ( + self.aq.coef[self.layers] * qxqy[: self.order + 1, np.newaxis, :] + ) + qxqyrv[1, :] = ( + self.aq.coef[self.layers] * qxqy[self.order + 1 :, np.newaxis, :] + ) return rv def plot(self, layer=None): if (layer is None) or (layer in self.layers): - plt.plot([self.x1, self.x2], [self.y1, self.y2], 'k') + plt.plot([self.x1, self.x2], [self.y1, self.y2], "k") def dischargeinf(self): # returns the unit contribution to the discharge in each layer # array of length nunknowns Qdisinf = np.zeros((self.order + 1, self.nlayers)) for n in range(self.order + 1): - Qdisinf[n] = (1 ** (n + 1) - (-1) ** (n + 1)) / (n + 1) + Qdisinf[n] = (1 ** (n + 1) - (-1) ** (n + 1)) / (n + 1) rv = self.L / 2 * Qdisinf.ravel() return rv @@ -334,12 +463,15 @@ def discharge(self): return rv def headinside(self, icp=0): - hinside = \ - self.model.head(self.xc[icp], self.yc[icp])[self.layers[0]] \ - - np.sum(self.strengthinf[icp] * self.parameters[:, 0]) \ - * self.res / self.whfac + hinside = ( + self.model.head(self.xc[icp], self.yc[icp])[self.layers[0]] + - np.sum(self.strengthinf[icp] * self.parameters[:, 0]) + * self.res + / self.whfac + ) return hinside + class HeadLineSink(LineSinkHoBase, HeadEquation): """ Create a head-specified line-sink @@ -386,14 +518,37 @@ class HeadLineSink(LineSinkHoBase, HeadEquation): """ - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, \ - hls=1.0, res=0, wh=1, order=0, layers=0, \ - label=None, name='HeadLineSink', addtomodel=True): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + hls=1.0, + res=0, + wh=1, + order=0, + layers=0, + label=None, + name="HeadLineSink", + addtomodel=True, + ): self.storeinput(inspect.currentframe()) - LineSinkHoBase.__init__(self, model, x1, y1, x2, y2, Qls=0, \ - layers=layers, order=order, - name=name, label=label, \ - addtomodel=addtomodel) + LineSinkHoBase.__init__( + self, + model, + x1, + y1, + x2, + y2, + Qls=0, + layers=layers, + order=order, + name=name, + label=label, + addtomodel=addtomodel, + ) self.hls = np.atleast_1d(hls) self.res = res self.wh = wh @@ -401,9 +556,9 @@ def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, \ def initialize(self): LineSinkHoBase.initialize(self) - if self.wh == 'H': + if self.wh == "H": self.whfac = self.aq.Haq[self.layers] - elif self.wh == '2H': + elif self.wh == "2H": self.whfac = 2.0 * self.aq.Haq[self.layers] elif np.isscalar(self.wh): self.whfac = self.wh * np.ones(self.nlayers) @@ -421,6 +576,7 @@ def initialize(self): def setparams(self, sol): self.parameters[:, 0] = sol + class LineSinkDitch(HeadLineSink): """ Class to create a line-sink for which the total discharge @@ -465,12 +621,38 @@ class LineSinkDitch(HeadLineSink): """ - def __init__(self, model, x1=-1, y1=0, x2=1, y2=0, \ - Qls=1, res=0, wh=1, order=0, layers=0, label=None, addtomodel=True): + def __init__( + self, + model, + x1=-1, + y1=0, + x2=1, + y2=0, + Qls=1, + res=0, + wh=1, + order=0, + layers=0, + label=None, + addtomodel=True, + ): self.storeinput(inspect.currentframe()) - HeadLineSink.__init__(self, model, x1, y1, x2, y2, \ - hls=0, res=res, wh=wh, order=order, layers=layers, label=label, - name='HeadLineSinkDitch', addtomodel=addtomodel) + HeadLineSink.__init__( + self, + model, + x1, + y1, + x2, + y2, + hls=0, + res=res, + wh=wh, + order=order, + layers=layers, + label=label, + name="HeadLineSinkDitch", + addtomodel=addtomodel, + ) self.Qls = Qls def initialize(self): @@ -487,7 +669,7 @@ def equation(self): for e in self.model.elementlist: if e.nunknowns > 0: if e == self: - mat[0, ieq:ieq + e.nunknowns] = self.dischargeinf() + mat[0, ieq : ieq + e.nunknowns] = self.dischargeinf() break ieq += e.nunknowns rhs[0] = self.Qls @@ -498,14 +680,26 @@ def setparams(self, sol): class LineSinkStringBase(Element): - '''Original implementation - Used for boundaries of inhomogenieities''' - def __init__(self, model, xy, closed=False, layers=0, order=0, - name='LineSinkStringBase', label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, \ - name=name, label=label) - self.xy = np.atleast_2d(xy).astype('d') - if closed: self.xy = np.vstack((self.xy, self.xy[0])) + """Original implementation + Used for boundaries of inhomogenieities""" + + def __init__( + self, + model, + xy, + closed=False, + layers=0, + order=0, + name="LineSinkStringBase", + label=None, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) + self.xy = np.atleast_2d(xy).astype("d") + if closed: + self.xy = np.vstack((self.xy, self.xy[0])) self.order = order self.aq = aq self.lslist = [] @@ -513,17 +707,27 @@ def __init__(self, model, xy, closed=False, layers=0, order=0, self.nls = len(self.x) - 1 for i in range(self.nls): if label is not None: - lslabel = label + '_' + str(i) + lslabel = label + "_" + str(i) else: lslabel = label - self.lslist.append(LineSinkHoBase(model, - x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - Qls=0.0, layers=layers, order=order, label=lslabel, - addtomodel=False, aq=aq)) + self.lslist.append( + LineSinkHoBase( + model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + Qls=0.0, + layers=layers, + order=order, + label=lslabel, + addtomodel=False, + aq=aq, + ) + ) def __repr__(self): - return self.name + ' with nodes ' + str(self.xy) + return self.name + " with nodes " + str(self.xy) def initialize(self): for ls in self.lslist: @@ -538,8 +742,9 @@ def initialize(self): self.xls[i, :] = [ls.x1, ls.x2] self.yls[i, :] = [ls.y1, ls.y2] if self.aq is None: - self.aq = self.model.aq.find_aquifer_data(self.lslist[0].xc, - self.lslist[0].yc) + self.aq = self.model.aq.find_aquifer_data( + self.lslist[0].xc, self.lslist[0].yc + ) self.parameters = np.zeros((self.nparam, 1)) # As parameters are only stored for the element not the list, # we need to combine the following @@ -552,11 +757,10 @@ def initialize(self): self.cosnorm = np.array([ls.cosnorm for ls in self.lslist]).flatten() self.sinnorm = np.array([ls.sinnorm for ls in self.lslist]).flatten() self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], self.ycin[0]) - self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], - self.ycout[0]) + self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], self.ycout[0]) def potinf(self, x, y, aq=None): - ''' + """ linesink 0, order 0, layer[0] order 0, layer[1] ... @@ -569,8 +773,9 @@ def potinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] ... - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nls, self.lslist[0].nparam, aq.naq)) for i in range(self.nls): rv[i] = self.lslist[i].potinf(x, y, aq) @@ -578,38 +783,50 @@ def potinf(self, x, y, aq=None): return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nls, self.lslist[0].nparam, aq.naq)) for i in range(self.nls): rv[:, i] = self.lslist[i].disvecinf(x, y, aq) rv.shape = (2, self.nparam, aq.naq) return rv - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, - direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 message = None for ls in self.lslist: changed, terminate, xyztnew, message = ls.changetrace( - xyzt1, xyzt2, aq, layer, ltype, modellayer, direction) + xyzt1, xyzt2, aq, layer, ltype, modellayer, direction + ) if changed or terminate: return changed, terminate, xyztnew, message return changed, terminate, xyztnew, message def plot(self, layer=None): if (layer is None) or (layer in self.layers): - plt.plot(self.x, self.y, 'k') + plt.plot(self.x, self.y, "k") + class HeadLineSinkStringOLd(LineSinkStringBase, HeadEquation): - def __init__(self, model, xy=[(-1, 0), (1, 0)], hls=0.0, \ - layers=0, order=0, label=None): + def __init__( + self, model, xy=[(-1, 0), (1, 0)], hls=0.0, layers=0, order=0, label=None + ): self.storeinput(inspect.currentframe()) - LineSinkStringBase.__init__(self, model, xy, closed=False, - layers=layers, order=order, \ - name='HeadLineSinkString', label=label, - aq=None) + LineSinkStringBase.__init__( + self, + model, + xy, + closed=False, + layers=layers, + order=order, + name="HeadLineSinkString", + label=label, + aq=None, + ) self.hls = np.atleast_1d(hls) self.model.add_element(self) @@ -620,8 +837,7 @@ def initialize(self): if len(self.hls) == 1: self.pc = self.hls * self.aq.T[self.layers] * np.ones(self.nparam) elif len(self.hls) == self.nls: # head specified at centers - self.pc = (self.hls[:, np.newaxis] * - self.aq.T[self.layers]).flatten() + self.pc = (self.hls[:, np.newaxis] * self.aq.T[self.layers]).flatten() elif len(self.hls) == 2: L = np.array([ls.L for ls in self.lslist]) Ltot = np.sum(L) @@ -630,27 +846,39 @@ def initialize(self): for i in range(1, self.nls): xp[i] = xp[i - 1] + 0.5 * (L[i - 1] + L[i]) self.hls = np.interp(xp, [0, Ltot], self.hls) - self.pc = (self.hls[:, np.newaxis] * - self.aq.T[self.layers]).flatten() + self.pc = (self.hls[:, np.newaxis] * self.aq.T[self.layers]).flatten() else: - print('Error: hls entry not supported') + print("Error: hls entry not supported") self.resfac = 0.0 def setparams(self, sol): self.parameters[:, 0] = sol + class LineSinkStringBase2(Element): - ''' + """ Alternative implementation that loops through line-sinks to build equation Has the advantage that it is easier to have different line-sinks in different layers and/or aquifers - ''' - def __init__(self, model, xy, closed=False, layers=0, order=0, - name='LineSinkStringBase', label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, \ - name=name, label=label) - self.xy = np.atleast_2d(xy).astype('d') - if closed: self.xy = np.vstack((self.xy, self.xy[0])) + """ + + def __init__( + self, + model, + xy, + closed=False, + layers=0, + order=0, + name="LineSinkStringBase", + label=None, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) + self.xy = np.atleast_2d(xy).astype("d") + if closed: + self.xy = np.vstack((self.xy, self.xy[0])) self.order = order # same for all segments in string self.lslist = [] self.x, self.y = self.xy[:, 0], self.xy[:, 1] @@ -659,12 +887,13 @@ def __init__(self, model, xy, closed=False, layers=0, order=0, if len(self.layers) == self.nls: self.layers = self.layers[:, np.newaxis] else: # entire string in these layers - self.layers = self.layers * \ - np.ones((self.nls, len(self.layers)), dtype='int') + self.layers = self.layers * np.ones( + (self.nls, len(self.layers)), dtype="int" + ) self.nlayers = len(self.layers[0]) def __repr__(self): - return self.name + ' with nodes ' + str(self.xy) + return self.name + " with nodes " + str(self.xy) def initialize(self): for ls in self.lslist: @@ -676,14 +905,14 @@ def initialize(self): for aq in self.aq: aq.add_element(self) # Same order for all elements in string - #self.ncp = sum(ls.ncp for ls in self.lslist) + # self.ncp = sum(ls.ncp for ls in self.lslist) self.nparam = sum(ls.nparam for ls in self.lslist) self.nunknowns = self.nparam # where are self.xls and self.yls used? self.xls and self.yls removed self.parameters = np.zeros((self.nparam, 1)) def potinf(self, x, y, aq=None): - ''' + """ linesink 0, order 0, layer[0] order 0, layer[1] ... @@ -696,8 +925,9 @@ def potinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] ... - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nls, self.lslist[0].nparam, aq.naq)) if aq in self.aq: for i, ls in enumerate(self.lslist): @@ -706,7 +936,8 @@ def potinf(self, x, y, aq=None): return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nls, self.lslist[0].nparam, aq.naq)) if aq in self.aq: for i, ls in enumerate(self.lslist): @@ -721,8 +952,7 @@ def dischargeinf(self): return rv.ravel() def discharge(self): - """Discharge of the element in each layer - """ + """Discharge of the element in each layer""" rv = np.zeros(self.aq[0].naq) Qls = self.parameters[:, 0] * self.dischargeinf() @@ -730,26 +960,28 @@ def discharge(self): Qls = np.sum(Qls, 2) for i, q in enumerate(Qls): rv[self.layers[i]] += q - #rv[self.layers] = np.sum(Qls.reshape(self.nls * (self.order + 1), self.nlayers), 0) + # rv[self.layers] = np.sum(Qls.reshape(self.nls * (self.order + 1), self.nlayers), 0) return rv - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, - direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 message = None for ls in self.lslist: changed, terminate, xyztnew, message = ls.changetrace( - xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, - hstepmax) + xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ) if changed or terminate: return changed, terminate, xyztnew, message return changed, terminate, xyztnew, message def plot(self, layer=None): if (layer is None) or (layer in self.layers): - plt.plot(self.x, self.y, 'k') + plt.plot(self.x, self.y, "k") + class HeadLineSinkString(LineSinkStringBase2): """ @@ -774,11 +1006,11 @@ class HeadLineSinkString(LineSinkStringBase2): resistance of line-sink wh : scalar or str distance over which water enters line-sink - if 'H': (default) distance is equal to the thickness of the aquifer + if 'H': (default) distance is equal to the thickness of the aquifer layer (when flow comes mainly from one side) - if '2H': distance is twice the thickness of the aquifer layer (when + if '2H': distance is twice the thickness of the aquifer layer (when flow comes from both sides) - if scalar: the width of the stream that partially penetrates the + if scalar: the width of the stream that partially penetrates the aquifer layer order : int (default is 0) order of all line-sinks in string @@ -795,49 +1027,78 @@ class HeadLineSinkString(LineSinkStringBase2): """ - def __init__(self, model, xy=[(-1, 0), (1, 0)], hls=0, - res=0, wh=1, order=0, layers=0, label=None, - name='HeadLineSinkString'): + def __init__( + self, + model, + xy=[(-1, 0), (1, 0)], + hls=0, + res=0, + wh=1, + order=0, + layers=0, + label=None, + name="HeadLineSinkString", + ): self.storeinput(inspect.currentframe()) - LineSinkStringBase2.__init__(self, model, xy, closed=False, - layers=layers, order=order, - name=name, label=label, - aq=None) + LineSinkStringBase2.__init__( + self, + model, + xy, + closed=False, + layers=layers, + order=order, + name=name, + label=label, + aq=None, + ) self.hls = np.atleast_1d(hls) self.res = res self.wh = wh self.model.add_element(self) - #TO DO: TEST FOR DIFFERENT AQUIFERS AND LAYERS + # TO DO: TEST FOR DIFFERENT AQUIFERS AND LAYERS def initialize(self): if len(self.hls) == 1: # one value self.hls = self.hls * np.ones(self.nls + 1) # at all nodes elif len(self.hls) == 2: # values at beginning and end - L = np.sqrt((self.x[1:] - self.x[:-1]) ** 2 - + (self.y[1:] - self.y[:-1]) ** 2) + L = np.sqrt( + (self.x[1:] - self.x[:-1]) ** 2 + (self.y[1:] - self.y[:-1]) ** 2 + ) s = np.hstack((0, np.cumsum(L))) self.hls = np.interp(s, [0, s[-1]], self.hls) elif len(self.hls) == len(self.x): # nodes may contain nan values if np.isnan(self.hls).any(): - L = np.sqrt((self.x[1:] - self.x[:-1]) ** 2 - + (self.y[1:] - self.y[:-1]) ** 2) + L = np.sqrt( + (self.x[1:] - self.x[:-1]) ** 2 + (self.y[1:] - self.y[:-1]) ** 2 + ) s = np.hstack((0, np.cumsum(L))) - self.hls = np.interp(s, s[~np.isnan(self.hls)], - self.hls[~np.isnan(self.hls)]) + self.hls = np.interp( + s, s[~np.isnan(self.hls)], self.hls[~np.isnan(self.hls)] + ) else: - print('Error: hls entry not supported in HeadLineSinkString') + print("Error: hls entry not supported in HeadLineSinkString") self.lslist = [] # start with empty list for i in range(self.nls): if self.label is not None: - lslabel = self.label + '_' + str(i) + lslabel = self.label + "_" + str(i) else: lslabel = self.label self.lslist.append( - HeadLineSink(self.model, x1=self.x[i], y1=self.y[i], - x2=self.x[i + 1], y2=self.y[i + 1], - hls=self.hls[i:i + 2], res=self.res, - wh=self.wh, layers=self.layers[i], - order=self.order, label=lslabel, addtomodel=False)) + HeadLineSink( + self.model, + x1=self.x[i], + y1=self.y[i], + x2=self.x[i + 1], + y2=self.y[i + 1], + hls=self.hls[i : i + 2], + res=self.res, + wh=self.wh, + layers=self.layers[i], + order=self.order, + label=lslabel, + addtomodel=False, + ) + ) LineSinkStringBase2.initialize(self) def setparams(self, sol): @@ -850,8 +1111,8 @@ def equation(self): for ls in self.lslist: matls, rhsls = ls.equation() neq = len(rhsls) - mat[ieq:ieq + neq] = matls - rhs[ieq:ieq + neq] = rhsls + mat[ieq : ieq + neq] = matls + rhs[ieq : ieq + neq] = rhsls ieq += neq # fix to include resistance # this is not pretty but works @@ -866,11 +1127,14 @@ def equation(self): irow = 0 for ls in self.lslist: for icp in range(ls.ncp): - mat[irow:irow+ ls.nlayers, jcol:jcol + ls.nunknowns] -= ls.resfac[icp] + mat[irow : irow + ls.nlayers, jcol : jcol + ls.nunknowns] -= ls.resfac[ + icp + ] irow += ls.nlayers jcol += ls.nunknowns return mat, rhs + class LineSinkDitchString(HeadLineSinkString): """ Class to create a string of LineSinkDitch elements for which the @@ -910,12 +1174,30 @@ class LineSinkDitchString(HeadLineSinkString): """ - def __init__(self, model, xy=[(-1, 0), (1, 0)], \ - Qls=1, res=0, wh=1, order=0, layers=0, label=None): + def __init__( + self, + model, + xy=[(-1, 0), (1, 0)], + Qls=1, + res=0, + wh=1, + order=0, + layers=0, + label=None, + ): self.storeinput(inspect.currentframe()) - HeadLineSinkString.__init__(self, model, xy=xy, hls=0, \ - res=res, wh=wh, order=order, layers=layers, label=label, - name='LineSinkDitchString') + HeadLineSinkString.__init__( + self, + model, + xy=xy, + hls=0, + res=res, + wh=wh, + order=order, + layers=layers, + label=label, + name="LineSinkDitchString", + ) self.Qls = Qls def initialize(self): @@ -932,7 +1214,7 @@ def equation(self): for e in self.model.elementlist: if e.nunknowns > 0: if e == self: - mat[0, ieq:ieq + self.nunknowns] = self.dischargeinf() + mat[0, ieq : ieq + self.nunknowns] = self.dischargeinf() break ieq += e.nunknowns rhs[0] = self.Qls @@ -940,32 +1222,43 @@ def equation(self): def setparams(self, sol): self.parameters[:, 0] = sol - + + class LineSinkContainer(Element): - ''' + """ Container class for bunch of line-sinks Required attributes: lslist: list of line-sinks nls: total number of line-sinks - ''' - def __init__(self, model, layers=0, order=0, - name='LineSinkStringContainer', label=None, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, \ - name=name, label=label) + """ + + def __init__( + self, + model, + layers=0, + order=0, + name="LineSinkStringContainer", + label=None, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) self.order = order -# self.xy = np.atleast_2d(xy).astype('d') -# if closed: self.xy = np.vstack((self.xy, self.xy[0])) -# self.order = order # same for all segments in string -# self.lslist = [] -# self.x, self.y = self.xy[:, 0], self.xy[:, 1] -# self.nls = len(self.x) - 1 -# if self.layers.ndim == 1: -# if len(self.layers) == self.nls: -# self.layers = self.layers[:, np.newaxis] -# else: # entire string in these layers -# self.layers = self.layers * \ -# np.ones((self.nls, len(self.layers)), dtype='int') -# self.nlayers = len(self.layers[0]) + + # self.xy = np.atleast_2d(xy).astype('d') + # if closed: self.xy = np.vstack((self.xy, self.xy[0])) + # self.order = order # same for all segments in string + # self.lslist = [] + # self.x, self.y = self.xy[:, 0], self.xy[:, 1] + # self.nls = len(self.x) - 1 + # if self.layers.ndim == 1: + # if len(self.layers) == self.nls: + # self.layers = self.layers[:, np.newaxis] + # else: # entire string in these layers + # self.layers = self.layers * \ + # np.ones((self.nls, len(self.layers)), dtype='int') + # self.nlayers = len(self.layers[0]) def __repr__(self): return self.name @@ -987,7 +1280,7 @@ def initialize(self): self.parameters = np.zeros((self.nparam, 1)) def potinf(self, x, y, aq=None): - ''' + """ linesink 0, order 0, layer[0] order 0, layer[1] ... @@ -1000,8 +1293,9 @@ def potinf(self, x, y, aq=None): order 1, layer[0] order 1, layer[1] ... - ''' - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + """ + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nls, self.lslist[0].nparam, aq.naq)) if aq in self.aq: for i, ls in enumerate(self.lslist): @@ -1010,7 +1304,8 @@ def potinf(self, x, y, aq=None): return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nls, self.lslist[0].nparam, aq.naq)) if aq in self.aq: for i, ls in enumerate(self.lslist): @@ -1025,8 +1320,7 @@ def dischargeinf(self): return rv.ravel() def discharge(self): - """Discharge of the element in each layer - """ + """Discharge of the element in each layer""" # TBD: it is unclear what this function does. shouldn't it return # values only for the layers where the element is screened? rv = np.zeros(self.aq[0].naq) @@ -1035,19 +1329,20 @@ def discharge(self): Qls = np.sum(Qls, 2) for i, q in enumerate(Qls): rv[self.layers[i]] += q - #rv[self.layers] = np.sum(Qls.reshape(self.nls * (self.order + 1), self.nlayers), 0) + # rv[self.layers] = np.sum(Qls.reshape(self.nls * (self.order + 1), self.nlayers), 0) return rv - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, - direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 message = None for ls in self.lslist: changed, terminate, xyztnew, message = ls.changetrace( - xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, - hstepmax) + xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ) if changed or terminate: return changed, terminate, xyztnew, message return changed, terminate, xyztnew, message @@ -1055,8 +1350,9 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, def plot(self, layer=None): if (layer is None) or (layer in self.layers): for i in range(len(self.xls)): - plt.plot(self.xls[i], self.yls[i], 'k') - + plt.plot(self.xls[i], self.yls[i], "k") + + class HeadLineSinkContainer(LineSinkContainer): """ Class to create a container of head-specified line-sinks @@ -1068,18 +1364,18 @@ class HeadLineSinkContainer(LineSinkContainer): model : Model object Model to which the element is added xydict : dictionary - dictionary with lists or arrays of (x,y) pairs of coordinates of + dictionary with lists or arrays of (x,y) pairs of coordinates of end-points of line-sinks that are stringed together hls : scalar res : scalar (default is 0) resistance of line-sink wh : scalar or str distance over which water enters line-sink - if 'H': (default) distance is equal to the thickness of the aquifer + if 'H': (default) distance is equal to the thickness of the aquifer layer (when flow comes mainly from one side) - if '2H': distance is twice the thickness of the aquifer layer (when + if '2H': distance is twice the thickness of the aquifer layer (when flow comes from both sides) - if scalar: the width of the stream that partially penetrates the + if scalar: the width of the stream that partially penetrates the aquifer layer order : int (default is 0) order of all line-sinks in string @@ -1096,44 +1392,63 @@ class HeadLineSinkContainer(LineSinkContainer): """ - def __init__(self, model, xydict={0: [(-1, 0), (1, 0)]}, hls=0, - res=0, wh=1, order=0, laydict={0: 0}, label=None, - name='HeadLineSinkContainer'): + def __init__( + self, + model, + xydict={0: [(-1, 0), (1, 0)]}, + hls=0, + res=0, + wh=1, + order=0, + laydict={0: 0}, + label=None, + name="HeadLineSinkContainer", + ): self.storeinput(inspect.currentframe()) - LineSinkContainer.__init__(self, model, layers=0, - order=order, name=name, label=label, - aq=None) + LineSinkContainer.__init__( + self, model, layers=0, order=order, name=name, label=label, aq=None + ) self.xydict = xydict self.hls = hls self.laydict = laydict self.res = res self.wh = wh self.model.add_element(self) - #TO DO: TEST FOR DIFFERENT AQUIFERS AND LAYERS + # TO DO: TEST FOR DIFFERENT AQUIFERS AND LAYERS def initialize(self): self.lslist = [] - self.xls = [] # used for layout + self.xls = [] # used for layout self.yls = [] for key in self.xydict.keys(): xy = np.atleast_1d(self.xydict[key]) layers = np.atleast_1d(self.laydict[key]) if len(layers) == 1: - layers = layers * np.ones(len(xy) - 1, dtype='int') + layers = layers * np.ones(len(xy) - 1, dtype="int") self.xls.append(xy[:, 0]) - self.yls.append(xy[:, 1]) + self.yls.append(xy[:, 1]) for i in range(len(xy) - 1): x1, y1 = xy[i] x2, y2 = xy[i + 1] - ls = HeadLineSink(self.model, x1=x1, y1=y1, x2=x2, y2=y2, - hls=self.hls, res=self.res, wh=self.wh, - layers=layers[i], order=self.order, - label=None, addtomodel=False) + ls = HeadLineSink( + self.model, + x1=x1, + y1=y1, + x2=x2, + y2=y2, + hls=self.hls, + res=self.res, + wh=self.wh, + layers=layers[i], + order=self.order, + label=None, + addtomodel=False, + ) self.lslist.append(ls) self.nls = len(self.lslist) for i in range(self.nls): if self.label is not None: - lslabel = self.label + '_' + str(i) + lslabel = self.label + "_" + str(i) else: lslabel = self.label LineSinkContainer.initialize(self) @@ -1148,8 +1463,8 @@ def equation(self): for ls in self.lslist: matls, rhsls = ls.equation() neq = len(rhsls) - mat[ieq:ieq + neq] = matls - rhs[ieq:ieq + neq] = rhsls + mat[ieq : ieq + neq] = matls + rhs[ieq : ieq + neq] = rhsls ieq += neq # fix to include resistance # this is not pretty but works @@ -1164,7 +1479,9 @@ def equation(self): irow = 0 for ls in self.lslist: for icp in range(ls.ncp): - mat[irow:irow+ ls.nlayers, jcol:jcol + ls.nunknowns] -= ls.resfac[icp] + mat[irow : irow + ls.nlayers, jcol : jcol + ls.nunknowns] -= ls.resfac[ + icp + ] irow += ls.nlayers jcol += ls.nunknowns return mat, rhs diff --git a/timml/linesink1d.py b/timml/linesink1d.py index fff3760f..173182a4 100644 --- a/timml/linesink1d.py +++ b/timml/linesink1d.py @@ -1,30 +1,49 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np + from .element import Element -from .equation import HeadEquation, MscreenWellEquation, HeadDiffEquation, DisvecDiffEquation +from .equation import ( + DisvecDiffEquation, + HeadDiffEquation, + HeadEquation, + MscreenWellEquation, +) -__all__ = ['LineSink1D', 'HeadLineSink1D'] +__all__ = ["LineSink1D", "HeadLineSink1D"] -class LineSink1DBase(Element): - def __init__(self, model, xls, sigls=1, layers=0, name="LineSink1DBase", label=None, - addtomodel=True, res=0, wh=1, aq=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, - name=name, label=label) +class LineSink1DBase(Element): + def __init__( + self, + model, + xls, + sigls=1, + layers=0, + name="LineSink1DBase", + label=None, + addtomodel=True, + res=0, + wh=1, + aq=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) self.xls = float(xls) self.sigls = np.atleast_1d(sigls) self.res = float(res) self.wh = wh self.aq = aq self.addtomodel = addtomodel - if self.addtomodel: + if self.addtomodel: self.model.add_element(self) self.nparam = self.nlayers self.tiny = 1e-12 - + def __repr__(self): return self.name + " at " + str(self.xls) + " in layers: " + str(self.layers) - + def initialize(self): self.xc = np.array([self.xls]) self.yc = np.zeros(1) @@ -39,72 +58,73 @@ def initialize(self): self.theta_norm_out = np.zeros(1) self.cosnorm = np.cos(self.theta_norm_out) * np.ones(self.ncp) self.sinnorm = np.sin(self.theta_norm_out) * np.ones(self.ncp) - if self.wh == 'H': + if self.wh == "H": self.wh = self.aq.Haq[self.layers] - elif self.wh == '2H': + elif self.wh == "2H": self.wh = 2.0 * self.aq.Haq[self.layers] elif np.isscalar(self.wh): self.wh = self.wh * np.ones(self.nlayers) self.resfac = self.aq.Haq[self.layers] * self.res / self.wh def potinf(self, x, y, aq=None): - if aq is None: + if aq is None: aq = self.model.aq.find_aquifer_data(x, 0) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: pot = np.zeros(aq.naq) if aq.ilap: - if x - self.xls < 0.: + if x - self.xls < 0.0: pot[0] = -0.5 * (x - self.xls - 1) # so that pot = 0.5 at x=xls pot[1:] = -0.5 * aq.lab[1:] * np.exp((x - self.xls) / aq.lab[1:]) - elif x - self.xls >= 0.: + elif x - self.xls >= 0.0: pot[0] = 0.5 * (x - self.xls + 1) pot[1:] = -0.5 * aq.lab[1:] * np.exp(-(x - self.xls) / aq.lab[1:]) else: - if x - self.xls < 0.: + if x - self.xls < 0.0: pot[:] = -0.5 * aq.lab * np.exp((x - self.xls) / aq.lab) - elif x - self.xls >= 0.: + elif x - self.xls >= 0.0: pot[:] = -0.5 * aq.lab * np.exp(-(x - self.xls) / aq.lab) rv[:] = self.aq.coef[self.layers] * pot return rv - + def disvecinf(self, x, y, aq=None): - if aq is None: + if aq is None: aq = self.model.aq.find_aquifer_data(x, 0) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: qx = np.zeros(aq.naq) if aq.ilap: - if x - self.xls < 0.: + if x - self.xls < 0.0: qx[0] = 0.5 qx[1:] = 0.5 * np.exp((x - self.xls) / aq.lab[1:]) - elif x - self.xls >= 0.: + elif x - self.xls >= 0.0: qx[0] = -0.5 qx[1:] = -0.5 * np.exp(-(x - self.xls) / aq.lab[1:]) else: - if x - self.xls < 0.: + if x - self.xls < 0.0: qx[:] = 0.5 * np.exp((x - self.xls) / aq.lab) - elif x - self.xls >= 0.: + elif x - self.xls >= 0.0: qx[:] = -0.5 * np.exp(-(x - self.xls) / aq.lab) rv[0] = self.aq.coef[self.layers] * qx return rv - + def discharge(self): """Discharge per unit length""" Q = np.zeros(self.aq.naq) Q[self.layers] = self.parameters[:, 0] return Q - + + class LineSink1D(LineSink1DBase, MscreenWellEquation): """ Create an infinitely long line-sink with a given discharge per unit length. In case the line-sink is screened in multiple layers, the discharge is distributed over the layers such that the head inside the line-sink is constant in all layers. - + Parameters ---------- - + model : Model object Model to which the element is added xls : scalar @@ -121,18 +141,27 @@ class LineSink1D(LineSink1DBase, MscreenWellEquation): layers : scalar, list or array layer(s) in which element is placed if scalar: element is placed in this layer - if list or array: element is placed in all these layers + if list or array: element is placed in all these layers label: str or None label of element """ - - def __init__(self, model, xls=0, sigls=1, \ - layers=0, label=None): + + def __init__(self, model, xls=0, sigls=1, layers=0, label=None): self.storeinput(inspect.currentframe()) - LineSink1DBase.__init__(self, model, xls, sigls=sigls, layers=layers, \ - name="Linesink1D", label=label, \ - addtomodel=True, res=0, wh=1, aq=None) + LineSink1DBase.__init__( + self, + model, + xls, + sigls=sigls, + layers=layers, + name="Linesink1D", + label=label, + addtomodel=True, + res=0, + wh=1, + aq=None, + ) self.Qc = float(sigls) if self.nlayers == 1: self.nunknowns = 0 @@ -144,14 +173,15 @@ def initialize(self): def setparams(self, sol): self.parameters[:, 0] = sol - + + class HeadLineSink1D(LineSink1DBase, HeadEquation): """ Create an infinitely long line-sink with a given head. - + Parameters ---------- - + model : Model object Model to which the element is added xls : scalar @@ -168,18 +198,27 @@ class HeadLineSink1D(LineSink1DBase, HeadEquation): layers : scalar, list or array layer(s) in which element is placed if scalar: element is placed in this layer - if list or array: element is placed in all these layers + if list or array: element is placed in all these layers label: str or None label of element """ - - def __init__(self, model, xls=0, hls=1, \ - res=0, wh=1, layers=0, label=None): + + def __init__(self, model, xls=0, hls=1, res=0, wh=1, layers=0, label=None): self.storeinput(inspect.currentframe()) - LineSink1DBase.__init__(self, model, xls, sigls=0, layers=layers, \ - name="HeadLinesink1D", label=label, \ - addtomodel=True, res=res, wh=wh, aq=None) + LineSink1DBase.__init__( + self, + model, + xls, + sigls=0, + layers=layers, + name="HeadLinesink1D", + label=label, + addtomodel=True, + res=res, + wh=wh, + aq=None, + ) self.hc = np.atleast_1d(hls) * np.ones(self.nlayers) self.nunknowns = self.nparam @@ -189,21 +228,28 @@ def initialize(self): def setparams(self, sol): self.parameters[:, 0] = sol - + + class HeadDiffLineSink1D(LineSink1DBase, HeadDiffEquation): - """HeadDiffLineSink1D for left side (xcout) - """ - - def __init__(self, model, xls, label=None, - aq=None, aqin=None, aqout=None): - LineSink1DBase.__init__(self, model, xls, sigls=0, - layers=np.arange(model.aq.naq), label=label, - name='HeadDiffLineSink1D', addtomodel=True, aq=aq) + """HeadDiffLineSink1D for left side (xcout)""" + + def __init__(self, model, xls, label=None, aq=None, aqin=None, aqout=None): + LineSink1DBase.__init__( + self, + model, + xls, + sigls=0, + layers=np.arange(model.aq.naq), + label=label, + name="HeadDiffLineSink1D", + addtomodel=True, + aq=aq, + ) self.inhomelement = True self.nunknowns = self.nparam self.aqin = aqin self.aqout = aqout - + def initialize(self): LineSink1DBase.initialize(self) self.xcout = self.xc + self.tiny * abs(self.xc) + self.tiny @@ -214,24 +260,31 @@ def initialize(self): self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], 0) if self.aqin is None: self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], 0) - + def setparams(self, sol): self.parameters[:, 0] = sol - + + class FluxDiffLineSink1D(LineSink1DBase, DisvecDiffEquation): - """HeadDiffLineSink1D for left side (xcout) - """ - - def __init__(self, model, xls, label=None, - aq=None, aqin=None, aqout=None): - LineSink1DBase.__init__(self, model, xls, sigls=0, - layers=np.arange(model.aq.naq), label=label, - name='FluxDiffLineSink1D', addtomodel=True, aq=aq) + """HeadDiffLineSink1D for left side (xcout)""" + + def __init__(self, model, xls, label=None, aq=None, aqin=None, aqout=None): + LineSink1DBase.__init__( + self, + model, + xls, + sigls=0, + layers=np.arange(model.aq.naq), + label=label, + name="FluxDiffLineSink1D", + addtomodel=True, + aq=aq, + ) self.inhomelement = True self.nunknowns = self.nparam self.aqin = aqin self.aqout = aqout - + def initialize(self): LineSink1DBase.initialize(self) self.xcout = self.xc - self.tiny * abs(self.xc) - self.tiny @@ -242,6 +295,6 @@ def initialize(self): self.aqout = self.model.aq.find_aquifer_data(self.xcout[0], 0) if self.aqin is None: self.aqin = self.model.aq.find_aquifer_data(self.xcin[0], 0) - + def setparams(self, sol): self.parameters[:, 0] = sol diff --git a/timml/model.py b/timml/model.py index 3ad7e136..b3df372a 100644 --- a/timml/model.py +++ b/timml/model.py @@ -3,17 +3,20 @@ """ -import numpy as np -import sys import inspect # Used for storing the input +import multiprocessing as mp +import sys + +import numpy as np +from scipy.integrate import quad_vec + from .aquifer import Aquifer -from .aquifer_parameters import param_maq, param_3d +from .aquifer_parameters import param_3d, param_maq from .constant import ConstantStar from .util import PlotTim -from scipy.integrate import quad_vec -import multiprocessing as mp -__all__ = ['Model', 'ModelMaq', 'Model3D'] +__all__ = ["Model", "ModelMaq", "Model3D"] + class Model(PlotTim): """ @@ -21,7 +24,7 @@ class Model(PlotTim): sequence of aquifer layers and leaky layers. Use ModelMaq for regular sequence of aquifers and leaky layers. Use Model3D for multi-layer model of a single aquifer - + Parameters ---------- kaq : array @@ -39,16 +42,16 @@ class Model(PlotTim): array indicating for each layer whether it is 'a' aquifer layer 'l' leaky layer - + """ - + def __init__(self, kaq, c, z, npor, ltype): # All input variables are numpy arrays # That should be checked outside this function self.elementlist = [] self.elementdict = {} # only elements that have a label self.aq = Aquifer(self, kaq, c, z, npor, ltype) - self.modelname = 'ml' # Used for writing out input + self.modelname = "ml" # Used for writing out input def initialize(self): # remove inhomogeneity elements (they are added again) @@ -59,40 +62,43 @@ def initialize(self): def add_element(self, e): self.elementlist.append(e) - if e.label is not None: self.elementdict[e.label] = e + if e.label is not None: + self.elementdict[e.label] = e def remove_element(self, e): - """Remove element `e` from model - """ - - if e.label is not None: self.elementdict.pop(e.label) + """Remove element `e` from model""" + + if e.label is not None: + self.elementdict.pop(e.label) self.elementlist.remove(e) def storeinput(self, frame): self.inputargs, _, _, self.inputvalues = inspect.getargvalues(frame) def potential(self, x, y, aq=None): - if aq is None: aq = self.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.aq.find_aquifer_data(x, y) pot = np.zeros(aq.naq) for e in aq.elementlist: pot += e.potential(x, y, aq) rv = np.sum(pot * aq.eigvec, 1) - if aq.ltype[0] == 'l': + if aq.ltype[0] == "l": # potential for head above leaky layer rv += aq.constantstar.potstar return rv def disvec(self, x, y, aq=None): """Discharge vector at `x`, `y` - + Returns ------- - + qxqy : array size (2, naq) first row is Qx in each aquifer layer, second row is Qy """ - - if aq is None: aq = self.aq.find_aquifer_data(x, y) + + if aq is None: + aq = self.aq.find_aquifer_data(x, y) rv = np.zeros((2, aq.naq)) for e in aq.elementlist: rv += e.disvec(x, y, aq) @@ -172,25 +178,27 @@ def intnormflux(self, x1, y1, x2, y2, method="legendre", ndeg=10): return L * qn / 2.0 def qztop(self, x, y, aq=None): - if aq is None: aq = self.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.aq.find_aquifer_data(x, y) rv = 0.0 - if aq.ltype[0] == 'a': # otherwise recharge cannot be added + if aq.ltype[0] == "a": # otherwise recharge cannot be added for e in aq.elementlist: rv += e.qztop(x, y, aq) return rv def head(self, x, y, layers=None, aq=None): """Head at `x`, `y` - + Returns ------- - + h : array length `naq` or `len(layers)` - head in all `layers` (if not `None`), + head in all `layers` (if not `None`), or all layers of aquifer (otherwise) """ - - if aq is None: aq = self.aq.find_aquifer_data(x, y) + + if aq is None: + aq = self.aq.find_aquifer_data(x, y) rv = self.potential(x, y, aq) / aq.T if layers is None: return rv @@ -199,7 +207,7 @@ def head(self, x, y, layers=None, aq=None): def headgrid(self, xg, yg, layers=None, printrow=False): """Grid of heads - + Parameters ---------- xg : array @@ -210,18 +218,18 @@ def headgrid(self, xg, yg, layers=None, printrow=False): layers for which grid is returned printrow : boolean, optional prints dot to screen for each row of grid if set to `True` - + Returns ------- h : array size `nlayers, ny, nx` - + See also -------- - + :func:`~timml.model.Model.headgrid2` """ - + nx, ny = len(xg), len(yg) if layers is None: Nlayers = self.aq.find_aquifer_data(xg[0], yg[0]).naq @@ -230,44 +238,44 @@ def headgrid(self, xg, yg, layers=None, printrow=False): h = np.empty((Nlayers, ny, nx)) for j in range(ny): if printrow: - print('.', end='', flush=True) + print(".", end="", flush=True) for i in range(nx): h[:, j, i] = self.head(xg[i], yg[j], layers) if printrow: - print('', flush=True) + print("", flush=True) return h def headgrid2(self, x1, x2, nx, y1, y2, ny, layers=None, printrow=False): """Grid of heads - + Parameters ---------- - x1, x2, nx : + x1, x2, nx : x values are generated as linspace(x1, x2, nx) - y1, y2, ny : + y1, y2, ny : y values are generated as linspace(y1, y2, ny) layers : integer, list or array, optional layers for which grid is returned printrow : boolean, optional prints dot to screen for each row of grid if set to `True` - + Returns ------- h : array size `nlayers, ny, nx` - + See also -------- - + :func:`~timml.model.Model.headgrid` - + """ - + xg, yg = np.linspace(x1, x2, nx), np.linspace(y1, y2, ny) return self.headgrid(xg, yg, layers=layers, printrow=printrow) def headalongline(self, x, y, layers=None): """Head along line or curve - + Parameters ---------- x : array @@ -276,13 +284,13 @@ def headalongline(self, x, y, layers=None): y values of line layers : integer, list or array, optional layers for which grid is returned - + Returns ------- h : array size `nlayers, nx` """ - + xg, yg = np.atleast_1d(x), np.atleast_1d(y) if layers is None: Nlayers = self.aq.find_aquifer_data(xg[0], yg[0]).naq @@ -295,11 +303,11 @@ def headalongline(self, x, y, layers=None): for i in range(nx): h[:, i] = self.head(xg[i], yg[i], layers) return h - + def disvecalongline(self, x, y, layers=None): - '''Returns Qx[Nlayers,len(x)], Qy[Nlayers,len(x)] + """Returns Qx[Nlayers,len(x)], Qy[Nlayers,len(x)] Assumes same number of layers for each x and y - layers may be None or list of layers for which head is computed''' + layers may be None or list of layers for which head is computed""" xg, yg = np.atleast_1d(x), np.atleast_1d(y) if layers is None: nlayers = self.aq.find_aquifer_data(xg[0], yg[0]).naq @@ -313,25 +321,26 @@ def disvecalongline(self, x, y, layers=None): for i in range(nx): Qx[:, i], Qy[:, 1] = self.disvec(xg[i], yg[i], layers) return Qx, Qy - -# def disvec_direction(self, s, x1, y1, cdirection): -# pass -# -# def discharge_across_line(self, x1, y1, x2, y2, layers=None): -# if layers is None: -# nlayers = self.aq.find_aquifer_data(x1, y1).naq -# else: -# nlayers = len(np.atleast_1d(layers)) -# z1 = x1 + y1 * 1j -# z2 = x2 + y2 * 1j -# normvec = (z2 - z1) / np.abs(z2 - z1) * np.exp(-np.pi * 1j / 2) -# disvec = self.disvec(xg[i], yg[i], layers) - + + # def disvec_direction(self, s, x1, y1, cdirection): + # pass + # + # def discharge_across_line(self, x1, y1, x2, y2, layers=None): + # if layers is None: + # nlayers = self.aq.find_aquifer_data(x1, y1).naq + # else: + # nlayers = len(np.atleast_1d(layers)) + # z1 = x1 + y1 * 1j + # z2 = x2 + y2 * 1j + # normvec = (z2 - z1) / np.abs(z2 - z1) * np.exp(-np.pi * 1j / 2) + # disvec = self.disvec(xg[i], yg[i], layers) + def velocity(self, x, y, z): return self.velocomp(x, y, z) - + def velocomp(self, x, y, z, aq=None, layer_ltype=None): - if aq is None: aq = self.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.aq.find_aquifer_data(x, y) assert z <= aq.z[0] and z >= aq.z[-1], "z value not inside aquifer" if layer_ltype is None: layer, ltype, dummy = aq.findlayer(z) @@ -341,9 +350,9 @@ def velocomp(self, x, y, z, aq=None, layer_ltype=None): # qz between aquifer layers qzlayer = np.zeros(aq.naq + 1) qzlayer[1:-1] = (h[1:] - h[:-1]) / aq.c[1:] - if aq.ltype[0] == 'l': + if aq.ltype[0] == "l": qzlayer[0] = (h[0] - aq.hstar) / aq.c[0] - if ltype == 'l': + if ltype == "l": vz = qzlayer[layer] / aq.nporll[layer] vx = 0 vy = 0 @@ -351,78 +360,99 @@ def velocomp(self, x, y, z, aq=None, layer_ltype=None): qzbot = qzlayer[layer + 1] qztop = qzlayer[layer] if layer == 0: - qztop += self.qztop(x, y) - vz = (qzbot + (z - aq.zaqbot[layer]) / aq.Haq[layer] * \ - (qztop - qzbot)) / aq.nporaq[layer] + qztop += self.qztop(x, y) + vz = ( + qzbot + (z - aq.zaqbot[layer]) / aq.Haq[layer] * (qztop - qzbot) + ) / aq.nporaq[layer] qx, qy = self.disvec(x, y, aq=aq) vx = qx[layer] / (aq.Haq[layer] * aq.nporaq[layer]) vy = qy[layer] / (aq.Haq[layer] * aq.nporaq[layer]) return np.array([vx, vy, vz]) - + def solve(self, printmat=0, sendback=0, silent=False): - '''Compute solution''' + """Compute solution""" # Initialize elements self.initialize() # Compute number of equations self.neq = np.sum([e.nunknowns for e in self.elementlist]) - if self.neq == 0: return + if self.neq == 0: + return if silent is False: - print('Number of elements, Number of equations:', len( - self.elementlist), ',', self.neq) + print( + "Number of elements, Number of equations:", + len(self.elementlist), + ",", + self.neq, + ) if self.neq == 0: - if silent is False: print('No unknowns. Solution complete') + if silent is False: + print("No unknowns. Solution complete") return mat = np.empty((self.neq, self.neq)) rhs = np.empty(self.neq) ieq = 0 for e in self.elementlist: if e.nunknowns > 0: - mat[ieq:ieq + e.nunknowns, :], rhs[ieq:ieq + e.nunknowns] = \ - e.equation() + ( + mat[ieq : ieq + e.nunknowns, :], + rhs[ieq : ieq + e.nunknowns], + ) = e.equation() ieq += e.nunknowns if silent is False: - print('.', end='', flush=True) + print(".", end="", flush=True) if printmat: return mat, rhs sol = np.linalg.solve(mat, rhs) icount = 0 for e in self.elementlist: if e.nunknowns > 0: - e.setparams(sol[icount:icount + e.nunknowns]) + e.setparams(sol[icount : icount + e.nunknowns]) icount += e.nunknowns if silent is False: print() # needed cause the dots are printed - print('solution complete') - elif (silent == 'dot') or (silent == '.'): - print('.', end='', flush=True) + print("solution complete") + elif (silent == "dot") or (silent == "."): + print(".", end="", flush=True) if sendback: return sol return def solve_mp(self, nproc=4, printmat=0, sendback=0, silent=False): - '''Compute solution, multiprocessing implementation. + """Compute solution, multiprocessing implementation. Note: estimated speedup approximately by factor of number of physical cores. Virtual cores do not improve - calculation time.''' + calculation time.""" # Initialize elements self.initialize() # Compute number of equations self.neq = np.sum([e.nunknowns for e in self.elementlist]) - if self.neq == 0: return + if self.neq == 0: + return if silent is False: - print('Number of elements, Number of equations:', len( - self.elementlist), ',', self.neq) + print( + "Number of elements, Number of equations:", + len(self.elementlist), + ",", + self.neq, + ) if self.neq == 0: - if silent is False: print('No unknowns. Solution complete') + if silent is False: + print("No unknowns. Solution complete") return mat = np.empty((self.neq, self.neq)) rhs = np.empty(self.neq) # start multiprocessing if nproc is None: - nproc = mp.cpu_count() - 1 # make no. of processes equal to 1 less than no. of cores + nproc = ( + mp.cpu_count() - 1 + ) # make no. of processes equal to 1 less than no. of cores elif nproc > mp.cpu_count(): - print("Given 'nproc' larger than no. of cores on machine. Setting 'nproc' to {}.".format(mp.cpu_count())) + print( + "Given 'nproc' larger than no. of cores on machine. Setting 'nproc' to {}.".format( + mp.cpu_count() + ) + ) nproc = mp.cpu_count() pool = mp.Pool(processes=nproc) @@ -431,7 +461,7 @@ def solve_mp(self, nproc=4, printmat=0, sendback=0, silent=False): if e.nunknowns > 0: results.append(pool.apply_async(e.equation)) if silent is False: - print('.', end='', flush=True) + print(".", end="", flush=True) pool.close() pool.join() @@ -443,8 +473,8 @@ def solve_mp(self, nproc=4, printmat=0, sendback=0, silent=False): for p in results: imat, irhs = p.get() - mat[ieq:ieq + imat.shape[0], :] = imat - rhs[ieq:ieq + irhs.shape[0]] = irhs + mat[ieq : ieq + imat.shape[0], :] = imat + rhs[ieq : ieq + irhs.shape[0]] = irhs ieq += imat.shape[0] # end multiprocessing @@ -455,44 +485,49 @@ def solve_mp(self, nproc=4, printmat=0, sendback=0, silent=False): icount = 0 for e in self.elementlist: if e.nunknowns > 0: - e.setparams(sol[icount:icount + e.nunknowns]) + e.setparams(sol[icount : icount + e.nunknowns]) icount += e.nunknowns if silent is False: print() # needed cause the dots are printed - print('solution complete') - elif (silent == 'dot') or (silent == '.'): - print('.', end='', flush=True) + print("solution complete") + elif (silent == "dot") or (silent == "."): + print(".", end="", flush=True) if sendback: return sol return - + def write(self): - rv = self.modelname + ' = ' + self.name + '(\n' + rv = self.modelname + " = " + self.name + "(\n" for key in self.inputargs[1:]: # The first argument (self) is ignored if isinstance(self.inputvalues[key], np.ndarray): - rv += key + ' = ' + np.array2string(self.inputvalues[key], - separator=',') + ',\n' - elif isinstance(self.inputvalues[key],str): + rv += ( + key + + " = " + + np.array2string(self.inputvalues[key], separator=",") + + ",\n" + ) + elif isinstance(self.inputvalues[key], str): rv += key + " = '" + self.inputvalues[key] + "',\n" else: - rv += key + ' = ' + str(self.inputvalues[key]) + ',\n' - rv += ')\n' + rv += key + " = " + str(self.inputvalues[key]) + ",\n" + rv += ")\n" return rv - + def writemodel(self, fname): self.initialize() # So that the model can be written without solving first - f = open(fname, 'w') - f.write('from timml import *\n') + f = open(fname, "w") + f.write("from timml import *\n") f.write(self.write()) for e in self.elementlist: f.write(e.write()) f.close() - + + class ModelMaq(Model): """ Create a Model object by specifying a mult-aquifer sequence of aquifer-leakylayer-aquifer-leakylayer-aquifer etc - + Parameters ---------- kaq : float, array or list @@ -502,7 +537,7 @@ class ModelMaq(Model): Elevation of tops and bottoms of the aquifers from the top down. Leaky layers may have zero thickness. * if topboundary='conf': length is 2 * number of aquifers - * if topboundary='semi': length is 2 * number of aquifers + 1 + * if topboundary='semi': length is 2 * number of aquifers + 1 as top of leaky layer on top of systems needs to be specified c : float, array or list Resistance of leaky layers from the top down. @@ -523,24 +558,24 @@ class ModelMaq(Model): Examples -------- >>> ml = ModelMaq(kaq=[10, 20], z=[20, 12, 10, 0], c=1000) - + """ - - def __init__(self, kaq=1, z=[1, 0], c=[], npor=0.3, topboundary='conf', - hstar=None): + + def __init__(self, kaq=1, z=[1, 0], c=[], npor=0.3, topboundary="conf", hstar=None): self.storeinput(inspect.currentframe()) kaq, c, npor, ltype = param_maq(kaq, z, c, npor, topboundary) Model.__init__(self, kaq, c, z, npor, ltype) - self.name = 'ModelMaq' - if self.aq.ltype[0] == 'l': + self.name = "ModelMaq" + if self.aq.ltype[0] == "l": ConstantStar(self, hstar, aq=self.aq) - + + class Model3D(Model): """ Model3D Class to create a multi-layer model object consisting of many aquifer layers. The resistance between the layers is computed from the vertical hydraulic conductivity of the layers. - + Parameters ---------- kaq : float, array or list @@ -574,23 +609,30 @@ class Model3D(Model): Examples -------- >>> ml = Model3D(kaq=10, z=np.arange(20, -1, -2), kzoverkh=0.1) - + """ - - def __init__(self, kaq=1, z=[1, 0], kzoverkh=1, npor=0.3, - topboundary='conf', topres=0, topthick=0, hstar=0): - '''Model3D + + def __init__( + self, + kaq=1, + z=[1, 0], + kzoverkh=1, + npor=0.3, + topboundary="conf", + topres=0, + topthick=0, + hstar=0, + ): + """Model3D for semi-confined aquifers, set top equal to 'semi' and provide topres: resistance of top tophick: thickness of top - hstar: head above top''' + hstar: head above top""" self.storeinput(inspect.currentframe()) - kaq, c, npor, ltype = param_3d(kaq, z, kzoverkh, npor, topboundary, - topres) - if topboundary == 'semi': + kaq, c, npor, ltype = param_3d(kaq, z, kzoverkh, npor, topboundary, topres) + if topboundary == "semi": z = np.hstack((z[0] + topthick, z)) Model.__init__(self, kaq, c, z, npor, ltype) - self.name = 'Model3D' - if self.aq.ltype[0] == 'l': + self.name = "Model3D" + if self.aq.ltype[0] == "l": ConstantStar(self, hstar, aq=self.aq) - diff --git a/timml/stripareasink.py b/timml/stripareasink.py index 343b2b12..d54c7feb 100644 --- a/timml/stripareasink.py +++ b/timml/stripareasink.py @@ -1,8 +1,11 @@ -import numpy as np import inspect # Used for storing the input + +import numpy as np + from .element import Element -__all__ = ['StripAreaSink'] +__all__ = ["StripAreaSink"] + class StripAreaSinkInhom(Element): """Create a strip area-sink in combination with an inhomogeneity. @@ -19,16 +22,27 @@ class StripAreaSinkInhom(Element): right boundary of inhomogeneity (may not be np.inf) """ - def __init__(self, model, xleft=-1, xright=1, N=0.001, layer=0, name='StripAreaSink', label=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layer, \ - name=name, label=label) + + def __init__( + self, + model, + xleft=-1, + xright=1, + N=0.001, + layer=0, + name="StripAreaSink", + label=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layer, name=name, label=label + ) self.xleft = xleft self.xright = xright self.N = N self.model.add_element(self) def __repr__(self): - return self.name + ' between ' + str((self.xleft, self.xright)) + return self.name + " between " + str((self.xleft, self.xright)) def initialize(self): self.xc = 0.5 * (self.xleft + self.xright) @@ -39,23 +53,25 @@ def initialize(self): self.parameters = np.array([[self.N]]) if self.aq.ilap: self.lab = self.aq.lab[1:] - self.A = -self.aq.coef[self.layers, 1:] * self.lab ** 2 / 2 + self.A = -self.aq.coef[self.layers, 1:] * self.lab**2 / 2 self.B = self.A * (np.exp(-self.L / self.lab) - 1) - self.plabsq = self.aq.coef[self.layers, 1:] * self.lab ** 2 + self.plabsq = self.aq.coef[self.layers, 1:] * self.lab**2 else: - print('StripAreaSink cannot be added to semi-confined system') + print("StripAreaSink cannot be added to semi-confined system") def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: if (x > self.xleft) and (x < self.xright): - rv[0, 0] = -0.5 * (x ** 2 - 2 * self.xc * x + self.xc ** 2) + rv[0, 0] = -0.5 * (x**2 - 2 * self.xc * x + self.xc**2) rv[0, 1:] = self.plabsq return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: if (x > self.xleft) and (x < self.xright): @@ -65,10 +81,14 @@ def disvecinf(self, x, y, aq=None): def qztop(self, x, y): rv = 0.0 if (x > self.xleft) and (x < self.xright): - rv = -self.parameters[0, 0] # minus cause the parameter is the infiltration rate + rv = -self.parameters[ + 0, 0 + ] # minus cause the parameter is the infiltration rate return rv - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 @@ -76,36 +96,56 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst eps = 1e-8 r1sq = (xyzt1[0] - self.xc) ** 2 + (xyzt1[1] - self.yc) ** 2 r2sq = (xyzt2[0] - self.xc) ** 2 + (xyzt2[1] - self.yc) ** 2 - if (r1sq < self.Rsq and r2sq > self.Rsq ) or (r1sq > self.Rsq and r2sq < self.Rsq): + if (r1sq < self.Rsq and r2sq > self.Rsq) or ( + r1sq > self.Rsq and r2sq < self.Rsq + ): changed = True x1, y1 = xyzt1[0:2] x2, y2 = xyzt2[0:2] a = (x2 - x1) ** 2 + (y2 - y1) ** 2 b = 2 * ((x2 - x1) * (x1 - self.xc) + (y2 - y1) * (y1 - self.yc)) - c = self.xc ** 2 + self.yc ** 2 + x1 ** 2 + y1 ** 2 - 2 * (self.xc * x1 +self.yc * y1) - self.Rsq - u1 = (-b - np.sqrt(b ** 2 - 4 * a * c)) / (2 * a) - u2 = (-b + np.sqrt(b ** 2 - 4 * a * c)) / (2 * a) + c = ( + self.xc**2 + + self.yc**2 + + x1**2 + + y1**2 + - 2 * (self.xc * x1 + self.yc * y1) + - self.Rsq + ) + u1 = (-b - np.sqrt(b**2 - 4 * a * c)) / (2 * a) + u2 = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a) if u1 > 0: - u = u1 * (1.0 + eps) # Go just beyond circle + u = u1 * (1.0 + eps) # Go just beyond circle else: - u = u2 * (1.0 + eps) # Go just beyond circle + u = u2 * (1.0 + eps) # Go just beyond circle xn = x1 + u * (x2 - x1) yn = y1 + u * (y2 - y1) zn = xyzt1[2] + u * (xyzt2[2] - xyzt1[2]) xyztnew = xyzt1 + u * (xyzt2 - xyzt1) return changed, terminate, xyztnew, message + class StripAreaSink(Element): - def __init__(self, model, xleft=-1, xright=1, N=0.001, layer=0, name='StripAreaSink', label=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layer, \ - name=name, label=label) + def __init__( + self, + model, + xleft=-1, + xright=1, + N=0.001, + layer=0, + name="StripAreaSink", + label=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layer, name=name, label=label + ) self.xleft = xleft self.xright = xright self.N = N self.model.add_element(self) def __repr__(self): - return self.name + ' at ' + str((self.xc, self.yc)) + return self.name + " at " + str((self.xc, self.yc)) def initialize(self): self.xc = 0.5 * (self.xleft + self.xright) @@ -116,33 +156,38 @@ def initialize(self): self.parameters = np.array([[self.N]]) if self.aq.ilap: self.lab = self.aq.lab[1:] - self.A = -self.aq.coef[self.layers, 1:] * self.lab ** 2 / 2 + self.A = -self.aq.coef[self.layers, 1:] * self.lab**2 / 2 self.B = self.A * (np.exp(-self.L / self.lab) - 1) - self.plabsq = self.aq.coef[self.layers, 1:] * self.lab ** 2 + self.plabsq = self.aq.coef[self.layers, 1:] * self.lab**2 else: - print('StripAreaSink cannot be added to semi-confined system') + print("StripAreaSink cannot be added to semi-confined system") def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((self.nparam, aq.naq)) if aq == self.aq: if x < self.xleft: - rv[0, 0] = -(self.xleft - self.xc) * (x - self.xc) + \ - self.L ** 2 / 8 + rv[0, 0] = -(self.xleft - self.xc) * (x - self.xc) + self.L**2 / 8 rv[0, 1:] = self.B * np.exp((x - self.xleft) / self.lab) elif x > self.xright: - rv[0, 0] = -(self.xright - self.xc) * (x - self.xc) + \ - self.L ** 2 / 8 + rv[0, 0] = -(self.xright - self.xc) * (x - self.xc) + self.L**2 / 8 rv[0, 1:] = self.B * np.exp(-(x - self.xright) / self.lab) else: - rv[0, 0] = -0.5 * (x ** 2 - 2 * self.xc * x + self.xc ** 2) - rv[0, 1:] = self.A * (np.exp(-(x - self.xleft) / self.lab) + - np.exp((x - self.xright) / self.lab)) + \ - self.plabsq + rv[0, 0] = -0.5 * (x**2 - 2 * self.xc * x + self.xc**2) + rv[0, 1:] = ( + self.A + * ( + np.exp(-(x - self.xleft) / self.lab) + + np.exp((x - self.xright) / self.lab) + ) + + self.plabsq + ) return rv def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, self.nparam, aq.naq)) if aq == self.aq: if x < self.xleft: @@ -153,18 +198,27 @@ def disvecinf(self, x, y, aq=None): rv[0, 0, 1:] = self.B / self.lab * np.exp(-(x - self.xright) / self.lab) else: rv[0, 0, 0] = x - self.xc - rv[0, 0, 1:] = self.A / self.lab * ( - np.exp(-(x - self.xleft) / self.lab) - - np.exp((x - self.xright) / self.lab)) + rv[0, 0, 1:] = ( + self.A + / self.lab + * ( + np.exp(-(x - self.xleft) / self.lab) + - np.exp((x - self.xright) / self.lab) + ) + ) return rv def qztop(self, x, y): rv = 0.0 if (x > self.xleft) and (x < self.xright): - rv = -self.parameters[0, 0] # minus cause the parameter is the infiltration rate + rv = -self.parameters[ + 0, 0 + ] # minus cause the parameter is the infiltration rate return rv - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 @@ -172,19 +226,28 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hst eps = 1e-8 r1sq = (xyzt1[0] - self.xc) ** 2 + (xyzt1[1] - self.yc) ** 2 r2sq = (xyzt2[0] - self.xc) ** 2 + (xyzt2[1] - self.yc) ** 2 - if (r1sq < self.Rsq and r2sq > self.Rsq ) or (r1sq > self.Rsq and r2sq < self.Rsq): + if (r1sq < self.Rsq and r2sq > self.Rsq) or ( + r1sq > self.Rsq and r2sq < self.Rsq + ): changed = True x1, y1 = xyzt1[0:2] x2, y2 = xyzt2[0:2] a = (x2 - x1) ** 2 + (y2 - y1) ** 2 b = 2 * ((x2 - x1) * (x1 - self.xc) + (y2 - y1) * (y1 - self.yc)) - c = self.xc ** 2 + self.yc ** 2 + x1 ** 2 + y1 ** 2 - 2 * (self.xc * x1 +self.yc * y1) - self.Rsq - u1 = (-b - np.sqrt(b ** 2 - 4 * a * c)) / (2 * a) - u2 = (-b + np.sqrt(b ** 2 - 4 * a * c)) / (2 * a) + c = ( + self.xc**2 + + self.yc**2 + + x1**2 + + y1**2 + - 2 * (self.xc * x1 + self.yc * y1) + - self.Rsq + ) + u1 = (-b - np.sqrt(b**2 - 4 * a * c)) / (2 * a) + u2 = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a) if u1 > 0: - u = u1 * (1.0 + eps) # Go just beyond circle + u = u1 * (1.0 + eps) # Go just beyond circle else: - u = u2 * (1.0 + eps) # Go just beyond circle + u = u2 * (1.0 + eps) # Go just beyond circle xn = x1 + u * (x2 - x1) yn = y1 + u * (y2 - y1) zn = xyzt1[2] + u * (xyzt2[2] - xyzt1[2]) diff --git a/timml/trace.py b/timml/trace.py index 0a8b8102..b4cdafff 100644 --- a/timml/trace.py +++ b/timml/trace.py @@ -11,9 +11,21 @@ ) -def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, - nstepmax=100, win=[-1e30, 1e30, -1e30, 1e30], silent=False, - returnlayers=False, *, metadata=False): +def timtraceline( + ml, + xstart, + ystart, + zstart, + hstepmax, + vstepfrac=0.2, + tmax=1e12, + nstepmax=100, + win=[-1e30, 1e30, -1e30, 1e30], + silent=False, + returnlayers=False, + *, + metadata=False +): verbose = False # used for debugging if not metadata: warnings.warn(_future_warning_metadata, FutureWarning, stacklevel=2) @@ -31,7 +43,7 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, layer, ltype, modellayer = aq.findlayer(zstart) # slightly alter starting location not to get stuck in surpring points # starting at time 0 - xyzt = [np.array([xstart * (1 + eps), ystart * (1 + eps), zstart, 0])] + xyzt = [np.array([xstart * (1 + eps), ystart * (1 + eps), zstart, 0])] layerlist = [] # to keep track of layers for plotting with colors for _ in range(nstepmax): if terminate: @@ -42,8 +54,8 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, layerlist.append(modellayer) v0 = ml.velocomp(x0, y0, z0, aq, [layer, ltype]) * direction if verbose: - print('xyz, layer', x0, y0, z0, layer) - print('v0, layer, ltype', v0, layer, ltype) + print("xyz, layer", x0, y0, z0, layer) + print("v0, layer, ltype", v0, layer, ltype) vx, vy, vz = v0 if ltype == "l": # in leaky layer if vz > 0: # upward through leaky layer @@ -69,7 +81,7 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, t1 = t0 + abs((z1 - z0) / vz) xyztnew = [np.array([x0, y0, z1, t1])] else: # in aquifer layer - vh = np.sqrt(vx ** 2 + vy ** 2) + vh = np.sqrt(vx**2 + vy**2) if vz > 0: # flows upward if aq.z[modellayer] - z0 < vstepfrac * aq.Haq[layer]: # just below top @@ -91,7 +103,7 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, message = "at point of zero velocity" terminate = True break - if vh * tvstep > hstepmax: + if vh * tvstep > hstepmax: # max horizonal step smaller than max vertical step thstep = hstepmax / vh z1 = z0 + thstep * vz @@ -106,26 +118,27 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, correction = True for e in aq.elementlist: changed, terminate, xyztnew, changemessage = e.changetrace( - xyzt[-1], xyzt1, aq, layer, ltype, modellayer, - direction, hstepmax) + xyzt[-1], xyzt1, aq, layer, ltype, modellayer, direction, hstepmax + ) if changed or terminate: correction = False if changemessage: message = changemessage break if correction: # correction step - vx, vy, vz = 0.5 * (v0 + direction * \ - ml.velocomp(x1, y1, z1, aq, [layer, ltype])) + vx, vy, vz = 0.5 * ( + v0 + direction * ml.velocomp(x1, y1, z1, aq, [layer, ltype]) + ) if verbose: - print('xyz1, layer', x1, y1, z1, layer) - print('correction vx, vy, vz', vx, vy, vz) - vh = np.sqrt(vx ** 2 + vy ** 2) + print("xyz1, layer", x1, y1, z1, layer) + print("correction vx, vy, vz", vx, vy, vz) + vh = np.sqrt(vx**2 + vy**2) if vz > 0: # flows upward - tvstep = min(aq.z[modellayer] - z0, - vstepfrac * aq.Haq[layer]) / vz + tvstep = min(aq.z[modellayer] - z0, vstepfrac * aq.Haq[layer]) / vz elif vz < 0: - tvstep = min(z0 - aq.z[modellayer + 1], - vstepfrac * aq.Haq[layer]) / abs(vz) + tvstep = min( + z0 - aq.z[modellayer + 1], vstepfrac * aq.Haq[layer] + ) / abs(vz) else: # vz=0 tvstep = np.inf if vh * tvstep > hstepmax: @@ -147,8 +160,7 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, else: modellayer -= 1 # just above new bottom - z1 = aq.z[modellayer + 1] + \ - eps * aq.Hlayer[modellayer] + z1 = aq.z[modellayer + 1] + eps * aq.Hlayer[modellayer] else: z1 = z0 + thstep * vz else: @@ -160,8 +172,7 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, else: modellayer += 1 # just below new top - z1 = aq.z[modellayer] - \ - eps * aq.Hlayer[modellayer] + z1 = aq.z[modellayer] - eps * aq.Hlayer[modellayer] else: z1 = z0 + thstep * vz if not terminate: @@ -171,9 +182,16 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, xyztnew = [np.array([x1, y1, z1, t1])] # check again if point needs to be changed for e in aq.elementlist: - changed, terminate, xyztchanged, changemessage = \ - e.changetrace(xyzt[-1], xyztnew[0], aq, layer, ltype, - modellayer, direction, hstepmax) + changed, terminate, xyztchanged, changemessage = e.changetrace( + xyzt[-1], + xyztnew[0], + aq, + layer, + ltype, + modellayer, + direction, + hstepmax, + ) if changed or terminate: xyztnew = xyztchanged if changemessage: @@ -216,8 +234,7 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, if not silent: print(message) if metadata: - result = {"trace": np.array(xyzt), "message": message, - "complete": terminate} + result = {"trace": np.array(xyzt), "message": message, "complete": terminate} if returnlayers: result["layers"] = layerlist else: @@ -228,15 +245,36 @@ def timtraceline(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, tmax=1e12, return result -def timtracelines(ml, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, - tmax=1e12, nstepmax=100, silent=".", - win=[-1e30, 1e30, -1e30, 1e30], *, metadata=False): +def timtracelines( + ml, + xstart, + ystart, + zstart, + hstepmax, + vstepfrac=0.2, + tmax=1e12, + nstepmax=100, + silent=".", + win=[-1e30, 1e30, -1e30, 1e30], + *, + metadata=False +): xyztlist = [] for x, y, z in zip(xstart, ystart, zstart): xyztlist.append( - timtraceline(ml, x, y, z, hstepmax=hstepmax, vstepfrac=vstepfrac, - tmax=tmax, nstepmax=nstepmax, silent=silent, win=win, - metadata=metadata) + timtraceline( + ml, + x, + y, + z, + hstepmax=hstepmax, + vstepfrac=vstepfrac, + tmax=tmax, + nstepmax=nstepmax, + silent=silent, + win=win, + metadata=metadata, + ) ) if silent == ".": print(".", end="", flush=True) diff --git a/timml/uflow.py b/timml/uflow.py index 0045cc58..6d1fe296 100644 --- a/timml/uflow.py +++ b/timml/uflow.py @@ -1,15 +1,18 @@ +import inspect # Used for storing the input + import numpy as np -import inspect # Used for storing the input + from .element import Element -__all__ = ['Uflow'] +__all__ = ["Uflow"] + class Uflow(Element): """ Add uniform flow to the model. Uniform flow may only be added to a model of which the background aquifer system is confined. - + Parameters ---------- model : Model object @@ -22,34 +25,43 @@ class Uflow(Element): counter clock-wise is positive) label : string or None (default: None) label of the element - + """ - + def __init__(self, model, slope, angle, label=None): - assert model.aq.ilap, 'TimML Error: Uflow can only be added to model with background confined aquifer' + assert ( + model.aq.ilap + ), "TimML Error: Uflow can only be added to model with background confined aquifer" self.storeinput(inspect.currentframe()) - Element.__init__(self, model, nparam=2, nunknowns=0, layers=0, \ - name='Uflow', label=label) + Element.__init__( + self, model, nparam=2, nunknowns=0, layers=0, name="Uflow", label=label + ) self.slope = slope self.angle = angle self.model.add_element(self) + def __repr__(self): - return self.name + ' with slope and angle: ' + str((self.slope, self.angle)) + return self.name + " with slope and angle: " + str((self.slope, self.angle)) + def initialize(self): self.aq = self.model.aq self.aq.add_element(self) self.Qx = self.slope * np.cos(self.angle * np.pi / 180) * np.sum(self.aq.T) self.Qy = self.slope * np.sin(self.angle * np.pi / 180) * np.sum(self.aq.T) self.parameters = np.array([[self.Qx], [self.Qy]]) + def potinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, aq.naq)) if aq == self.aq: rv[0, 0] = -x rv[1, 0] = -y return rv + def disvecinf(self, x, y, aq=None): - if aq is None: aq = self.model.aq.find_aquifer_data(x, y) + if aq is None: + aq = self.model.aq.find_aquifer_data(x, y) rv = np.zeros((2, 2, aq.naq)) if aq == self.aq: rv[0, 0, 0] = 1.0 diff --git a/timml/util.py b/timml/util.py index f5db82b5..816b8c0c 100644 --- a/timml/util.py +++ b/timml/util.py @@ -8,8 +8,15 @@ class PlotTim: - def plot(self, win=None, newfig=True, figsize=None, orientation="hor", - topfigfrac=0.8, layer=None): + def plot( + self, + win=None, + newfig=True, + figsize=None, + orientation="hor", + topfigfrac=0.8, + layer=None, + ): """Plot layout Parameters @@ -25,10 +32,17 @@ def plot(self, win=None, newfig=True, figsize=None, orientation="hor", ax1 = None ax2 = None if orientation == "both": - ax1 = plt.axes([0.125, 0.18 + (1 - topfigfrac) * 0.7, - (0.9 - 0.125), topfigfrac * 0.7]) - ax2 = plt.axes([0.125, 0.11, (0.9 - 0.125), - (1 - topfigfrac) * 0.7], sharex=ax1) + ax1 = plt.axes( + [ + 0.125, + 0.18 + (1 - topfigfrac) * 0.7, + (0.9 - 0.125), + topfigfrac * 0.7, + ] + ) + ax2 = plt.axes( + [0.125, 0.11, (0.9 - 0.125), (1 - topfigfrac) * 0.7], sharex=ax1 + ) elif orientation[:3] == "hor": ax1 = plt.subplot() elif orientation[:3] == "ver": @@ -60,16 +74,30 @@ def plot(self, win=None, newfig=True, figsize=None, orientation="hor", plt.sca(ax2) for i in range(self.aq.nlayers): if self.aq.ltype[i] == "l": - plt.axhspan(ymin=self.aq.z[i + 1], ymax=self.aq.z[i], - color=[0.8, 0.8, 0.8]) + plt.axhspan( + ymin=self.aq.z[i + 1], ymax=self.aq.z[i], color=[0.8, 0.8, 0.8] + ) for i in range(1, self.aq.nlayers): if self.aq.ltype[i] == "a" and self.aq.ltype[i - 1] == "a": - plt.axhspan(ymin=self.aq.z[i], ymax=self.aq.z[i], - color=[0.8, 0.8, 0.8]) + plt.axhspan( + ymin=self.aq.z[i], ymax=self.aq.z[i], color=[0.8, 0.8, 0.8] + ) - def contour(self, win, ngr=20, layers=0, levels=20, layout=True, - labels=True, decimals=0, color=None, newfig=True, - figsize=None, legend=True, **kwargs): + def contour( + self, + win, + ngr=20, + layers=0, + levels=20, + layout=True, + labels=True, + decimals=0, + color=None, + newfig=True, + figsize=None, + legend=True, + **kwargs + ): """Contour plot Parameters @@ -100,10 +128,10 @@ def contour(self, win, ngr=20, layers=0, levels=20, layout=True, legend : list or boolean (default True) add legend to figure if list of strings: use strings as names in legend - + Returns ------- - + cs : list of contour sets for each contoured layer """ @@ -150,18 +178,29 @@ def contour(self, win, ngr=20, layers=0, levels=20, layout=True, self.plot(win=[x1, x2, y1, y2], newfig=False, layer=layers) return cslist - def vcontour(self, win, n, levels, labels=False, decimals=0, color=None, - vinterp=True, nudge=1e-6, newfig=True, figsize=None, - layout=True): + def vcontour( + self, + win, + n, + levels, + labels=False, + decimals=0, + color=None, + vinterp=True, + nudge=1e-6, + newfig=True, + figsize=None, + layout=True, + ): """ Vertical contour - + Returns ------- - + cs : contour set """ - + x1, x2, y1, y2 = win h = self.headalongline( np.linspace(x1 + nudge, x2 - nudge, n), @@ -189,13 +228,26 @@ def vcontour(self, win, n, levels, labels=False, decimals=0, color=None, self.plot(win=[x1, x2, y1, y2], orientation="ver", newfig=False) return cs - def tracelines(self, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, - tmax=1e12, nstepmax=100, silent=".", color=None, - orientation="hor", win=[-1e30, 1e30, -1e30, 1e30], - newfig=False, figsize=None, *, return_traces=False, - metadata=False): - """Draw trace lines - """ + def tracelines( + self, + xstart, + ystart, + zstart, + hstepmax, + vstepfrac=0.2, + tmax=1e12, + nstepmax=100, + silent=".", + color=None, + orientation="hor", + win=[-1e30, 1e30, -1e30, 1e30], + newfig=False, + figsize=None, + *, + return_traces=False, + metadata=False + ): + """Draw trace lines""" if color is None: c = plt.rcParams["axes.prop_cycle"].by_key()["color"] elif type(color) is str: @@ -206,8 +258,9 @@ def tracelines(self, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, n = int(np.ceil(self.aq.naq / len(c))) c = n * c fig = plt.gcf() - assert (len(fig.axes) > 0), \ - "Error: Need to specify axes in figure before invoking tracelines" + assert ( + len(fig.axes) > 0 + ), "Error: Need to specify axes in figure before invoking tracelines" ax1 = None ax2 = None if orientation == "both": @@ -270,9 +323,21 @@ def tracelines(self, xstart, ystart, zstart, hstepmax, vstepfrac=0.2, if return_traces: return traces - def vcontoursf1D(self, x1, x2, nx, levels, labels=False, decimals=0, - color=None, nudge=1e-6, newfig=True, figsize=None, - layout=True, ax=None): + def vcontoursf1D( + self, + x1, + x2, + nx, + levels, + labels=False, + decimals=0, + color=None, + nudge=1e-6, + newfig=True, + figsize=None, + layout=True, + ax=None, + ): """ Vertical contour for 1D model diff --git a/timml/version.py b/timml/version.py index e68f7f1a..86a59e3b 100644 --- a/timml/version.py +++ b/timml/version.py @@ -1,2 +1,2 @@ -__version__='6.1.2' -#__build__='4.0.0.0' +__version__ = "6.1.2" +# __build__='4.0.0.0' diff --git a/timml/well.py b/timml/well.py index 4300669e..581ebf48 100644 --- a/timml/well.py +++ b/timml/well.py @@ -12,10 +12,23 @@ class WellBase(Element): - def __init__(self, model, xw=0, yw=0, Qw=100.0, rw=0.1, res=0.0, layers=0, - name="WellBase", label=None, xc=None, yc=None): - Element.__init__(self, model, nparam=1, nunknowns=0, layers=layers, - name=name, label=label) + def __init__( + self, + model, + xw=0, + yw=0, + Qw=100.0, + rw=0.1, + res=0.0, + layers=0, + name="WellBase", + label=None, + xc=None, + yc=None, + ): + Element.__init__( + self, model, nparam=1, nunknowns=0, layers=layers, name=name, label=label + ) # Defined here and not in Element as other elements can have multiple # parameters per layers self.nparam = len(self.layers) @@ -77,7 +90,7 @@ def disvecinf(self, x, y, aq=None): yminyw = y - self.yw if r < self.rw: r = self.rw - rsq = r ** 2 + rsq = r**2 xminxw = self.rw yminyw = 0.0 if aq.ilap: @@ -122,8 +135,9 @@ def discharge(self): Q[self.layers] = self.parameters[:, 0] return Q - def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, - direction, hstepmax): + def changetrace( + self, xyzt1, xyzt2, aq, layer, ltype, modellayer, direction, hstepmax + ): changed = False terminate = False xyztnew = 0 @@ -134,11 +148,12 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, if ltype == "a": if (layer == self.layers).any(): # in layer where well is screened if (self.discharge()[layer] > 0 and direction > 0) or ( - self.discharge()[layer] < 0 and direction < 0): + self.discharge()[layer] < 0 and direction < 0 + ): vx, vy, vz = self.model.velocity(*xyzt1[:-1]) tstep = np.sqrt( (xyzt1[0] - self.xw) ** 2 + (xyzt1[1] - self.yw) ** 2 - ) / np.sqrt(vx ** 2 + vy ** 2) + ) / np.sqrt(vx**2 + vy**2) xnew = self.xw ynew = self.yw znew = xyzt1[2] + tstep * vz * direction @@ -153,8 +168,16 @@ def changetrace(self, xyzt1, xyzt2, aq, layer, ltype, modellayer, return changed, terminate, [xyztnew], message def capzone( - self, nt=10, zstart=None, hstepmax=10, vstepfrac=0.2, tmax=None, - nstepmax=100, silent=".", *, metadata=False + self, + nt=10, + zstart=None, + hstepmax=10, + vstepfrac=0.2, + tmax=None, + nstepmax=100, + silent=".", + *, + metadata=False ): """Compute a capture zone @@ -182,9 +205,18 @@ def capzone( """ xstart, ystart, zstart = self.capzonestart(nt, zstart) - xyzt = timtracelines(self.model, xstart, ystart, zstart, -np.abs(hstepmax), - vstepfrac=vstepfrac, tmax=tmax, nstepmax=nstepmax, silent=silent, - metadata=metadata) + xyzt = timtracelines( + self.model, + xstart, + ystart, + zstart, + -np.abs(hstepmax), + vstepfrac=vstepfrac, + tmax=tmax, + nstepmax=nstepmax, + silent=silent, + metadata=metadata, + ) return xyzt def capzonestart(self, nt, zstart): @@ -201,11 +233,24 @@ def plot(self, layer=None): if (layer is None) or (layer in self.layers): plt.plot(self.xw, self.yw, "k.") - def plotcapzone(self, nt=10, zstart=None, hstepmax=20, vstepfrac=0.2, - tmax=365, nstepmax=100, silent=".", color=None, - orientation="hor", win=[-1e30, 1e30, -1e30, 1e30], - newfig=False, figsize=None, *, return_traces=False, - metadata=False): + def plotcapzone( + self, + nt=10, + zstart=None, + hstepmax=20, + vstepfrac=0.2, + tmax=365, + nstepmax=100, + silent=".", + color=None, + orientation="hor", + win=[-1e30, 1e30, -1e30, 1e30], + newfig=False, + figsize=None, + *, + return_traces=False, + metadata=False + ): """Plot a capture zone Parameters @@ -239,11 +284,23 @@ def plotcapzone(self, nt=10, zstart=None, hstepmax=20, vstepfrac=0.2, if not return_traces: metadata = True # suppress future warning from timtraceline xstart, ystart, zstart = self.capzonestart(nt, zstart) - traces = self.model.tracelines(xstart, ystart, zstart, - hstepmax=-abs(hstepmax), vstepfrac=vstepfrac, tmax=tmax, - nstepmax=nstepmax, silent=silent, color=color, - orientation=orientation, win=win, newfig=newfig, - figsize=figsize, return_traces=return_traces, metadata=metadata) + traces = self.model.tracelines( + xstart, + ystart, + zstart, + hstepmax=-abs(hstepmax), + vstepfrac=vstepfrac, + tmax=tmax, + nstepmax=nstepmax, + silent=silent, + color=color, + orientation=orientation, + win=win, + newfig=newfig, + figsize=figsize, + return_traces=return_traces, + metadata=metadata, + ) if return_traces: return traces @@ -292,11 +349,34 @@ class Well(WellBase, MscreenWellEquation): """ - def __init__(self, model, xw=0, yw=0, Qw=100.0, rw=0.1, \ - res=0.0, layers=0, label=None, xc=None, yc=None): + def __init__( + self, + model, + xw=0, + yw=0, + Qw=100.0, + rw=0.1, + res=0.0, + layers=0, + label=None, + xc=None, + yc=None, + ): self.storeinput(inspect.currentframe()) - WellBase.__init__(self, model, xw, yw, Qw, rw, res, \ - layers=layers, name="Well", label=label, xc=xc, yc=yc) + WellBase.__init__( + self, + model, + xw, + yw, + Qw, + rw, + res, + layers=layers, + name="Well", + label=label, + xc=xc, + yc=yc, + ) self.Qc = float(Qw) if self.nlayers == 1: self.nunknowns = 0 @@ -348,11 +428,34 @@ class HeadWell(WellBase, PotentialEquation): """ - def __init__(self, model, xw=0, yw=0, hw=10, rw=0.1, res=0, layers=0, - label=None, xc=None, yc=None): + def __init__( + self, + model, + xw=0, + yw=0, + hw=10, + rw=0.1, + res=0, + layers=0, + label=None, + xc=None, + yc=None, + ): self.storeinput(inspect.currentframe()) - WellBase.__init__(self, model, xw, yw, 0.0, rw, res, layers=layers, - name="HeadWell", label=label, xc=xc, yc=yc) + WellBase.__init__( + self, + model, + xw, + yw, + 0.0, + rw, + res, + layers=layers, + name="HeadWell", + label=label, + xc=xc, + yc=yc, + ) self.hc = hw self.nunknowns = self.nparam From 4f33f28e3acabd9c483fcb5de4b43c4e5c864a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Wed, 30 Aug 2023 10:26:00 +0200 Subject: [PATCH 2/9] add .git-blame-ignore-revs --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..2a2e5397 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Migrate code style to black +998b86fc128e35f1506e3d4facb169c558679bde \ No newline at end of file From b6e52293fd480473960bb58495268b26f7dff124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Wed, 30 Aug 2023 10:29:35 +0200 Subject: [PATCH 3/9] add ci to dev branch --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c636d231..e48854b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,11 @@ on: push: branches: - master + - dev pull_request: branches: - master + - dev jobs: test: From 0e80f35e662e0db4b4b9808cb0e85a4bc331d324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Wed, 30 Aug 2023 10:34:07 +0200 Subject: [PATCH 4/9] add citation file --- CITATION.cff | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CITATION.cff diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..6f620c61 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,24 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: + - family-names: "Bakker" + given-names: "Mark" + orcid: "https://orcid.org/0000-0002-5629-2861" +title: "TimML" +url: "https://github.com/mbakker7/timml" + +preferred-citation: + type: article + authors: + - family-names: "Bakker" + given-names: "Mark" + orcid: "https://orcid.org/0000-0002-5629-2861" + - family-names: "Strack" + given-names: "Otto D.L." + doi: "10.1016/S0022-1694(02)00319-0" + journal: "Journal of Hydrology" + title: "Analytic elements for multiaquifer flow" + volume: 271 + number: 1 + pages: 119-129 + year: 2003 From e348545526bab848e3028850c15573d32fb2b885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Wed, 30 Aug 2023 10:36:16 +0200 Subject: [PATCH 5/9] move to pyproject toml delete setup.py --- pyproject.toml | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 28 ---------------------- 2 files changed, 65 insertions(+), 28 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..1b676589 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,65 @@ +[build-system] +# Minimum requirements for the build system to execute +requires = ["setuptools>64"] +build-backend = "setuptools.build_meta" + +[project] +name = "timml" +dynamic = ["version"] +description = "Steady multi-layer AEM Model" +license = { file = "LICENSE" } +readme = "README.md" +authors = [{ name = "Mark Bakker" }] +maintainers = [ + { name = "Mark Bakker", email = "markbak@gmail.com" }, + { name = "Davíd Brakenhoff", email = "d.brakenhoff@artesia-water.nl" }, +] +requires-python = ">= 3.7" +dependencies = ["numpy>=1.12", "scipy>=0.19", "numba>=0.39", "matplotlib>=3.0"] + +keywords = ["hydrology", "groundwater", "model", "analytic element method"] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Intended Audience :: Other Audience", + "License :: OSI Approved :: MIT License", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering :: Hydrology", +] + +[project.urls] +homepage = "https://github.com/mbakker7/timml" +repository = "https://github.com/mbakker7/timml" +documentation = "http://mbakker7.github.io/timml/docs/builddocs/html/index.html" + +[project.optional-dependencies] +ci = [ + "pytest>=4.6", + "jupyter>=1.0.0", + "shapely", +] + +[tool.setuptools] +packages= ["timml", "timml.besselaesnumba"] + +[tool.setuptools.dynamic] +version = { attr = "timml.version.__version__" } + +[tool.black] +line-length = 88 + +[tool.isort] +profile = "black" +src_paths = ["timml"] +line_length = 88 diff --git a/setup.py b/setup.py deleted file mode 100644 index f18876ba..00000000 --- a/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -from os import path - -from setuptools import setup - -version = {} -with open("timml/version.py") as fp: - exec(fp.read(), version) - -this_directory = path.abspath(path.dirname(__file__)) -with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: - l_d = f.read() - -setup( - name="timml", - version=version["__version__"], - description="Steady multi-layer AEM Model", - long_description=l_d, - long_description_content_type='text/markdown', - author="Mark Bakker", - author_email="markbak@gmail.com", - url="https://github.com/mbakker7/timml", - license="MIT", - packages=["timml", "timml/besselaesnumba"], - python_requires='>3.5', - install_requires=["numpy>=1.12", "scipy>=0.19", - "numba>=0.39", "matplotlib>=3.0"], - classifiers=['Topic :: Scientific/Engineering :: Hydrology'], -) From c42637141d9656a460a9153e521ae7297fc4a1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Wed, 30 Aug 2023 16:38:37 +0200 Subject: [PATCH 6/9] Update CITATION.cff Co-authored-by: Mike Taves --- CITATION.cff | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CITATION.cff b/CITATION.cff index 6f620c61..0ccb507c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -20,5 +20,6 @@ preferred-citation: title: "Analytic elements for multiaquifer flow" volume: 271 number: 1 - pages: 119-129 + start: 119 + end: 129 year: 2003 From 9d4edcda492019f87b0b1a92e2f77d28caa1c16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Sun, 10 Sep 2023 17:47:30 +0200 Subject: [PATCH 7/9] fix #75 --- timml/inhomogeneity.py | 2 +- timml/trace.py | 4 ++-- timml/util.py | 4 ++-- timml/well.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/timml/inhomogeneity.py b/timml/inhomogeneity.py index 84852790..6e8e32fd 100644 --- a/timml/inhomogeneity.py +++ b/timml/inhomogeneity.py @@ -376,7 +376,7 @@ def __init__( self.order = order self.ndeg = ndeg - self.layers = layers # layers with impermeable wall + self.layers = np.atleast_1d(layers) # layers with impermeable wall self.nonimplayers = list( set(range(self.model.aq.naq)) - set(self.layers) ) # layers without wall diff --git a/timml/trace.py b/timml/trace.py index b4cdafff..7217b58f 100644 --- a/timml/trace.py +++ b/timml/trace.py @@ -24,7 +24,7 @@ def timtraceline( silent=False, returnlayers=False, *, - metadata=False + metadata=False, ): verbose = False # used for debugging if not metadata: @@ -257,7 +257,7 @@ def timtracelines( silent=".", win=[-1e30, 1e30, -1e30, 1e30], *, - metadata=False + metadata=False, ): xyztlist = [] for x, y, z in zip(xstart, ystart, zstart): diff --git a/timml/util.py b/timml/util.py index 816b8c0c..00a40d84 100644 --- a/timml/util.py +++ b/timml/util.py @@ -96,7 +96,7 @@ def contour( newfig=True, figsize=None, legend=True, - **kwargs + **kwargs, ): """Contour plot @@ -245,7 +245,7 @@ def tracelines( figsize=None, *, return_traces=False, - metadata=False + metadata=False, ): """Draw trace lines""" if color is None: diff --git a/timml/well.py b/timml/well.py index 581ebf48..716a82ea 100644 --- a/timml/well.py +++ b/timml/well.py @@ -177,7 +177,7 @@ def capzone( nstepmax=100, silent=".", *, - metadata=False + metadata=False, ): """Compute a capture zone @@ -249,7 +249,7 @@ def plotcapzone( figsize=None, *, return_traces=False, - metadata=False + metadata=False, ): """Plot a capture zone From 9aae5d8bd43e491d742035af8c910bd4d8625ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Sun, 10 Sep 2023 17:50:07 +0200 Subject: [PATCH 8/9] up version --- timml/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timml/version.py b/timml/version.py index 86a59e3b..319aa57f 100644 --- a/timml/version.py +++ b/timml/version.py @@ -1,2 +1,2 @@ -__version__ = "6.1.2" +__version__ = "6.2.0" # __build__='4.0.0.0' From b0e803f5680ee822d95972911e22a6b721052340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=ADd=20Brakenhoff?= Date: Mon, 11 Sep 2023 13:52:46 +0200 Subject: [PATCH 9/9] update github workflows --- .github/workflows/ci.yml | 6 +----- .github/workflows/python-publish.yml | 8 ++++---- pyproject.toml | 5 ++++- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e48854b8..d7cb7570 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,11 +28,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - if [ -f requirements.ci.txt ]; then pip install -r requirements.ci.txt; fi - pip install flake8 pytest - pip install pytest-cov - pip install coveralls - pip install -e . + pip install -e .[ci] - name: Lint with flake8 run: | diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 0c36fedc..bcc4cd5c 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -21,11 +21,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install wheel twine build - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel - twine upload dist/* + python3 -m build + python3 -m twine upload --repository pypi dist/* diff --git a/pyproject.toml b/pyproject.toml index 1b676589..dd1e4b87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ maintainers = [ { name = "Davíd Brakenhoff", email = "d.brakenhoff@artesia-water.nl" }, ] requires-python = ">= 3.7" -dependencies = ["numpy>=1.12", "scipy>=0.19", "numba>=0.39", "matplotlib>=3.0"] +dependencies = ["numpy>=1.20", "scipy>=0.19", "numba>=0.39", "matplotlib>=3.0"] keywords = ["hydrology", "groundwater", "model", "analytic element method"] classifiers = [ @@ -46,8 +46,11 @@ documentation = "http://mbakker7.github.io/timml/docs/builddocs/html/index.html" [project.optional-dependencies] ci = [ "pytest>=4.6", + "pytest-cov", "jupyter>=1.0.0", "shapely", + "flake8", + "coveralls", ] [tool.setuptools]