ci(rtd): generate tutorial files and save as action asset (#979)
parent
2763a1d5ef
commit
893bd11a81
|
@ -20,52 +20,27 @@ sys.path.insert(0, os.path.abspath(".."))
|
||||||
from flopy import __version__
|
from flopy import __version__
|
||||||
import pymake
|
import pymake
|
||||||
|
|
||||||
|
# -- determine if running on readthedocs ------------------------------------
|
||||||
|
on_rtd = os.environ.get('READTHEDOCS') == 'True'
|
||||||
|
|
||||||
# -- get the MODFLOW executables --------------------------------------------
|
# -- get the MODFLOW executables --------------------------------------------
|
||||||
ws = ".bin"
|
if not on_rtd:
|
||||||
if os.path.isdir(ws):
|
ws = ".bin"
|
||||||
shutil.rmtree(ws)
|
if os.path.isdir(ws):
|
||||||
os.makedirs(ws)
|
shutil.rmtree(ws)
|
||||||
osname = sys.platform.lower()
|
os.makedirs(ws)
|
||||||
if osname == "darwin":
|
osname = sys.platform.lower()
|
||||||
platform = "mac"
|
if osname == "darwin":
|
||||||
else:
|
platform = "mac"
|
||||||
platform = osname
|
else:
|
||||||
pymake.getmfexes(pth=ws, platform=platform, verbose=True)
|
platform = osname
|
||||||
|
pymake.getmfexes(pth=ws, platform=platform, verbose=True)
|
||||||
|
|
||||||
# -- copy the example problems ----------------------------------------------
|
# -- convert the tutorial scripts -------------------------------------------
|
||||||
srcdir = "pysrc"
|
if not on_rtd:
|
||||||
ws = ".working"
|
cmd = ("python", "tutorials2ipynb.py")
|
||||||
if os.path.isdir(ws):
|
print(" ".join(cmd))
|
||||||
shutil.rmtree(ws)
|
os.system(" ".join(cmd))
|
||||||
os.makedirs(ws)
|
|
||||||
scripts = []
|
|
||||||
for fname in os.listdir(srcdir):
|
|
||||||
if fname.endswith(".py"):
|
|
||||||
scripts.append(fname)
|
|
||||||
src = os.path.join(srcdir, fname)
|
|
||||||
dst = os.path.join(ws, fname)
|
|
||||||
shutil.copyfile(src, dst)
|
|
||||||
|
|
||||||
# -- run the example problems -----------------------------------------------
|
|
||||||
for s in scripts:
|
|
||||||
args = ("python", s)
|
|
||||||
proc = Popen(args, stdout=PIPE, stderr=PIPE, cwd=ws)
|
|
||||||
stdout, stderr = proc.communicate()
|
|
||||||
if stdout:
|
|
||||||
print(stdout.decode("utf-8"))
|
|
||||||
if stderr:
|
|
||||||
print("Errors:\n{}".format(stderr.decode("utf-8")))
|
|
||||||
|
|
||||||
# -- copy the output to _static directory -----------------------------------
|
|
||||||
ws_dst = "_static"
|
|
||||||
if os.path.isdir(ws_dst):
|
|
||||||
shutil.rmtree(ws_dst)
|
|
||||||
os.makedirs(ws_dst)
|
|
||||||
for fname in os.listdir(ws):
|
|
||||||
if fname.endswith(".png"):
|
|
||||||
src = os.path.join(ws, fname)
|
|
||||||
dst = os.path.join(ws_dst, fname)
|
|
||||||
shutil.copyfile(src, dst)
|
|
||||||
|
|
||||||
# -- Create the flopy rst files ---------------------------------------------
|
# -- Create the flopy rst files ---------------------------------------------
|
||||||
args = ("sphinx-apidoc", "-e", "-o", "source/", "../flopy/")
|
args = ("sphinx-apidoc", "-e", "-o", "source/", "../flopy/")
|
||||||
|
@ -78,7 +53,6 @@ if stderr:
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = "flopy"
|
project = "flopy"
|
||||||
copyright = "2020, Bakker, Mark, Post, Vincent, Langevin, C. D., Hughes, J. D., White, J. T., Leaf, A. T., Paulinski, S. R., Larsen, J. D., Toews, M. W., Morway, E. D., Bellino, J. C., Starn, J. J., and Fienen, M. N."
|
copyright = "2020, Bakker, Mark, Post, Vincent, Langevin, C. D., Hughes, J. D., White, J. T., Leaf, A. T., Paulinski, S. R., Larsen, J. D., Toews, M. W., Morway, E. D., Bellino, J. C., Starn, J. J., and Fienen, M. N."
|
||||||
author = "Bakker, Mark, Post, Vincent, Langevin, C. D., Hughes, J. D., White, J. T., Leaf, A. T., Paulinski, S. R., Larsen, J. D., Toews, M. W., Morway, E. D., Bellino, J. C., Starn, J. J., and Fienen, M. N."
|
author = "Bakker, Mark, Post, Vincent, Langevin, C. D., Hughes, J. D., White, J. T., Leaf, A. T., Paulinski, S. R., Larsen, J. D., Toews, M. W., Morway, E. D., Bellino, J. C., Starn, J. J., and Fienen, M. N."
|
||||||
|
@ -111,6 +85,18 @@ extensions = [
|
||||||
"recommonmark",
|
"recommonmark",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# nbsphinx_execute_arguments = [
|
||||||
|
# "--InlineBackend.figure_formats={'svg', 'pdf'}",
|
||||||
|
# "--InlineBackend.rc={'figure.dpi': 200}",
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# Settings for GitHub actions integration
|
||||||
|
if on_rtd:
|
||||||
|
extensions.append("rtds_action")
|
||||||
|
rtds_action_github_repo = "modflowpy/flopy"
|
||||||
|
rtds_action_path = "_notebooks"
|
||||||
|
rtds_action_artifact_prefix = "notebooks-for-"
|
||||||
|
rtds_action_github_token = os.environ.get("GITHUB_TOKEN", None)
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
|
@ -183,7 +169,7 @@ html_css_files = [
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
html_short_title = "flopy"
|
html_short_title = "flopy"
|
||||||
html_favicon = ".._images/flopylogo.png"
|
html_favicon = "_images/flopylogo.png"
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
sphinx-apidoc -e -o source/ ../flopy/
|
|
||||||
make html
|
|
|
@ -1,202 +0,0 @@
|
||||||
Tutorial 1: Confined Steady-State Flow Model
|
|
||||||
============================================
|
|
||||||
|
|
||||||
This tutorial demonstrates use of FloPy to develop a simple MODFLOW model.
|
|
||||||
Note that you can access the latest version this tutorial python script from
|
|
||||||
`here <https://github.com/modflowpy/flopy/blob/develop/.docs/pysrc/tutorial01.py>`_.
|
|
||||||
|
|
||||||
Getting Started
|
|
||||||
---------------
|
|
||||||
If FloPy has been properly installed, then it can be imported as follows::
|
|
||||||
|
|
||||||
|
|
||||||
import flopy
|
|
||||||
|
|
||||||
|
|
||||||
Now that we can import flopy, we begin creating our simple MODFLOW model.
|
|
||||||
|
|
||||||
Creating the MODFLOW Model
|
|
||||||
--------------------------
|
|
||||||
One of the nice things about creating models in python is that it is very easy
|
|
||||||
to change one or two things and completely change the grid resolution for your
|
|
||||||
model. So in this example, we will design our python script so that the number
|
|
||||||
of layers, columns, and rows can be easily changed.
|
|
||||||
|
|
||||||
We can create a very simple MODFLOW model that has a basic package (BAS),
|
|
||||||
discretization input file (DIS), layer-property flow (LPF) package, output
|
|
||||||
control (OC), and preconditioned conjugate gradient (PCG) solver. Each one of
|
|
||||||
these has its own input file, which will be created automatically by flopy,
|
|
||||||
provided that we pass flopy the correct information.
|
|
||||||
|
|
||||||
Discretization
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
We start by creating our flopy model object as follows::
|
|
||||||
|
|
||||||
|
|
||||||
# Assign name and create modflow model object
|
|
||||||
modelname = 'tutorial1'
|
|
||||||
mf = flopy.modflow.Modflow(modelname, exe_name='mf2005')
|
|
||||||
|
|
||||||
Next, let's proceed by defining our model domain and creating a MODFLOW grid
|
|
||||||
to span the domain::
|
|
||||||
|
|
||||||
# Model domain and grid definition
|
|
||||||
Lx = 1000.
|
|
||||||
Ly = 1000.
|
|
||||||
ztop = 0.
|
|
||||||
zbot = -50.
|
|
||||||
nlay = 1
|
|
||||||
nrow = 10
|
|
||||||
ncol = 10
|
|
||||||
delr = Lx / ncol
|
|
||||||
delc = Ly / nrow
|
|
||||||
delv = (ztop - zbot) / nlay
|
|
||||||
botm = np.linspace(ztop, zbot, nlay + 1)
|
|
||||||
|
|
||||||
With this information, we can now create the flopy discretization object by
|
|
||||||
entering the following::
|
|
||||||
|
|
||||||
# Create the discretization object
|
|
||||||
dis = flopy.modflow.ModflowDis(mf, nlay, nrow, ncol, delr=delr, delc=delc,
|
|
||||||
top=ztop, botm=botm[1:])
|
|
||||||
|
|
||||||
The obvious question at this point is, how do I know which arguments are
|
|
||||||
required by this strange thing called flopy.modflow.ModflowDis? Fortunately,
|
|
||||||
there is an online help page for each one of the model objects. The page for
|
|
||||||
the DIS input file is located at `flopy.modflow.mfdis <mfdis.html>`__.
|
|
||||||
|
|
||||||
Basic Package
|
|
||||||
^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Next we can create a flopy object that represents the MODFLOW Basic Package.
|
|
||||||
Details on the flopy BAS class are at: `flopy.modflow.mfbas <mfbas.html>`__.
|
|
||||||
For this simple model, we will assign constant head values of 10. and 0. to the
|
|
||||||
first and last model columns (in all layers), respectively. The python code
|
|
||||||
for doing this is::
|
|
||||||
|
|
||||||
# Variables for the BAS package
|
|
||||||
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
|
||||||
ibound[:, :, 0] = -1
|
|
||||||
ibound[:, :, -1] = -1
|
|
||||||
strt = np.ones((nlay, nrow, ncol), dtype=np.float32)
|
|
||||||
strt[:, :, 0] = 10.
|
|
||||||
strt[:, :, -1] = 0.
|
|
||||||
bas = flopy.modflow.ModflowBas(mf, ibound=ibound, strt=strt)
|
|
||||||
|
|
||||||
Layer-Property Flow Package
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Details on the flopy LPF class are at: `flopy.modflow.mflpf <mflpf.html>`__.
|
|
||||||
Values of 10. are assigned for the horizontal and vertical hydraulic
|
|
||||||
conductivity::
|
|
||||||
|
|
||||||
# Add LPF package to the MODFLOW model
|
|
||||||
lpf = flopy.modflow.ModflowLpf(mf, hk=10., vka=10., ipakcb=53)
|
|
||||||
|
|
||||||
Because we did not specify a value for laytyp, Flopy will use the default value
|
|
||||||
of 0, which means that this model will be confined.
|
|
||||||
|
|
||||||
Output Control
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Details on the flopy OC class are at: `flopy.modflow.mfoc <mfoc.html>`__. Here
|
|
||||||
we can use the default OC settings by specifying the following::
|
|
||||||
|
|
||||||
# Add OC package to the MODFLOW model
|
|
||||||
spd = {(0, 0): ['print head', 'print budget', 'save head', 'save budget']}
|
|
||||||
oc = flopy.modflow.ModflowOc(mf, stress_period_data=spd, compact=True)
|
|
||||||
|
|
||||||
The stress period dictionary is used to set what output is saved for the
|
|
||||||
corresponding stress period and time step. In this case, the tuple (0, 0)
|
|
||||||
means that stress period 1 and time step 1 for MODFLOW will have output saved.
|
|
||||||
Head and budgets will be printed and head and budget information will be saved.
|
|
||||||
|
|
||||||
Preconditioned Conjugate Gradient Package
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Details on the flopy PCG class are at: `flopy.modflow.mfpcg <mfpcg.html>`__.
|
|
||||||
The default settings used by flopy will be used by specifying the following
|
|
||||||
commands::
|
|
||||||
|
|
||||||
# Add PCG package to the MODFLOW model
|
|
||||||
pcg = flopy.modflow.ModflowPcg(mf)
|
|
||||||
|
|
||||||
Writing the MODFLOW Data Files
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The MODFLOW input data files are written by simply issuing the following::
|
|
||||||
|
|
||||||
# Write the MODFLOW model input files
|
|
||||||
mf.write_input()
|
|
||||||
|
|
||||||
Running the Modeling
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Flopy can also be used to run the model. The model object (mf in this example)
|
|
||||||
has an attached method that will run the model. For this to work, the MODFLOW
|
|
||||||
program must be located somewhere within the system path, or within the working
|
|
||||||
directory. In this example, we have specified that the name of the executable
|
|
||||||
program is 'mf2005'. Issue the following to run the model::
|
|
||||||
|
|
||||||
# Run the MODFLOW model
|
|
||||||
success, buff = mf.run_model()
|
|
||||||
|
|
||||||
Here we have used run_model, and we could also have specified values for the
|
|
||||||
optional keywords silent, pause, and report.
|
|
||||||
|
|
||||||
Post-Processing the Results
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
Now that we have successfully built and run our MODFLOW model, we can look at
|
|
||||||
the results. MODFLOW writes the simulated heads to a binary data output file.
|
|
||||||
We cannot look at these heads with a text editor, but flopy has a binary
|
|
||||||
utility that can be used to read the heads. The following statements will
|
|
||||||
read the binary head file and create a plot of simulated heads for layer 1::
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import flopy.utils.binaryfile as bf
|
|
||||||
plt.subplot(1, 1, 1, aspect='equal')
|
|
||||||
hds = bf.HeadFile(modelname + '.hds')
|
|
||||||
head = hds.get_data(totim=1.0)
|
|
||||||
levels = np.arange(1, 10, 1)
|
|
||||||
extent = (delr / 2., Lx - delr / 2., Ly - delc / 2., delc / 2.)
|
|
||||||
plt.contour(head[0, :, :], levels=levels, extent=extent)
|
|
||||||
plt.savefig('tutorial1a.png')
|
|
||||||
|
|
||||||
If everything has worked properly, you should see the following head contours.
|
|
||||||
|
|
||||||
.. figure:: _static/tutorial1a.png
|
|
||||||
:alt: head contours in first layer
|
|
||||||
:scale: 100 %
|
|
||||||
:align: left
|
|
||||||
|
|
||||||
Flopy also has some pre-canned plotting capabilities can can be accessed using
|
|
||||||
the PlotMapView class. The following code shows how to use the plotmapview
|
|
||||||
class to plot boundary conditions (IBOUND), plot the grid, plot head contours,
|
|
||||||
and plot vectors::
|
|
||||||
|
|
||||||
fig = plt.figure(figsize=(10,10))
|
|
||||||
ax = fig.add_subplot(1, 1, 1, aspect='equal')
|
|
||||||
|
|
||||||
hds = bf.HeadFile(modelname + '.hds')
|
|
||||||
times = hds.get_times()
|
|
||||||
head = hds.get_data(totim=times[-1])
|
|
||||||
levels = np.linspace(0, 10, 11)
|
|
||||||
|
|
||||||
cbb = bf.CellBudgetFile(modelname + '.cbc')
|
|
||||||
kstpkper_list = cbb.get_kstpkper()
|
|
||||||
frf = cbb.get_data(text='FLOW RIGHT FACE', totim=times[-1])[0]
|
|
||||||
fff = cbb.get_data(text='FLOW FRONT FACE', totim=times[-1])[0]
|
|
||||||
|
|
||||||
pmv = flopy.plot.PlotMapView(model=mf, layer=0)
|
|
||||||
qm = pmv.plot_ibound()
|
|
||||||
lc = pmv.plot_grid()
|
|
||||||
cs = pmv.contour_array(head, levels=levels)
|
|
||||||
quiver = pmv.plot_discharge(frf, fff, head=head)
|
|
||||||
plt.savefig('tutorial1b.png')
|
|
||||||
|
|
||||||
.. figure:: _static/tutorial1b.png
|
|
||||||
:alt: head contours in first layer
|
|
||||||
:scale: 100 %
|
|
||||||
:align: left
|
|
|
@ -1,295 +0,0 @@
|
||||||
Tutorial 2: Unconfined Transient Flow Model
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
In this example, we will convert the tutorial 1 model into an unconfined,
|
|
||||||
transient flow model with time varying boundaries. Instead of using constant
|
|
||||||
heads for the left and right boundaries (by setting ibound to -1), we will use
|
|
||||||
general head boundaries. We will have the model consider the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
* Initial conditions -- head is 10.0 everywhere
|
|
||||||
* Period 1 (1 day) -- steady state with left and right GHB stage = 10.
|
|
||||||
* Period 2 (100 days) -- left GHB with stage = 10., right GHB with stage set
|
|
||||||
to 0.
|
|
||||||
* Period 3 (100 days) -- pumping well at model center with rate = -500., left
|
|
||||||
and right GHB = 10., and 0.
|
|
||||||
|
|
||||||
We will start with selected model commands from the previous tutorial.
|
|
||||||
|
|
||||||
Note that you can access the latest version of this tutorial python script from
|
|
||||||
`here <https://github.com/modflowpy/flopy/blob/develop/.docs/pysrc/tutorial02.py>`_.
|
|
||||||
|
|
||||||
Getting Started
|
|
||||||
---------------
|
|
||||||
As shown in the previous tutorial, import flopy using your preferred method,
|
|
||||||
such as::
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import flopy
|
|
||||||
|
|
||||||
Creating the MODFLOW Model
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Define the Model Extent, Grid Resolution, and Characteristics
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Assign the model information::
|
|
||||||
|
|
||||||
# Model domain and grid definition
|
|
||||||
Lx = 1000.
|
|
||||||
Ly = 1000.
|
|
||||||
ztop = 10.
|
|
||||||
zbot = -50.
|
|
||||||
nlay = 1
|
|
||||||
nrow = 10
|
|
||||||
ncol = 10
|
|
||||||
delr = Lx / ncol
|
|
||||||
delc = Ly / nrow
|
|
||||||
delv = (ztop - zbot) / nlay
|
|
||||||
botm = np.linspace(ztop, zbot, nlay + 1)
|
|
||||||
hk = 1.
|
|
||||||
vka = 1.
|
|
||||||
sy = 0.1
|
|
||||||
ss = 1.e-4
|
|
||||||
laytyp = 1
|
|
||||||
|
|
||||||
# Variables for the BAS package
|
|
||||||
# Note that changes from the previous tutorial!
|
|
||||||
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
|
||||||
strt = 10. * np.ones((nlay, nrow, ncol), dtype=np.float32)
|
|
||||||
|
|
||||||
|
|
||||||
Define the Stress Periods
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
To create a model with multiple stress periods, we need to define nper, perlen,
|
|
||||||
nstp, and steady. This is done in the following block in a manner that allows
|
|
||||||
us to pass these variable directly to the discretization object::
|
|
||||||
|
|
||||||
# Time step parameters
|
|
||||||
nper = 3
|
|
||||||
perlen = [1, 100, 100]
|
|
||||||
nstp = [1, 100, 100]
|
|
||||||
steady = [True, False, False]
|
|
||||||
|
|
||||||
Create Time-Invariant Flopy Objects
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
With this information, we can now create the static flopy objects that do
|
|
||||||
not change with time::
|
|
||||||
|
|
||||||
# Flopy objects
|
|
||||||
modelname = 'tutorial2'
|
|
||||||
mf = flopy.modflow.Modflow(modelname, exe_name='mf2005')
|
|
||||||
dis = flopy.modflow.ModflowDis(mf, nlay, nrow, ncol, delr=delr, delc=delc,
|
|
||||||
top=ztop, botm=botm[1:],
|
|
||||||
nper=nper, perlen=perlen, nstp=nstp, steady=steady)
|
|
||||||
bas = flopy.modflow.ModflowBas(mf, ibound=ibound, strt=strt)
|
|
||||||
lpf = flopy.modflow.ModflowLpf(mf, hk=hk, vka=vka, sy=sy, ss=ss, laytyp=laytyp, ipakcb=53)
|
|
||||||
pcg = flopy.modflow.ModflowPcg(mf)
|
|
||||||
|
|
||||||
|
|
||||||
Transient General-Head Boundary Package
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
At this point, our model is ready to add our transient boundary packages.
|
|
||||||
First, we will create the GHB object, which is of the following
|
|
||||||
type: `flopy.modflow.ModflowGhb <mfghb.html>`__.
|
|
||||||
|
|
||||||
The key to creating Flopy transient boundary packages is recognizing that
|
|
||||||
the boundary data is stored in a dictionary with key values equal to the
|
|
||||||
zero-based stress period number and values equal to the boundary conditions
|
|
||||||
for that stress period. For a GHB the values can be a two-dimensional nested
|
|
||||||
list of [layer, row, column, stage, conductance]::
|
|
||||||
|
|
||||||
# Make list for stress period 1
|
|
||||||
stageleft = 10.
|
|
||||||
stageright = 10.
|
|
||||||
bound_sp1 = []
|
|
||||||
for il in range(nlay):
|
|
||||||
condleft = hk * (stageleft - zbot) * delc
|
|
||||||
condright = hk * (stageright - zbot) * delc
|
|
||||||
for ir in range(nrow):
|
|
||||||
bound_sp1.append([il, ir, 0, stageleft, condleft])
|
|
||||||
bound_sp1.append([il, ir, ncol - 1, stageright, condright])
|
|
||||||
print('Adding ', len(bound_sp1), 'GHBs for stress period 1.')
|
|
||||||
|
|
||||||
# Make list for stress period 2
|
|
||||||
stageleft = 10.
|
|
||||||
stageright = 0.
|
|
||||||
condleft = hk * (stageleft - zbot) * delc
|
|
||||||
condright = hk * (stageright - zbot) * delc
|
|
||||||
bound_sp2 = []
|
|
||||||
for il in range(nlay):
|
|
||||||
for ir in range(nrow):
|
|
||||||
bound_sp2.append([il, ir, 0, stageleft, condleft])
|
|
||||||
bound_sp2.append([il, ir, ncol - 1, stageright, condright])
|
|
||||||
print('Adding ', len(bound_sp2), 'GHBs for stress period 2.')
|
|
||||||
|
|
||||||
# We do not need to add a dictionary entry for stress period 3.
|
|
||||||
# Flopy will automatically take the list from stress period 2 and apply it
|
|
||||||
# to the end of the simulation, if necessary
|
|
||||||
stress_period_data = {0: bound_sp1, 1: bound_sp2}
|
|
||||||
|
|
||||||
# Create the flopy ghb object
|
|
||||||
ghb = flopy.modflow.ModflowGhb(mf, stress_period_data=stress_period_data)
|
|
||||||
|
|
||||||
|
|
||||||
Transient Well Package
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Now we can create the well package object, which is of the type,
|
|
||||||
`flopy.modflow.ModflowWel <mfwel.html>`__.::
|
|
||||||
|
|
||||||
# Create the well package
|
|
||||||
# Remember to use zero-based layer, row, column indices!
|
|
||||||
pumping_rate = -500.
|
|
||||||
wel_sp1 = [[0, nrow/2 - 1, ncol/2 - 1, 0.]]
|
|
||||||
wel_sp2 = [[0, nrow/2 - 1, ncol/2 - 1, 0.]]
|
|
||||||
wel_sp3 = [[0, nrow/2 - 1, ncol/2 - 1, pumping_rate]]
|
|
||||||
stress_period_data = {0: wel_sp1, 1: wel_sp2, 2: wel_sp3}
|
|
||||||
wel = flopy.modflow.ModflowWel(mf, stress_period_data=stress_period_data)
|
|
||||||
|
|
||||||
|
|
||||||
Output Control
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Here we create the output control package object, which is of the
|
|
||||||
type `flopy.modflow.ModflowOc <mfoc.html>`__.::
|
|
||||||
|
|
||||||
stress_period_data = {}
|
|
||||||
for kper in range(nper):
|
|
||||||
for kstp in range(nstp[kper]):
|
|
||||||
stress_period_data[(kper, kstp)] = ['save head',
|
|
||||||
'save drawdown',
|
|
||||||
'save budget',
|
|
||||||
'print head',
|
|
||||||
'print budget']
|
|
||||||
oc = flopy.modflow.ModflowOc(mf, stress_period_data=stress_period_data,
|
|
||||||
compact=True)
|
|
||||||
|
|
||||||
|
|
||||||
Running the Modeling
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Run the model with the run_model method, which returns a success flag and
|
|
||||||
the stream of output. With run_model, we have some finer control, that allows us to suppress the output.::
|
|
||||||
|
|
||||||
# Write the model input files
|
|
||||||
mf.write_input()
|
|
||||||
|
|
||||||
# Run the model
|
|
||||||
success, mfoutput = mf.run_model(silent=True, pause=False, report=True)
|
|
||||||
if not success:
|
|
||||||
raise Exception('MODFLOW did not terminate normally.')
|
|
||||||
|
|
||||||
Post-Processing the Results
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
Once again, we can read heads from the MODFLOW binary output file, using
|
|
||||||
the `flopy.utils.binaryfile <binaryfile.html>`__ module. Included with the
|
|
||||||
HeadFile object are several methods that we will use here:
|
|
||||||
|
|
||||||
* get_times() will return a list of times contained in the binary head file
|
|
||||||
* get_data() will return a three-dimensional head array for the specified time
|
|
||||||
* get_ts() will return a time series array [ntimes, headval] for the specified cell
|
|
||||||
|
|
||||||
Using these methods, we can create head plots and hydrographs from the
|
|
||||||
model results.::
|
|
||||||
|
|
||||||
# Imports
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import flopy.utils.binaryfile as bf
|
|
||||||
|
|
||||||
# Create the headfile and budget file objects
|
|
||||||
headobj = bf.HeadFile(modelname + '.hds')
|
|
||||||
times = headobj.get_times()
|
|
||||||
cbb = bf.CellBudgetFile(modelname + '.cbc')
|
|
||||||
|
|
||||||
# Setup contour parameters
|
|
||||||
levels = np.linspace(0, 10, 11)
|
|
||||||
extent = (delr / 2., Lx - delr / 2., delc / 2., Ly - delc / 2.)
|
|
||||||
print('Levels: ', levels)
|
|
||||||
print('Extent: ', extent)
|
|
||||||
|
|
||||||
# Well point
|
|
||||||
wpt = ((float(ncol / 2) - 0.5) * delr, (float(nrow / 2 - 1) + 0.5) * delc)
|
|
||||||
wpt = (450., 550.)
|
|
||||||
|
|
||||||
# Make the plots
|
|
||||||
mytimes = [1.0, 101.0, 201.0]
|
|
||||||
for iplot, time in enumerate(mytimes):
|
|
||||||
print('*****Processing time: ', time)
|
|
||||||
head = headobj.get_data(totim=time)
|
|
||||||
#Print statistics
|
|
||||||
print('Head statistics')
|
|
||||||
print(' min: ', head.min())
|
|
||||||
print(' max: ', head.max())
|
|
||||||
print(' std: ', head.std())
|
|
||||||
|
|
||||||
# Extract flow right face and flow front face
|
|
||||||
frf = cbb.get_data(text='FLOW RIGHT FACE', totim=time)[0]
|
|
||||||
fff = cbb.get_data(text='FLOW FRONT FACE', totim=time)[0]
|
|
||||||
|
|
||||||
#Create the plot
|
|
||||||
f = plt.figure()
|
|
||||||
plt.subplot(1, 1, 1, aspect='equal')
|
|
||||||
plt.title('stress period ' + str(iplot + 1))
|
|
||||||
|
|
||||||
|
|
||||||
pmv = flopy.plot.PlotMapView(model=mf, layer=0)
|
|
||||||
qm = pmv.plot_ibound()
|
|
||||||
lc = pmv.plot_grid()
|
|
||||||
qm = pmv.plot_bc('GHB', alpha=0.5)
|
|
||||||
cs = pmv.contour_array(head, levels=levels)
|
|
||||||
plt.clabel(cs, inline=1, fontsize=10, fmt='%1.1f')
|
|
||||||
quiver = pmv.plot_discharge(frf, fff, head=head)
|
|
||||||
|
|
||||||
|
|
||||||
mfc = 'None'
|
|
||||||
if (iplot + 1) == len(mytimes):
|
|
||||||
mfc='black'
|
|
||||||
plt.plot(wpt[0], wpt[1], lw=0, marker='o', markersize=8,
|
|
||||||
markeredgewidth=0.5,
|
|
||||||
markeredgecolor='black', markerfacecolor=mfc, zorder=9)
|
|
||||||
plt.text(wpt[0] + 25, wpt[1] - 25, 'well', size=12, zorder=12)
|
|
||||||
plt.savefig('tutorial2-{}.png'.format(iplot))
|
|
||||||
|
|
||||||
If everything has worked properly, you should see the following head contours.
|
|
||||||
|
|
||||||
.. figure:: _static/tutorial2-0.png
|
|
||||||
:alt: head contours for stress period 1
|
|
||||||
:scale: 100 %
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
.. figure:: _static/tutorial2-1.png
|
|
||||||
:alt: head contours for stress period 2
|
|
||||||
:scale: 100 %
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
.. figure:: _static/tutorial2-2.png
|
|
||||||
:alt: head contours for stress period 3
|
|
||||||
:scale: 100 %
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
|
|
||||||
Plot Head Versus Time
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
Make a plot of head versus time by extracting the binary heads from
|
|
||||||
the headobj::
|
|
||||||
|
|
||||||
# Plot the head versus time
|
|
||||||
idx = (0, int(nrow / 2) - 1, int(ncol / 2) - 1)
|
|
||||||
ts = headobj.get_ts(idx)
|
|
||||||
plt.subplot(1, 1, 1)
|
|
||||||
ttl = 'Head at cell ({0},{1},{2})'.format(idx[0] + 1, idx[1] + 1, idx[2] + 1)
|
|
||||||
plt.title(ttl)
|
|
||||||
plt.xlabel('time')
|
|
||||||
plt.ylabel('head')
|
|
||||||
plt.plot(ts[:, 0], ts[:, 1], 'bo-')
|
|
||||||
plt.savefig('tutorial2-ts.png')
|
|
||||||
|
|
||||||
.. figure:: _static/tutorial2-ts.png
|
|
||||||
:alt: head contours in first layer
|
|
||||||
:scale: 100 %
|
|
||||||
:align: center
|
|
|
@ -1,10 +1,33 @@
|
||||||
Tutorials
|
Tutorials
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
MODFLOW 6 Tutorials
|
||||||
|
-----------------
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
tutorial1
|
_notebooks/tutorial01_mf6
|
||||||
tutorial2
|
|
||||||
|
MODFLOW Tutorials
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
_notebooks/tutorial01_mf
|
||||||
|
_notebooks/tutorial02_mf
|
||||||
|
|
||||||
|
SEAWAT Tutorials
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
_notebooks/tutorial01_seawat
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
wpth = ".working"
|
||||||
|
if os.path.isdir(wpth):
|
||||||
|
shutil.rmtree(wpth)
|
||||||
|
os.makedirs(wpth)
|
||||||
|
# copy the python files
|
||||||
|
pth = os.path.join("..", "examples", "Tutorials")
|
||||||
|
py_files = [file_name for file_name in os.listdir(pth)
|
||||||
|
if file_name.endswith(".py")]
|
||||||
|
for file_name in py_files:
|
||||||
|
src = os.path.join(pth, file_name)
|
||||||
|
dst = os.path.join(wpth, file_name)
|
||||||
|
shutil.copyfile(src, dst)
|
||||||
|
py_pth = os.path.join(wpth, "*.py")
|
||||||
|
cmd = (
|
||||||
|
"jupytext",
|
||||||
|
"--to ipynb",
|
||||||
|
"--execute",
|
||||||
|
py_pth,
|
||||||
|
)
|
||||||
|
print(" ".join(cmd))
|
||||||
|
os.system(" ".join(cmd))
|
||||||
|
|
||||||
|
npth = "_notebooks"
|
||||||
|
# copy notebooks
|
||||||
|
if os.path.isdir(npth):
|
||||||
|
shutil.rmtree(npth)
|
||||||
|
os.makedirs(npth)
|
||||||
|
for file_name in py_files:
|
||||||
|
src = os.path.join(wpth, file_name.replace(".py", ".ipynb"))
|
||||||
|
dst = os.path.join(npth, file_name.replace(".py", ".ipynb"))
|
||||||
|
shutil.copyfile(src, dst)
|
||||||
|
shutil.rmtree(".working")
|
||||||
|
|
|
@ -104,12 +104,18 @@ jobs:
|
||||||
activate-environment: flopy
|
activate-environment: flopy
|
||||||
use-only-tar-bz2: true
|
use-only-tar-bz2: true
|
||||||
|
|
||||||
- name: Add jupyter and nbconvert to one matrix entry
|
- name: Add jupyter and nbconvert to notebooks run
|
||||||
if: matrix.run-type == 'nb'
|
if: matrix.run-type == 'nb'
|
||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
run: |
|
run: |
|
||||||
conda install -n flopy -c conda-forge jupyter nbconvert
|
conda install -n flopy -c conda-forge jupyter nbconvert
|
||||||
|
|
||||||
|
- name: Add jupyter and jupytext to scripts run
|
||||||
|
if: matrix.run-type == 'script'
|
||||||
|
shell: bash -l {0}
|
||||||
|
run: |
|
||||||
|
conda install -n flopy -c conda-forge jupyter jupytext
|
||||||
|
|
||||||
- name: Add packages to flopy environment
|
- name: Add packages to flopy environment
|
||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
run: |
|
run: |
|
||||||
|
@ -154,3 +160,44 @@ jobs:
|
||||||
uses: codecov/codecov-action@v1.0.12
|
uses: codecov/codecov-action@v1.0.12
|
||||||
with:
|
with:
|
||||||
file: ./coverage.xml
|
file: ./coverage.xml
|
||||||
|
|
||||||
|
- name: Run jupytext on tutorials
|
||||||
|
if: matrix.run-type == 'script'
|
||||||
|
shell: bash -l {0}
|
||||||
|
run: |
|
||||||
|
cd .docs/
|
||||||
|
python tutorials2ipynb.py
|
||||||
|
cd ../
|
||||||
|
|
||||||
|
- name: Upload completed jupyter notebooks as an artifact for ReadtheDocs
|
||||||
|
if: matrix.run-type == 'script' && github.repository_owner == 'modflowpy'
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: notebooks-for-${{ github.sha }}
|
||||||
|
path: |
|
||||||
|
.docs/_notebooks
|
||||||
|
|
||||||
|
# trigger rtd if previous job was successful
|
||||||
|
rtd:
|
||||||
|
name: ReadtheDocs
|
||||||
|
needs: flopyCI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
if: github.repository_owner == 'modflowpy'
|
||||||
|
steps:
|
||||||
|
- name: Checkout flopy repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Output repo information
|
||||||
|
run: |
|
||||||
|
echo ${{ github.repository_owner }}
|
||||||
|
echo ${{ github.repository }}
|
||||||
|
echo ${{ github.ref }}
|
||||||
|
|
||||||
|
- name: Trigger RTDs build on master and develop branches
|
||||||
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop'
|
||||||
|
uses: dfm/rtds-action@v1.0.0
|
||||||
|
with:
|
||||||
|
webhook_url: ${{ secrets.RTDS_WEBHOOK_URL }}
|
||||||
|
webhook_token: ${{ secrets.RTDS_WEBHOOK_TOKEN }}
|
||||||
|
commit_ref: ${{ github.ref }}
|
||||||
|
|
|
@ -85,4 +85,6 @@ autotest/.noseids
|
||||||
.docs/_templates
|
.docs/_templates
|
||||||
.docs/source
|
.docs/source
|
||||||
.docs/.bin
|
.docs/.bin
|
||||||
|
.docs/_temp
|
||||||
|
.docs/_notebooks
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import print_function
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
exclude = ['flopy_swi2_ex2.py', 'flopy_swi2_ex5.py']
|
exclude = ['flopy_swi2_ex2.py', 'flopy_swi2_ex5.py']
|
||||||
for arg in sys.argv:
|
for arg in sys.argv:
|
||||||
|
@ -10,6 +11,7 @@ for arg in sys.argv:
|
||||||
exclude = []
|
exclude = []
|
||||||
|
|
||||||
sdir = os.path.join('..', 'examples', 'scripts')
|
sdir = os.path.join('..', 'examples', 'scripts')
|
||||||
|
tdir = os.path.join("..", "examples", "Tutorials")
|
||||||
|
|
||||||
# make working directories
|
# make working directories
|
||||||
tempdir = os.path.join('.', 'temp')
|
tempdir = os.path.join('.', 'temp')
|
||||||
|
@ -17,17 +19,20 @@ if os.path.isdir(tempdir):
|
||||||
shutil.rmtree(tempdir)
|
shutil.rmtree(tempdir)
|
||||||
os.mkdir(tempdir)
|
os.mkdir(tempdir)
|
||||||
|
|
||||||
testdir = os.path.join('.', 'temp', 'scripts')
|
testdirs = (os.path.join('.', 'temp', 'scripts'),
|
||||||
if os.path.isdir(testdir):
|
os.path.join('.', 'temp', 'tutorials'),
|
||||||
shutil.rmtree(testdir)
|
)
|
||||||
os.mkdir(testdir)
|
for testdir in testdirs:
|
||||||
|
if os.path.isdir(testdir):
|
||||||
|
shutil.rmtree(testdir)
|
||||||
|
os.mkdir(testdir)
|
||||||
|
|
||||||
# add testdir to python path
|
# add testdir to python path
|
||||||
sys.path.append(testdir)
|
sys.path.append(testdir)
|
||||||
|
|
||||||
|
|
||||||
def copy_scripts():
|
def copy_scripts(src_dir, dst_dir):
|
||||||
files = [f for f in os.listdir(sdir) if f.endswith('.py')]
|
files = [f for f in sorted(os.listdir(src_dir)) if f.endswith('.py')]
|
||||||
|
|
||||||
# exclude unwanted files
|
# exclude unwanted files
|
||||||
for e in exclude:
|
for e in exclude:
|
||||||
|
@ -35,13 +40,13 @@ def copy_scripts():
|
||||||
files.remove(e)
|
files.remove(e)
|
||||||
|
|
||||||
# copy files
|
# copy files
|
||||||
for fn in files:
|
for file_name in files:
|
||||||
pth = os.path.join(sdir, fn)
|
src = os.path.join(src_dir, file_name)
|
||||||
opth = os.path.join(testdir, fn)
|
dst = os.path.join(dst_dir, file_name)
|
||||||
|
|
||||||
# copy script
|
# copy script
|
||||||
print('copying {} from {} to {}'.format(fn, sdir, testdir))
|
print('copying {} from {} to {}'.format(file_name, src_dir, testdir))
|
||||||
shutil.copyfile(pth, opth)
|
shutil.copyfile(src, dst)
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
@ -52,7 +57,7 @@ def import_from(mod, name):
|
||||||
return main
|
return main
|
||||||
|
|
||||||
|
|
||||||
def run_scripts(fn):
|
def run_scripts(fn, testdir):
|
||||||
# import run function from scripts
|
# import run function from scripts
|
||||||
s = os.path.splitext(fn)[0]
|
s = os.path.splitext(fn)[0]
|
||||||
run = import_from(s, 'run')
|
run = import_from(s, 'run')
|
||||||
|
@ -73,19 +78,42 @@ def run_scripts(fn):
|
||||||
assert ival == 0, 'could not run {}'.format(fn)
|
assert ival == 0, 'could not run {}'.format(fn)
|
||||||
|
|
||||||
|
|
||||||
def test_notebooks():
|
def run_tutorial_scripts(fn, testdir):
|
||||||
|
args = ("python", fn)
|
||||||
|
print("running...'{}'".format(" ".join(args)))
|
||||||
|
proc = Popen(args, stdout=PIPE, stderr=PIPE, cwd=testdir)
|
||||||
|
stdout, stderr = proc.communicate()
|
||||||
|
if stdout:
|
||||||
|
print(stdout.decode("utf-8"))
|
||||||
|
if stderr:
|
||||||
|
print("Errors:\n{}".format(stderr.decode("utf-8")))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def test_scripts():
|
||||||
# get list of scripts to run
|
# get list of scripts to run
|
||||||
files = copy_scripts()
|
files = copy_scripts(sdir, testdirs[0])
|
||||||
|
|
||||||
for fn in files:
|
for fn in files:
|
||||||
yield run_scripts, fn
|
yield run_scripts, fn, testdirs[0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_tutorial_scripts():
|
||||||
|
# get list of scripts to run
|
||||||
|
files = copy_scripts(tdir, testdirs[1])
|
||||||
|
|
||||||
|
for fn in files:
|
||||||
|
yield run_tutorial_scripts, fn, testdirs[1]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
# # get list of scripts to run
|
||||||
|
# files = copy_scripts(sdir, testdirs[0])
|
||||||
|
# for fn in files:
|
||||||
|
# run_scripts(fn, testdirs[0])
|
||||||
|
|
||||||
# get list of scripts to run
|
# get list of tutorial scripts to run
|
||||||
files = copy_scripts()
|
files = copy_scripts(tdir, testdirs[1])
|
||||||
|
|
||||||
for fn in files:
|
for fn in files:
|
||||||
run_scripts(fn)
|
run_tutorial_scripts(fn, testdirs[1])
|
||||||
|
|
|
@ -4,6 +4,7 @@ These are the examples that are distributed with MODFLOW-USG.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import flopy
|
import flopy
|
||||||
import pymake
|
import pymake
|
||||||
|
|
||||||
|
@ -37,6 +38,10 @@ v = flopy.which(mfnwt_exe)
|
||||||
run = True
|
run = True
|
||||||
if v is None:
|
if v is None:
|
||||||
run = False
|
run = False
|
||||||
|
# fix for intermittent CI failure on windows
|
||||||
|
else:
|
||||||
|
if sys.platform.lower() in ("win32", "darwin"):
|
||||||
|
run = False
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
import numpy as np
|
|
||||||
import flopy
|
|
||||||
|
|
||||||
# Assign name and create modflow model object
|
|
||||||
modelname = "tutorial1"
|
|
||||||
mf = flopy.modflow.Modflow(modelname, exe_name="mf2005")
|
|
||||||
|
|
||||||
# Model domain and grid definition
|
|
||||||
Lx = 1000.0
|
|
||||||
Ly = 1000.0
|
|
||||||
ztop = 0.0
|
|
||||||
zbot = -50.0
|
|
||||||
nlay = 1
|
|
||||||
nrow = 10
|
|
||||||
ncol = 10
|
|
||||||
delr = Lx / ncol
|
|
||||||
delc = Ly / nrow
|
|
||||||
delv = (ztop - zbot) / nlay
|
|
||||||
botm = np.linspace(ztop, zbot, nlay + 1)
|
|
||||||
|
|
||||||
# Create the discretization object
|
|
||||||
dis = flopy.modflow.ModflowDis(
|
|
||||||
mf, nlay, nrow, ncol, delr=delr, delc=delc, top=ztop, botm=botm[1:]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Variables for the BAS package
|
|
||||||
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
|
||||||
ibound[:, :, 0] = -1
|
|
||||||
ibound[:, :, -1] = -1
|
|
||||||
strt = np.ones((nlay, nrow, ncol), dtype=np.float32)
|
|
||||||
strt[:, :, 0] = 10.0
|
|
||||||
strt[:, :, -1] = 0.0
|
|
||||||
bas = flopy.modflow.ModflowBas(mf, ibound=ibound, strt=strt)
|
|
||||||
|
|
||||||
# Add LPF package to the MODFLOW model
|
|
||||||
lpf = flopy.modflow.ModflowLpf(mf, hk=10.0, vka=10.0, ipakcb=53)
|
|
||||||
|
|
||||||
# Add OC package to the MODFLOW model
|
|
||||||
spd = {(0, 0): ["print head", "print budget", "save head", "save budget"]}
|
|
||||||
oc = flopy.modflow.ModflowOc(mf, stress_period_data=spd, compact=True)
|
|
||||||
|
|
||||||
# Add PCG package to the MODFLOW model
|
|
||||||
pcg = flopy.modflow.ModflowPcg(mf)
|
|
||||||
|
|
||||||
# Write the MODFLOW model input files
|
|
||||||
mf.write_input()
|
|
||||||
|
|
||||||
# Run the MODFLOW model
|
|
||||||
success, buff = mf.run_model()
|
|
||||||
|
|
||||||
# Post process the results
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import flopy.utils.binaryfile as bf
|
|
||||||
|
|
||||||
plt.subplot(1, 1, 1, aspect="equal")
|
|
||||||
hds = bf.HeadFile(modelname + ".hds")
|
|
||||||
head = hds.get_data(totim=1.0)
|
|
||||||
levels = np.arange(1, 10, 1)
|
|
||||||
extent = (delr / 2.0, Lx - delr / 2.0, Ly - delc / 2.0, delc / 2.0)
|
|
||||||
plt.contour(head[0, :, :], levels=levels, extent=extent)
|
|
||||||
plt.savefig("tutorial1a.png")
|
|
||||||
|
|
||||||
fig = plt.figure(figsize=(10, 10))
|
|
||||||
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
|
||||||
|
|
||||||
hds = bf.HeadFile(modelname + ".hds")
|
|
||||||
times = hds.get_times()
|
|
||||||
head = hds.get_data(totim=times[-1])
|
|
||||||
levels = np.linspace(0, 10, 11)
|
|
||||||
|
|
||||||
cbb = bf.CellBudgetFile(modelname + ".cbc")
|
|
||||||
kstpkper_list = cbb.get_kstpkper()
|
|
||||||
frf = cbb.get_data(text="FLOW RIGHT FACE", totim=times[-1])[0]
|
|
||||||
fff = cbb.get_data(text="FLOW FRONT FACE", totim=times[-1])[0]
|
|
||||||
|
|
||||||
modelmap = flopy.plot.ModelMap(model=mf, layer=0)
|
|
||||||
qm = modelmap.plot_ibound()
|
|
||||||
lc = modelmap.plot_grid()
|
|
||||||
cs = modelmap.contour_array(head, levels=levels)
|
|
||||||
quiver = modelmap.plot_discharge(frf, fff, head=head)
|
|
||||||
plt.savefig("tutorial1b.png")
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
# ---
|
||||||
|
# jupyter:
|
||||||
|
# jupytext:
|
||||||
|
# text_representation:
|
||||||
|
# extension: .py
|
||||||
|
# format_name: light
|
||||||
|
# format_version: '1.5'
|
||||||
|
# jupytext_version: 1.5.1
|
||||||
|
# kernelspec:
|
||||||
|
# display_name: Python 3
|
||||||
|
# language: python
|
||||||
|
# name: python3
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# # MODFLOW Tutorial 1: Confined Steady-State Flow Model
|
||||||
|
#
|
||||||
|
# This tutorial demonstrates use of FloPy to develop a simple MODFLOW-2005
|
||||||
|
# model.
|
||||||
|
|
||||||
|
# ## Getting Started
|
||||||
|
#
|
||||||
|
# If FloPy has been properly installed, then it can be imported as follows:
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import flopy
|
||||||
|
|
||||||
|
# Now that we can import flopy, we begin creating our simple MODFLOW model.
|
||||||
|
# numpy is imported to create arrays of model data.
|
||||||
|
|
||||||
|
# ## Creating the MODFLOW Model
|
||||||
|
#
|
||||||
|
# One of the nice things about creating models in python is that it is very
|
||||||
|
# easy to change one or two things and completely change the grid resolution
|
||||||
|
# for your model. So in this example, we will design our python script so
|
||||||
|
# that the number of layers, columns, and rows can be easily changed.
|
||||||
|
#
|
||||||
|
# We can create a very simple MODFLOW model that has a basic package (BAS),
|
||||||
|
# discretization input file (DIS), layer-property flow (LPF) package, output
|
||||||
|
# control (OC), and preconditioned conjugate gradient (PCG) solver. Each one
|
||||||
|
# of these has its own input file, which will be created automatically by
|
||||||
|
# flopy, provided that we pass flopy the correct information.
|
||||||
|
|
||||||
|
# ### Discretization
|
||||||
|
#
|
||||||
|
# We start by creating our flopy model object.
|
||||||
|
|
||||||
|
modelname = "tutorial1_mf"
|
||||||
|
mf = flopy.modflow.Modflow(modelname, exe_name="mf2005")
|
||||||
|
|
||||||
|
# Next, let's proceed by defining our model domain and creating a MODFLOW grid
|
||||||
|
# to span the domain.
|
||||||
|
|
||||||
|
Lx = 1000.0
|
||||||
|
Ly = 1000.0
|
||||||
|
ztop = 0.0
|
||||||
|
zbot = -50.0
|
||||||
|
nlay = 1
|
||||||
|
nrow = 10
|
||||||
|
ncol = 10
|
||||||
|
delr = Lx / ncol
|
||||||
|
delc = Ly / nrow
|
||||||
|
delv = (ztop - zbot) / nlay
|
||||||
|
botm = np.linspace(ztop, zbot, nlay + 1)
|
||||||
|
|
||||||
|
# With this information, we can now create the flopy discretization object by
|
||||||
|
# entering the following:
|
||||||
|
|
||||||
|
dis = flopy.modflow.ModflowDis(
|
||||||
|
mf, nlay, nrow, ncol, delr=delr, delc=delc, top=ztop, botm=botm[1:]
|
||||||
|
)
|
||||||
|
|
||||||
|
# ### Basic Package
|
||||||
|
#
|
||||||
|
# Next we can create a flopy object that represents the MODFLOW Basic Package.
|
||||||
|
# For this simple model, we will assign constant head values of 10. and 0. to
|
||||||
|
# the first and last model columns (in all layers), respectively. The python
|
||||||
|
# code for doing this is:
|
||||||
|
|
||||||
|
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
||||||
|
ibound[:, :, 0] = -1
|
||||||
|
ibound[:, :, -1] = -1
|
||||||
|
strt = np.ones((nlay, nrow, ncol), dtype=np.float32)
|
||||||
|
strt[:, :, 0] = 10.0
|
||||||
|
strt[:, :, -1] = 0.0
|
||||||
|
bas = flopy.modflow.ModflowBas(mf, ibound=ibound, strt=strt)
|
||||||
|
|
||||||
|
# ### Layer-Property Flow Package
|
||||||
|
|
||||||
|
# Constant values of 10. are assigned for the horizontal and vertical
|
||||||
|
# hydraulic conductivity:
|
||||||
|
|
||||||
|
lpf = flopy.modflow.ModflowLpf(mf, hk=10.0, vka=10.0, ipakcb=53)
|
||||||
|
|
||||||
|
# Because we did not specify a value for laytyp, Flopy will use the default
|
||||||
|
# value of 0, which means that this model will be confined.
|
||||||
|
|
||||||
|
# ### Output Control
|
||||||
|
#
|
||||||
|
# Here we can use the default OC settings by specifying the following:
|
||||||
|
|
||||||
|
spd = {(0, 0): ["print head", "print budget", "save head", "save budget"]}
|
||||||
|
oc = flopy.modflow.ModflowOc(mf, stress_period_data=spd, compact=True)
|
||||||
|
|
||||||
|
# The stress period dictionary is used to set what output is saved for the
|
||||||
|
# corresponding stress period and time step. In this case, the tuple `(0, 0)`
|
||||||
|
# means that stress period 1 and time step 1 for MODFLOW will have output
|
||||||
|
# saved. Head and budgets will be printed and head and budget information
|
||||||
|
# will be saved.
|
||||||
|
|
||||||
|
# ### Preconditioned Conjugate Gradient Package
|
||||||
|
#
|
||||||
|
# The default settings used by flopy will be used by specifying the following
|
||||||
|
# commands:
|
||||||
|
|
||||||
|
pcg = flopy.modflow.ModflowPcg(mf)
|
||||||
|
|
||||||
|
# ### Writing the MODFLOW Data Files
|
||||||
|
#
|
||||||
|
# The MODFLOW input data files are written by simply issuing the following:
|
||||||
|
|
||||||
|
mf.write_input()
|
||||||
|
|
||||||
|
# ## Running the Model
|
||||||
|
#
|
||||||
|
# Flopy can also be used to run the model. The model object (`mf` in this
|
||||||
|
# example) has an attached method that will run the model. For this to work,
|
||||||
|
# the MODFLOW program must be located somewhere within the system path, or
|
||||||
|
# within the working directory. In this example, we have specified that the
|
||||||
|
# name of the executable program is 'mf2005'. Issue the following to run
|
||||||
|
# the model:
|
||||||
|
|
||||||
|
success, buff = mf.run_model()
|
||||||
|
if not success:
|
||||||
|
raise Exception("MODFLOW did not terminate normally.")
|
||||||
|
|
||||||
|
# Here we have used run_model, and we could also have specified values for the
|
||||||
|
# optional keywords silent, pause, and report.
|
||||||
|
|
||||||
|
# ## Post-Processing the Results
|
||||||
|
#
|
||||||
|
# Now that we have successfully built and run our MODFLOW model, we can look at
|
||||||
|
# the results. MODFLOW writes the simulated heads to a binary data output file.
|
||||||
|
# We cannot look at these heads with a text editor, but flopy has a binary
|
||||||
|
# utility that can be used to read the heads. The following statements will
|
||||||
|
# read the binary head file and create a plot of simulated heads for layer 1:
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import flopy.utils.binaryfile as bf
|
||||||
|
|
||||||
|
# Extract the heads
|
||||||
|
|
||||||
|
hds = bf.HeadFile(modelname + ".hds")
|
||||||
|
head = hds.get_data(totim=1.0)
|
||||||
|
|
||||||
|
# Contour the heads
|
||||||
|
|
||||||
|
extent = (delr / 2.0, Lx - delr / 2.0, Ly - delc / 2.0, delc / 2.0)
|
||||||
|
fig = plt.figure(figsize=(6, 6))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
||||||
|
ax.contour(head[0, :, :], levels=np.arange(1, 10, 1), extent=extent)
|
||||||
|
|
||||||
|
# Flopy also has some pre-canned plotting capabilities can can be accessed
|
||||||
|
# using the `PlotMapView()` class. The following code shows how to use the
|
||||||
|
# plotmapview class to plot boundary conditions (`IBOUND`), plot the grid,
|
||||||
|
# plot head contours, and plot vectors:
|
||||||
|
|
||||||
|
# Extract the heads
|
||||||
|
hds = bf.HeadFile(modelname + ".hds")
|
||||||
|
times = hds.get_times()
|
||||||
|
head = hds.get_data(totim=times[-1])
|
||||||
|
|
||||||
|
# Extract the cell-by-cell flows
|
||||||
|
|
||||||
|
cbb = bf.CellBudgetFile(modelname + ".cbc")
|
||||||
|
kstpkper_list = cbb.get_kstpkper()
|
||||||
|
frf = cbb.get_data(text="FLOW RIGHT FACE", totim=times[-1])[0]
|
||||||
|
fff = cbb.get_data(text="FLOW FRONT FACE", totim=times[-1])[0]
|
||||||
|
|
||||||
|
# Create the figure
|
||||||
|
|
||||||
|
fig = plt.figure(figsize=(6, 6))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
||||||
|
modelmap = flopy.plot.PlotMapView(model=mf, layer=0, ax=ax)
|
||||||
|
qm = modelmap.plot_ibound()
|
||||||
|
lc = modelmap.plot_grid()
|
||||||
|
cs = modelmap.contour_array(head, levels=np.linspace(0, 10, 11))
|
||||||
|
quiver = modelmap.plot_discharge(frf, fff, head=head)
|
|
@ -0,0 +1,255 @@
|
||||||
|
# ---
|
||||||
|
# jupyter:
|
||||||
|
# jupytext:
|
||||||
|
# text_representation:
|
||||||
|
# extension: .py
|
||||||
|
# format_name: light
|
||||||
|
# format_version: '1.5'
|
||||||
|
# jupytext_version: 1.5.1
|
||||||
|
# kernelspec:
|
||||||
|
# display_name: Python 3
|
||||||
|
# language: python
|
||||||
|
# name: python3
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# # MODFLOW 6 Tutorial 1: Unconfined Steady-State Flow Model
|
||||||
|
#
|
||||||
|
# This tutorial demonstrates use of FloPy to develop a simple MODFLOW 6
|
||||||
|
# model.
|
||||||
|
|
||||||
|
# ## Getting Started
|
||||||
|
|
||||||
|
import os
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import flopy
|
||||||
|
|
||||||
|
# We are creating a square model with a specified head equal to `h1` along
|
||||||
|
# all boundaries. The head at the cell in the center in the top layer is
|
||||||
|
# fixed to `h2`. First, set the name of the model and the parameters of the
|
||||||
|
# model: the number of layers `Nlay`, the number of rows and columns `N`,
|
||||||
|
# lengths of the sides of the model `L`, aquifer thickness `H`,
|
||||||
|
# hydraulic conductivity `k`
|
||||||
|
|
||||||
|
name = "tutorial01_mf6"
|
||||||
|
h1 = 100
|
||||||
|
h2 = 90
|
||||||
|
Nlay = 10
|
||||||
|
N = 101
|
||||||
|
L = 400.0
|
||||||
|
H = 50.0
|
||||||
|
k = 1.0
|
||||||
|
|
||||||
|
# ### Create the Flopy Model Objects
|
||||||
|
#
|
||||||
|
# One big difference between MODFLOW 6 and previous MODFLOW versions is
|
||||||
|
# that MODFLOW 6 is based on the concept of a simulation.
|
||||||
|
# A simulation consists of the following:
|
||||||
|
#
|
||||||
|
# * Temporal discretization (`TDIS`)
|
||||||
|
# * One or more models
|
||||||
|
# * Zero or more exchanges (instructions for how models are coupled)
|
||||||
|
# * Solutions
|
||||||
|
#
|
||||||
|
# For this simple example, the simulation consists of the temporal
|
||||||
|
# discretization (`TDIS`) package, a groundwater flow (`GWF`) model, and
|
||||||
|
# an iterative model solution (`IMS`), which controls how the GWF model is
|
||||||
|
# solved.
|
||||||
|
|
||||||
|
# ### Create the Flopy simulation object
|
||||||
|
|
||||||
|
sim = flopy.mf6.MFSimulation(
|
||||||
|
sim_name=name, exe_name="mf6", version="mf6", sim_ws="."
|
||||||
|
)
|
||||||
|
|
||||||
|
# ### Create the Flopy `TDIS` object
|
||||||
|
|
||||||
|
tdis = flopy.mf6.ModflowTdis(
|
||||||
|
sim, pname="tdis", time_units="DAYS", nper=1, perioddata=[(1.0, 1, 1.0)]
|
||||||
|
)
|
||||||
|
|
||||||
|
# ### Create the Flopy `IMS` Package object
|
||||||
|
|
||||||
|
ims = flopy.mf6.ModflowIms(sim, pname="ims", complexity="SIMPLE")
|
||||||
|
|
||||||
|
# Create the Flopy groundwater flow (gwf) model object
|
||||||
|
|
||||||
|
model_nam_file = "{}.nam".format(name)
|
||||||
|
gwf = flopy.mf6.ModflowGwf(sim, modelname=name, model_nam_file=model_nam_file)
|
||||||
|
|
||||||
|
# Now that the overall simulation is set up, we can focus on building the
|
||||||
|
# groundwater flow model. The groundwater flow model will be built by
|
||||||
|
# adding packages to it that describe the model characteristics.
|
||||||
|
|
||||||
|
# ### Create the discretization (`DIS`) Package
|
||||||
|
#
|
||||||
|
# Define the discretization of the model. All layers are given equal thickness.
|
||||||
|
# The `bot` array is build from `H` and the `Nlay` values to indicate top and
|
||||||
|
# bottom of each layer, and `delrow` and `delcol` are computed from model
|
||||||
|
# size `L` and number of cells `N`. Once these are all computed, the
|
||||||
|
# Discretization file is built.
|
||||||
|
|
||||||
|
bot = np.linspace(-H / Nlay, -H, Nlay)
|
||||||
|
delrow = delcol = L / (N - 1)
|
||||||
|
dis = flopy.mf6.ModflowGwfdis(
|
||||||
|
gwf,
|
||||||
|
nlay=Nlay,
|
||||||
|
nrow=N,
|
||||||
|
ncol=N,
|
||||||
|
delr=delrow,
|
||||||
|
delc=delcol,
|
||||||
|
top=0.0,
|
||||||
|
botm=bot,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ### Create the initial conditions (`IC`) Package
|
||||||
|
|
||||||
|
start = h1 * np.ones((Nlay, N, N))
|
||||||
|
ic = flopy.mf6.ModflowGwfic(gwf, pname="ic", strt=start)
|
||||||
|
|
||||||
|
# ### Create the node property flow (`NPF`) Package
|
||||||
|
|
||||||
|
npf = flopy.mf6.ModflowGwfnpf(gwf, icelltype=1, k=k, save_flows=True)
|
||||||
|
|
||||||
|
# ### Create the constant head (`CHD`) Package
|
||||||
|
#
|
||||||
|
# List information is created a bit differently for MODFLOW 6 than for other
|
||||||
|
# MODFLOW versions. The cellid (layer, row, column, for a regular grid)
|
||||||
|
# can be entered as a tuple as the first entry. Remember that these must be
|
||||||
|
# zero-based indices!
|
||||||
|
|
||||||
|
chd_rec = []
|
||||||
|
chd_rec.append(((0, int(N / 4), int(N / 4)), h2))
|
||||||
|
for layer in range(0, Nlay):
|
||||||
|
for row_col in range(0, N):
|
||||||
|
chd_rec.append(((layer, row_col, 0), h1))
|
||||||
|
chd_rec.append(((layer, row_col, N - 1), h1))
|
||||||
|
if row_col != 0 and row_col != N - 1:
|
||||||
|
chd_rec.append(((layer, 0, row_col), h1))
|
||||||
|
chd_rec.append(((layer, N - 1, row_col), h1))
|
||||||
|
chd = flopy.mf6.ModflowGwfchd(
|
||||||
|
gwf,
|
||||||
|
maxbound=len(chd_rec),
|
||||||
|
stress_period_data=chd_rec,
|
||||||
|
save_flows=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# The `CHD` Package stored the constant heads in a structured array,
|
||||||
|
# also called a `numpy.recarray`. We can get a pointer to the recarray
|
||||||
|
# for the first stress period (iper = 0) as follows.
|
||||||
|
|
||||||
|
iper = 0
|
||||||
|
ra = chd.stress_period_data.get_data(key=iper)
|
||||||
|
ra
|
||||||
|
|
||||||
|
# Create the output control (`OC`) Package
|
||||||
|
headfile = "{}.hds".format(name)
|
||||||
|
head_filerecord = [headfile]
|
||||||
|
budgetfile = "{}.cbb".format(name)
|
||||||
|
budget_filerecord = [budgetfile]
|
||||||
|
saverecord = [("HEAD", "ALL"), ("BUDGET", "ALL")]
|
||||||
|
printrecord = [("HEAD", "LAST")]
|
||||||
|
oc = flopy.mf6.ModflowGwfoc(
|
||||||
|
gwf,
|
||||||
|
saverecord=saverecord,
|
||||||
|
head_filerecord=head_filerecord,
|
||||||
|
budget_filerecord=budget_filerecord,
|
||||||
|
printrecord=printrecord,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ## Create the MODFLOW 6 Input Files and Run the Model
|
||||||
|
#
|
||||||
|
# Once all the flopy objects are created, it is very easy to create
|
||||||
|
# all of the input files and run the model.
|
||||||
|
|
||||||
|
|
||||||
|
# ### Write the datasets
|
||||||
|
|
||||||
|
sim.write_simulation()
|
||||||
|
|
||||||
|
# ### Run the Simulation
|
||||||
|
#
|
||||||
|
# We can also run the simulation from python, but only if the MODFLOW 6
|
||||||
|
# executable is available. The executable can be made available by putting
|
||||||
|
# the executable in a folder that is listed in the system path variable.
|
||||||
|
# Another option is to just put a copy of the executable in the simulation
|
||||||
|
# folder, though this should generally be avoided. A final option is to
|
||||||
|
# provide a full path to the executable when the simulation is constructed.
|
||||||
|
# This would be done by specifying exe_name with the full path.
|
||||||
|
|
||||||
|
success, buff = sim.run_simulation()
|
||||||
|
if not success:
|
||||||
|
raise Exception("MODFLOW 6 did not terminate normally.")
|
||||||
|
|
||||||
|
# ## Post-Process Head Results
|
||||||
|
#
|
||||||
|
# First, a link to the heads file is created with `HeadFile`. The link can then be accessed with the `get_data` function, by specifying, in this case, the step number and period number for which we want to retrieve data. A three-dimensional array is returned of size `nlay, nrow, ncol`. Matplotlib contouring functions are used to make contours of the layers or a cross-section.
|
||||||
|
|
||||||
|
# Read the binary head file and plot the results. We can use the Flopy
|
||||||
|
# `HeadFile()` class because the format of the headfile for MODFLOW 6 is
|
||||||
|
# the same as for previous MODFLOW versions.
|
||||||
|
|
||||||
|
# ### Plot a Map of Layer 1
|
||||||
|
|
||||||
|
hds = flopy.utils.binaryfile.HeadFile(headfile)
|
||||||
|
h = hds.get_data(kstpkper=(0, 0))
|
||||||
|
x = y = np.linspace(0, L, N)
|
||||||
|
y = y[::-1]
|
||||||
|
fig = plt.figure(figsize=(6, 6))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
||||||
|
c = ax.contour(x, y, h[0], np.arange(90, 100.1, 0.2), colors="black")
|
||||||
|
plt.clabel(c, fmt="%2.1f")
|
||||||
|
|
||||||
|
|
||||||
|
# ### Plot a Map of Layer 10
|
||||||
|
|
||||||
|
x = y = np.linspace(0, L, N)
|
||||||
|
y = y[::-1]
|
||||||
|
fig = plt.figure(figsize=(6, 6))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
||||||
|
c = ax.contour(x, y, h[-1], np.arange(90, 100.1, 0.2), colors="black")
|
||||||
|
plt.clabel(c, fmt="%1.1f")
|
||||||
|
|
||||||
|
# ### Plot a Cross-section along row 51
|
||||||
|
|
||||||
|
z = np.linspace(-H / Nlay / 2, -H + H / Nlay / 2, Nlay)
|
||||||
|
fig = plt.figure(figsize=(5, 2.5))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="auto")
|
||||||
|
c = ax.contour(x, z, h[:, 50, :], np.arange(90, 100.1, 0.2), colors="black")
|
||||||
|
plt.clabel(c, fmt="%1.1f")
|
||||||
|
|
||||||
|
# ### We can also use the Flopy `PlotMapView()` capabilities for MODFLOW 6
|
||||||
|
#
|
||||||
|
# Before we start we will create a MODFLOW-2005 ibound array to use to plot
|
||||||
|
# the locations of the constant heads.
|
||||||
|
|
||||||
|
ibd = np.ones((Nlay, N, N), dtype=np.int)
|
||||||
|
for k, i, j in ra["cellid"]:
|
||||||
|
ibd[k, i, j] = -1
|
||||||
|
|
||||||
|
# ### Plot a Map of Layers 1 and 10
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(2, 1, figsize=(6, 12), constrained_layout=True)
|
||||||
|
# first subplot
|
||||||
|
ax = axes[0]
|
||||||
|
ax.set_title("Model Layer 1")
|
||||||
|
modelmap = flopy.plot.PlotMapView(model=gwf, ax=ax)
|
||||||
|
quadmesh = modelmap.plot_ibound(ibound=ibd)
|
||||||
|
linecollection = modelmap.plot_grid(lw=0.5, color="0.5")
|
||||||
|
contours = modelmap.contour_array(
|
||||||
|
h[0], levels=np.arange(90, 100.1, 0.2), colors="black"
|
||||||
|
)
|
||||||
|
ax.clabel(contours, fmt="%2.1f")
|
||||||
|
# second subplot
|
||||||
|
ax = axes[1]
|
||||||
|
ax.set_title("Model Layer {}".format(Nlay))
|
||||||
|
modelmap = flopy.plot.PlotMapView(model=gwf, ax=ax, layer=Nlay - 1)
|
||||||
|
quadmesh = modelmap.plot_ibound(ibound=ibd)
|
||||||
|
linecollection = modelmap.plot_grid(lw=0.5, color="0.5")
|
||||||
|
pa = modelmap.plot_array(h[0])
|
||||||
|
contours = modelmap.contour_array(
|
||||||
|
h[0], levels=np.arange(90, 100.1, 0.2), colors="black"
|
||||||
|
)
|
||||||
|
cb = plt.colorbar(pa, shrink=0.5, ax=ax)
|
||||||
|
ax.clabel(contours, fmt="%2.1f")
|
|
@ -0,0 +1,196 @@
|
||||||
|
# ---
|
||||||
|
# jupyter:
|
||||||
|
# jupytext:
|
||||||
|
# text_representation:
|
||||||
|
# extension: .py
|
||||||
|
# format_name: light
|
||||||
|
# format_version: '1.5'
|
||||||
|
# jupytext_version: 1.5.1
|
||||||
|
# kernelspec:
|
||||||
|
# display_name: Python 3
|
||||||
|
# language: python
|
||||||
|
# name: python3
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# # SEAWAT Tutorial 1: Henry Saltwater Intrusion Problem
|
||||||
|
#
|
||||||
|
# In this tutorial, we will use Flopy to create, run, and post process the
|
||||||
|
# Henry saltwater intrusion problem using SEAWAT Version 4.
|
||||||
|
|
||||||
|
# ## Getting Started
|
||||||
|
|
||||||
|
import os
|
||||||
|
import numpy as np
|
||||||
|
import flopy
|
||||||
|
|
||||||
|
# ### Input variables for the Henry Problem
|
||||||
|
|
||||||
|
Lx = 2.0
|
||||||
|
Lz = 1.0
|
||||||
|
nlay = 50
|
||||||
|
nrow = 1
|
||||||
|
ncol = 100
|
||||||
|
delr = Lx / ncol
|
||||||
|
delc = 1.0
|
||||||
|
delv = Lz / nlay
|
||||||
|
henry_top = 1.0
|
||||||
|
henry_botm = np.linspace(henry_top - delv, 0.0, nlay)
|
||||||
|
qinflow = 5.702 # m3/day
|
||||||
|
dmcoef = 0.57024 # m2/day Could also try 1.62925 as another case of the Henry problem
|
||||||
|
hk = 864.0 # m/day
|
||||||
|
|
||||||
|
# ### Create the basic MODFLOW model structure
|
||||||
|
|
||||||
|
modelname = "henry"
|
||||||
|
swt = flopy.seawat.Seawat(modelname, exe_name="swtv4")
|
||||||
|
print(swt.namefile)
|
||||||
|
|
||||||
|
# save cell fluxes to unit 53
|
||||||
|
|
||||||
|
ipakcb = 53
|
||||||
|
|
||||||
|
# Add DIS package to the MODFLOW model
|
||||||
|
|
||||||
|
dis = flopy.modflow.ModflowDis(
|
||||||
|
swt,
|
||||||
|
nlay,
|
||||||
|
nrow,
|
||||||
|
ncol,
|
||||||
|
nper=1,
|
||||||
|
delr=delr,
|
||||||
|
delc=delc,
|
||||||
|
laycbd=0,
|
||||||
|
top=henry_top,
|
||||||
|
botm=henry_botm,
|
||||||
|
perlen=1.5,
|
||||||
|
nstp=15,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Variables for the BAS package
|
||||||
|
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
||||||
|
ibound[:, :, -1] = -1
|
||||||
|
|
||||||
|
# Add BAS package to the MODFLOW model
|
||||||
|
|
||||||
|
bas = flopy.modflow.ModflowBas(swt, ibound, 0)
|
||||||
|
|
||||||
|
# Add LPF package to the MODFLOW model
|
||||||
|
|
||||||
|
lpf = flopy.modflow.ModflowLpf(swt, hk=hk, vka=hk, ipakcb=ipakcb)
|
||||||
|
|
||||||
|
# Add PCG Package to the MODFLOW model
|
||||||
|
|
||||||
|
pcg = flopy.modflow.ModflowPcg(swt, hclose=1.0e-8)
|
||||||
|
|
||||||
|
# Add OC package to the MODFLOW model
|
||||||
|
|
||||||
|
oc = flopy.modflow.ModflowOc(
|
||||||
|
swt,
|
||||||
|
stress_period_data={(0, 0): ["save head", "save budget"]},
|
||||||
|
compact=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create WEL and SSM data
|
||||||
|
|
||||||
|
itype = flopy.mt3d.Mt3dSsm.itype_dict()
|
||||||
|
wel_data = {}
|
||||||
|
ssm_data = {}
|
||||||
|
wel_sp1 = []
|
||||||
|
ssm_sp1 = []
|
||||||
|
for k in range(nlay):
|
||||||
|
wel_sp1.append([k, 0, 0, qinflow / nlay])
|
||||||
|
ssm_sp1.append([k, 0, 0, 0.0, itype["WEL"]])
|
||||||
|
ssm_sp1.append([k, 0, ncol - 1, 35.0, itype["BAS6"]])
|
||||||
|
wel_data[0] = wel_sp1
|
||||||
|
ssm_data[0] = ssm_sp1
|
||||||
|
wel = flopy.modflow.ModflowWel(swt, stress_period_data=wel_data, ipakcb=ipakcb)
|
||||||
|
|
||||||
|
|
||||||
|
# ### Create the basic MT3DMS model structure
|
||||||
|
|
||||||
|
btn = flopy.mt3d.Mt3dBtn(
|
||||||
|
swt,
|
||||||
|
nprs=-5,
|
||||||
|
prsity=0.35,
|
||||||
|
sconc=35.0,
|
||||||
|
ifmtcn=0,
|
||||||
|
chkmas=False,
|
||||||
|
nprobs=10,
|
||||||
|
nprmas=10,
|
||||||
|
dt0=0.001,
|
||||||
|
)
|
||||||
|
adv = flopy.mt3d.Mt3dAdv(swt, mixelm=0)
|
||||||
|
dsp = flopy.mt3d.Mt3dDsp(swt, al=0.0, trpt=1.0, trpv=1.0, dmcoef=dmcoef)
|
||||||
|
gcg = flopy.mt3d.Mt3dGcg(swt, iter1=500, mxiter=1, isolve=1, cclose=1e-7)
|
||||||
|
ssm = flopy.mt3d.Mt3dSsm(swt, stress_period_data=ssm_data)
|
||||||
|
|
||||||
|
# ### Create the SEAWAT model structure
|
||||||
|
|
||||||
|
vdf = flopy.seawat.SeawatVdf(
|
||||||
|
swt,
|
||||||
|
iwtable=0,
|
||||||
|
densemin=0,
|
||||||
|
densemax=0,
|
||||||
|
denseref=1000.0,
|
||||||
|
denseslp=0.7143,
|
||||||
|
firstdt=1e-3,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ## Write the input files
|
||||||
|
|
||||||
|
swt.write_input()
|
||||||
|
|
||||||
|
# ## Run the model
|
||||||
|
|
||||||
|
success, buff = swt.run_model(silent=True, report=True)
|
||||||
|
if not success:
|
||||||
|
raise Exception("SEAWAT did not terminate normally.")
|
||||||
|
|
||||||
|
# ## Post-process the results
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import flopy.utils.binaryfile as bf
|
||||||
|
|
||||||
|
# ### Load the concentration data
|
||||||
|
|
||||||
|
ucnobj = bf.UcnFile("MT3D001.UCN", model=swt)
|
||||||
|
times = ucnobj.get_times()
|
||||||
|
concentration = ucnobj.get_data(totim=times[-1])
|
||||||
|
|
||||||
|
# ### Load the cell-by-cell flow data
|
||||||
|
|
||||||
|
cbbobj = bf.CellBudgetFile("henry.cbc")
|
||||||
|
times = cbbobj.get_times()
|
||||||
|
qx = cbbobj.get_data(text="flow right face", totim=times[-1])[0]
|
||||||
|
qy = np.zeros((nlay, nrow, ncol), dtype=np.float)
|
||||||
|
qz = cbbobj.get_data(text="flow lower face", totim=times[-1])[0]
|
||||||
|
|
||||||
|
# ### Create a plot with concentrations and flow vectors
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
fig = plt.figure(figsize=(12,9))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
||||||
|
pmv = flopy.plot.PlotCrossSection(model=swt, ax=ax, line={"row": 0})
|
||||||
|
arr = pmv.plot_array(concentration)
|
||||||
|
pmv.plot_vector(qx, qy, -qz, color="white", kstep=3, hstep=3)
|
||||||
|
plt.colorbar(arr, shrink=0.5, ax=ax)
|
||||||
|
ax.set_title("Simulated Concentrations");
|
||||||
|
|
||||||
|
# ### Load the head data
|
||||||
|
|
||||||
|
headobj = bf.HeadFile("henry.hds")
|
||||||
|
times = headobj.get_times()
|
||||||
|
head = headobj.get_data(totim=times[-1])
|
||||||
|
|
||||||
|
|
||||||
|
# ### Create a plot with heads
|
||||||
|
|
||||||
|
fig = plt.figure(figsize=(12, 9))
|
||||||
|
ax = fig.add_subplot(1, 1, 1, aspect="equal")
|
||||||
|
pmv = flopy.plot.PlotCrossSection(model=swt, ax=ax, line={"row": 0})
|
||||||
|
arr = pmv.plot_array(head)
|
||||||
|
contours = pmv.contour_array(head, colors="white")
|
||||||
|
ax.clabel(contours, fmt="%2.2f")
|
||||||
|
plt.colorbar(arr, shrink=0.5, ax=ax)
|
||||||
|
ax.set_title("Simulated Heads");
|
|
@ -1,7 +1,48 @@
|
||||||
|
# ---
|
||||||
|
# jupyter:
|
||||||
|
# jupytext:
|
||||||
|
# text_representation:
|
||||||
|
# extension: .py
|
||||||
|
# format_name: light
|
||||||
|
# format_version: '1.5'
|
||||||
|
# jupytext_version: 1.5.1
|
||||||
|
# kernelspec:
|
||||||
|
# display_name: Python 3
|
||||||
|
# language: python
|
||||||
|
# name: python3
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# # MODFLOW Tutorial 2: Unconfined Transient Flow Model
|
||||||
|
#
|
||||||
|
# In this example, we will convert the tutorial 1 model into an unconfined,
|
||||||
|
# transient flow model with time varying boundaries. Instead of using constant
|
||||||
|
# heads for the left and right boundaries (by setting ibound to -1), we will use
|
||||||
|
# general head boundaries. We will have the model consider the following
|
||||||
|
# conditions:
|
||||||
|
#
|
||||||
|
# * Initial conditions -- head is 10.0 everywhere
|
||||||
|
# * Period 1 (1 day) -- steady state with left and right GHB stage = 10.
|
||||||
|
# * Period 2 (100 days) -- left GHB with stage = 10., right GHB with stage set
|
||||||
|
# to 0.
|
||||||
|
# * Period 3 (100 days) -- pumping well at model center with rate = -500., left
|
||||||
|
# and right GHB = 10., and 0.
|
||||||
|
#
|
||||||
|
# We will start with selected model commands from the previous tutorial.
|
||||||
|
#
|
||||||
|
|
||||||
|
# ## Getting Started
|
||||||
|
#
|
||||||
|
# As shown in the previous MODFLOW tutorial, import flopy.
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import flopy
|
import flopy
|
||||||
|
|
||||||
# Model domain and grid definition
|
# ## Creating the MODFLOW Model
|
||||||
|
#
|
||||||
|
# ### Define the Model Extent, Grid Resolution, and Characteristics
|
||||||
|
#
|
||||||
|
# Assign the model information
|
||||||
|
|
||||||
Lx = 1000.0
|
Lx = 1000.0
|
||||||
Ly = 1000.0
|
Ly = 1000.0
|
||||||
ztop = 10.0
|
ztop = 10.0
|
||||||
|
@ -20,18 +61,28 @@ ss = 1.0e-4
|
||||||
laytyp = 1
|
laytyp = 1
|
||||||
|
|
||||||
# Variables for the BAS package
|
# Variables for the BAS package
|
||||||
# Note that changes from the previous tutorial!
|
# Note that changes from the MODFLOW tutorial 1
|
||||||
|
|
||||||
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
ibound = np.ones((nlay, nrow, ncol), dtype=np.int32)
|
||||||
strt = 10.0 * np.ones((nlay, nrow, ncol), dtype=np.float32)
|
strt = 10.0 * np.ones((nlay, nrow, ncol), dtype=np.float32)
|
||||||
|
|
||||||
# Time step parameters
|
# ### Define the Stress Periods
|
||||||
|
#
|
||||||
|
# To create a model with multiple stress periods, we need to define nper,
|
||||||
|
# perlen, nstp, and steady. This is done in the following block in a manner
|
||||||
|
# that allows us to pass these variable directly to the discretization object:
|
||||||
|
|
||||||
nper = 3
|
nper = 3
|
||||||
perlen = [1, 100, 100]
|
perlen = [1, 100, 100]
|
||||||
nstp = [1, 100, 100]
|
nstp = [1, 100, 100]
|
||||||
steady = [True, False, False]
|
steady = [True, False, False]
|
||||||
|
|
||||||
# Flopy objects
|
# ### Create Time-Invariant Flopy Objects
|
||||||
modelname = "tutorial2"
|
#
|
||||||
|
# With this information, we can now create the static flopy objects that do
|
||||||
|
# not change with time:
|
||||||
|
|
||||||
|
modelname = "tutorial2_mf"
|
||||||
mf = flopy.modflow.Modflow(modelname, exe_name="mf2005")
|
mf = flopy.modflow.Modflow(modelname, exe_name="mf2005")
|
||||||
dis = flopy.modflow.ModflowDis(
|
dis = flopy.modflow.ModflowDis(
|
||||||
mf,
|
mf,
|
||||||
|
@ -53,7 +104,18 @@ lpf = flopy.modflow.ModflowLpf(
|
||||||
)
|
)
|
||||||
pcg = flopy.modflow.ModflowPcg(mf)
|
pcg = flopy.modflow.ModflowPcg(mf)
|
||||||
|
|
||||||
# Make list for stress period 1
|
# ### Transient General-Head Boundary Package
|
||||||
|
#
|
||||||
|
# At this point, our model is ready to add our transient boundary packages.
|
||||||
|
# First, we will create the GHB object, which is of the following type:
|
||||||
|
# `flopy.modflow.ModflowGhb()`.
|
||||||
|
#
|
||||||
|
# The key to creating Flopy transient boundary packages is recognizing that
|
||||||
|
# the boundary data is stored in a dictionary with key values equal to the
|
||||||
|
# zero-based stress period number and values equal to the boundary conditions
|
||||||
|
# for that stress period. For a GHB the values can be a two-dimensional nested
|
||||||
|
# list of `[layer, row, column, stage, conductance]`.
|
||||||
|
|
||||||
stageleft = 10.0
|
stageleft = 10.0
|
||||||
stageright = 10.0
|
stageright = 10.0
|
||||||
bound_sp1 = []
|
bound_sp1 = []
|
||||||
|
@ -85,6 +147,11 @@ stress_period_data = {0: bound_sp1, 1: bound_sp2}
|
||||||
# Create the flopy ghb object
|
# Create the flopy ghb object
|
||||||
ghb = flopy.modflow.ModflowGhb(mf, stress_period_data=stress_period_data)
|
ghb = flopy.modflow.ModflowGhb(mf, stress_period_data=stress_period_data)
|
||||||
|
|
||||||
|
# ### Transient Well Package
|
||||||
|
#
|
||||||
|
# Now we can create the well package object, which is of the type,
|
||||||
|
# `flopy.modflow.ModflowWel()`.
|
||||||
|
|
||||||
# Create the well package
|
# Create the well package
|
||||||
# Remember to use zero-based layer, row, column indices!
|
# Remember to use zero-based layer, row, column indices!
|
||||||
pumping_rate = -500.0
|
pumping_rate = -500.0
|
||||||
|
@ -94,7 +161,11 @@ wel_sp3 = [[0, nrow / 2 - 1, ncol / 2 - 1, pumping_rate]]
|
||||||
stress_period_data = {0: wel_sp1, 1: wel_sp2, 2: wel_sp3}
|
stress_period_data = {0: wel_sp1, 1: wel_sp2, 2: wel_sp3}
|
||||||
wel = flopy.modflow.ModflowWel(mf, stress_period_data=stress_period_data)
|
wel = flopy.modflow.ModflowWel(mf, stress_period_data=stress_period_data)
|
||||||
|
|
||||||
# Output control
|
# ### Output Control
|
||||||
|
#
|
||||||
|
# Here we create the output control package object, which is of the
|
||||||
|
# type `flopy.modflow.ModflowOc()`.
|
||||||
|
|
||||||
stress_period_data = {}
|
stress_period_data = {}
|
||||||
for kper in range(nper):
|
for kper in range(nper):
|
||||||
for kstp in range(nstp[kper]):
|
for kstp in range(nstp[kper]):
|
||||||
|
@ -109,14 +180,34 @@ oc = flopy.modflow.ModflowOc(
|
||||||
mf, stress_period_data=stress_period_data, compact=True
|
mf, stress_period_data=stress_period_data, compact=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ## Running the Model
|
||||||
|
#
|
||||||
|
# Run the model with the run_model method, which returns a success flag and
|
||||||
|
# the stream of output. With run_model, we have some finer control, that
|
||||||
|
# allows us to suppress the output.
|
||||||
|
|
||||||
# Write the model input files
|
# Write the model input files
|
||||||
mf.write_input()
|
mf.write_input()
|
||||||
|
|
||||||
# Run the model
|
# Run the model
|
||||||
success, mfoutput = mf.run_model(silent=False, pause=False)
|
success, mfoutput = mf.run_model(silent=True, pause=False)
|
||||||
if not success:
|
if not success:
|
||||||
raise Exception("MODFLOW did not terminate normally.")
|
raise Exception("MODFLOW did not terminate normally.")
|
||||||
|
|
||||||
|
# ## Post-Processing the Results
|
||||||
|
#
|
||||||
|
# Once again, we can read heads from the MODFLOW binary output file, using
|
||||||
|
# the `flopy.utils.binaryfile()` module. Included with the HeadFile object
|
||||||
|
# are several methods that we will use here:
|
||||||
|
|
||||||
|
# * `get_times()` will return a list of times contained in the binary head file
|
||||||
|
# * `get_data()` will return a three-dimensional head array for the specified
|
||||||
|
# time
|
||||||
|
# * `get_ts()` will return a time series array `[ntimes, headval]` for the
|
||||||
|
# specified cell
|
||||||
|
#
|
||||||
|
# Using these methods, we can create head plots and hydrographs from the
|
||||||
|
# model results.
|
||||||
|
|
||||||
# Imports
|
# Imports
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
@ -133,11 +224,13 @@ extent = (delr / 2.0, Lx - delr / 2.0, delc / 2.0, Ly - delc / 2.0)
|
||||||
print("Levels: ", levels)
|
print("Levels: ", levels)
|
||||||
print("Extent: ", extent)
|
print("Extent: ", extent)
|
||||||
|
|
||||||
# Well point
|
# Well point for plotting
|
||||||
wpt = ((float(ncol / 2) - 0.5) * delr, (float(nrow / 2 - 1) + 0.5) * delc)
|
|
||||||
wpt = (450.0, 550.0)
|
wpt = (450.0, 550.0)
|
||||||
|
|
||||||
|
# Create a figure with maps for three times
|
||||||
|
|
||||||
# Make the plots
|
# Make the plots
|
||||||
|
fig = plt.figure(figsize=(5, 15))
|
||||||
mytimes = [1.0, 101.0, 201.0]
|
mytimes = [1.0, 101.0, 201.0]
|
||||||
for iplot, time in enumerate(mytimes):
|
for iplot, time in enumerate(mytimes):
|
||||||
print("*****Processing time: ", time)
|
print("*****Processing time: ", time)
|
||||||
|
@ -152,23 +245,23 @@ for iplot, time in enumerate(mytimes):
|
||||||
frf = cbb.get_data(text="FLOW RIGHT FACE", totim=time)[0]
|
frf = cbb.get_data(text="FLOW RIGHT FACE", totim=time)[0]
|
||||||
fff = cbb.get_data(text="FLOW FRONT FACE", totim=time)[0]
|
fff = cbb.get_data(text="FLOW FRONT FACE", totim=time)[0]
|
||||||
|
|
||||||
# Create the plot
|
# Create a map for this time
|
||||||
# plt.subplot(1, len(mytimes), iplot + 1, aspect='equal')
|
ax = fig.add_subplot(len(mytimes), 1, iplot + 1, aspect="equal")
|
||||||
plt.subplot(1, 1, 1, aspect="equal")
|
ax.set_title("stress period " + str(iplot + 1))
|
||||||
plt.title("stress period " + str(iplot + 1))
|
|
||||||
|
|
||||||
modelmap = flopy.plot.ModelMap(model=mf, layer=0)
|
pmv = flopy.plot.PlotMapView(model=mf, layer=0, ax=ax)
|
||||||
qm = modelmap.plot_ibound()
|
qm = pmv.plot_ibound()
|
||||||
lc = modelmap.plot_grid()
|
lc = pmv.plot_grid()
|
||||||
qm = modelmap.plot_bc("GHB", alpha=0.5)
|
qm = pmv.plot_bc("GHB", alpha=0.5)
|
||||||
cs = modelmap.contour_array(head, levels=levels)
|
if head.min() != head.max():
|
||||||
plt.clabel(cs, inline=1, fontsize=10, fmt="%1.1f")
|
cs = pmv.contour_array(head, levels=levels)
|
||||||
quiver = modelmap.plot_discharge(frf, fff, head=head)
|
plt.clabel(cs, inline=1, fontsize=10, fmt="%1.1f")
|
||||||
|
quiver = pmv.plot_vector(frf, fff)
|
||||||
|
|
||||||
mfc = "None"
|
mfc = "None"
|
||||||
if (iplot + 1) == len(mytimes):
|
if (iplot + 1) == len(mytimes):
|
||||||
mfc = "black"
|
mfc = "black"
|
||||||
plt.plot(
|
ax.plot(
|
||||||
wpt[0],
|
wpt[0],
|
||||||
wpt[1],
|
wpt[1],
|
||||||
lw=0,
|
lw=0,
|
||||||
|
@ -179,17 +272,17 @@ for iplot, time in enumerate(mytimes):
|
||||||
markerfacecolor=mfc,
|
markerfacecolor=mfc,
|
||||||
zorder=9,
|
zorder=9,
|
||||||
)
|
)
|
||||||
plt.text(wpt[0] + 25, wpt[1] - 25, "well", size=12, zorder=12)
|
ax.text(wpt[0] + 25, wpt[1] - 25, "well", size=12, zorder=12)
|
||||||
plt.savefig("tutorial2-{}.png".format(iplot))
|
|
||||||
|
|
||||||
|
# Create a hydrograph
|
||||||
|
|
||||||
# Plot the head versus time
|
# Plot the head versus time
|
||||||
idx = (0, int(nrow / 2) - 1, int(ncol / 2) - 1)
|
idx = (0, int(nrow / 2) - 1, int(ncol / 2) - 1)
|
||||||
ts = headobj.get_ts(idx)
|
ts = headobj.get_ts(idx)
|
||||||
plt.subplot(1, 1, 1)
|
fig = plt.figure(figsize=(6, 6))
|
||||||
|
ax = fig.add_subplot(1, 1, 1)
|
||||||
ttl = "Head at cell ({0},{1},{2})".format(idx[0] + 1, idx[1] + 1, idx[2] + 1)
|
ttl = "Head at cell ({0},{1},{2})".format(idx[0] + 1, idx[1] + 1, idx[2] + 1)
|
||||||
plt.title(ttl)
|
ax.set_title(ttl)
|
||||||
plt.xlabel("time")
|
ax.set_xlabel("time")
|
||||||
plt.ylabel("head")
|
ax.set_ylabel("head")
|
||||||
plt.plot(ts[:, 0], ts[:, 1], "bo-")
|
ax.plot(ts[:, 0], ts[:, 1], "bo-")
|
||||||
plt.savefig("tutorial2-ts.png")
|
|
Loading…
Reference in New Issue