Note

This page was generated from Notebooks/flopy3_mfusg_freyberg.ipynb.
Interactive online version: Binder badge

MODFLOW-USG Freyberg demo

This example demonstrates a MODFLOW USG Freyberg model, including construction of an UnstructuredGrid from a specification file and plotting head data in cross-section.

First we locate the model directory.

[1]:
from pathlib import Path
import flopy

root_name = "freyberg.usg"
model_ws = Path.cwd().parent / "../examples/data" / root_name.replace(".", "_")

Now construct an UnstructuredGrid from a grid specification file.

[2]:
from flopy.discretization import UnstructuredGrid

mfgrid = UnstructuredGrid.from_gridspec(str(model_ws / f"{root_name}.gsf"))

Plot the grid in map view.

[3]:
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1, aspect="equal")
pmv = flopy.plot.PlotMapView(modelgrid=mfgrid, ax=ax)
pmv.plot_grid(alpha=0.1)
[3]:
<matplotlib.collections.LineCollection at 0x7f98fb62e7d0>
../_images/Notebooks_flopy3_mfusg_freyberg_5_1.png

Create cross-section lines.

[4]:
from flopy.utils.geometry import LineString

lines = [
    LineString(ls)
    for ls in [
        [(623000, 3364000), (623000, 3372000)],
        [(623650, 3364000), (623650, 3372000)],
    ]
]

Load the model and retrieve inactive cells.

[5]:
gwf = flopy.mfusg.MfUsg.load(
    f"{root_name}.nam",
    model_ws=str(model_ws),
    verbose=False,
    check=False,
    exe_name="mfusg",
)

bas6 = gwf.get_package("bas6")
ibound = bas6.ibound.array

Show the map view again with cross-section lines and inactive cells.

[6]:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1, aspect="equal")
pmv = flopy.plot.PlotMapView(modelgrid=mfgrid, ax=ax)
grid = pmv.plot_grid(alpha=0.2)
shps = pmv.plot_shapes(lines, edgecolor="purple", lw=2, alpha=0.7)
inac = pmv.plot_inactive(ibound=ibound)
../_images/Notebooks_flopy3_mfusg_freyberg_11_0.png

Next, we can run the model and plot cross-sections of the resulting head. We will run the model in a temporary workspace to avoid altering the example data.

[7]:
from tempfile import TemporaryDirectory

# temporary directory
temp_dir = TemporaryDirectory()
work_dir = Path(temp_dir.name) / "freyberg_usg"

gwf.change_model_ws(str(work_dir))
gwf.write_name_file()
gwf.write_input()
success, buff = gwf.run_model(silent=True, report=True)
if success:
    for line in buff:
        print(line)
else:
    raise ValueError("Failed to run.")

creating model workspace...
   ../../../../../../../tmp/tmpc4u3riio/freyberg_usg

                                  MODFLOW-USG
    U.S. GEOLOGICAL SURVEY MODULAR FINITE-DIFFERENCE GROUNDWATER FLOW MODEL
                             Version 1.5.00 02/27/2019

 Using NAME file: freyberg.usg.nam
 Run start date and time (yyyy/mm/dd hh:mm:ss): 2023/05/04 16:05:11

 Solving:  Stress period:     1    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     2    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     3    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     4    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     5    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     6    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     7    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     8    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:     9    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    10    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    11    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    12    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    13    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    14    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    15    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    16    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    17    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    18    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    19    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    20    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    21    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    22    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    23    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    24    Time step:     1    Groundwater Flow Eqn.
 Solving:  Stress period:    25    Time step:     1    Groundwater Flow Eqn.
 Run end date and time (yyyy/mm/dd hh:mm:ss): 2023/05/04 16:05:11
 Elapsed run time:  0.374 Seconds

  Normal termination of simulation

Load head data from the output files:

[8]:
import numpy as np

hds = flopy.utils.HeadUFile(str(work_dir / f"{root_name}.hds"), model=gwf)
times = hds.get_times()
head = np.array(hds.get_data())
print(head.shape)
(3, 1499)

Plot the head colormap and contours for each layer.

[9]:
levels = np.arange(30, 35.4, 0.1)
fig = plt.figure(figsize=(15, 10))

for layer, h in enumerate(head):
    ax = fig.add_subplot(1, len(head), layer + 1)
    ax.set_title(f"Freyberg head (layer {layer})")
    pmv = flopy.plot.PlotMapView(modelgrid=mfgrid, ax=ax)
    mesh = pmv.plot_array(h, alpha=0.2)
    grid = pmv.plot_grid(alpha=0.2)
    shps = pmv.plot_shapes(lines, edgecolor="purple", lw=2, alpha=0.8)
    inac = pmv.plot_inactive(ibound=ibound)
    ctrs = pmv.contour_array(h, levels=levels)
../_images/Notebooks_flopy3_mfusg_freyberg_17_0.png

A head argument can be provided to CrossSectionPlot.contour_array() to show the phreatic surface.

[10]:
fig = plt.figure(figsize=(25, 5))

for i, line in enumerate(lines):
    ax = fig.add_subplot(1, len(lines), i + 1)
    ax.set_title(f"Freyberg head cross-section (line {i})")
    xsect = flopy.plot.PlotCrossSection(
        modelgrid=mfgrid,
        ax=ax,
        line={"line": lines[i]},
        geographic_coords=True,
    )
    xsect.plot_array(head, head=head, alpha=0.4)
    xsect.plot_ibound(ibound=ibound, head=head)
    xsect.plot_inactive(ibound=ibound)
    contours = xsect.contour_array(
        head,
        masked_values=[999.0],
        head=head,
        levels=levels,
        alpha=1.0,
        colors="blue",
    )
    plt.clabel(contours, fmt="%.0f", colors="blue", fontsize=12)
    xsect.plot_grid(alpha=0.2)
    ax.set_ylim([0, 40])  # set y axis range to ignore low elevations
../_images/Notebooks_flopy3_mfusg_freyberg_19_0.png

The head argument can be a 1D array or a 2D array matching the shape of the grid (i.e., head.shape == (layer count, ncpl)).

[11]:
line = lines[0]

for time in times[0:3]:
    head = np.array(hds.get_data(totim=time))
    head2 = np.hstack(head)

    fig = plt.figure(figsize=(25, 5))
    ax = fig.add_subplot(1, 3, 1)
    ax.set_title(f"Freyberg cross-section (t = {int(time)}, no head)")
    xsect = flopy.plot.PlotCrossSection(
        modelgrid=mfgrid, ax=ax, line={"line": line}, geographic_coords=True
    )
    cmap = xsect.plot_array(
        head2,
        masked_values=[-999.99],
        alpha=0.4,
    )
    contours = xsect.contour_array(
        head2, levels=levels, alpha=1.0, colors="blue"
    )
    xsect.plot_inactive(ibound=ibound, color_noflow=(0.8, 0.8, 0.8))
    xsect.plot_grid(alpha=0.2)
    ax.set_ylim([0, 40])  # set y axis range to ignore low elevations

    ax = fig.add_subplot(1, 3, 2)
    ax.set_title(
        f"Freyberg head cross-section (t = {int(time)}, head shape = {head.shape})"
    )
    xsect = flopy.plot.PlotCrossSection(
        modelgrid=mfgrid, ax=ax, line={"line": line}, geographic_coords=True
    )
    cmap = xsect.plot_array(
        head,
        masked_values=[-999.99],
        head=head,
        alpha=0.4,
    )
    contours = xsect.contour_array(
        head, head=head, levels=levels, alpha=1.0, colors="blue"
    )
    xsect.plot_inactive(ibound=ibound, color_noflow=(0.8, 0.8, 0.8))
    xsect.plot_grid(alpha=0.2)
    ax.set_ylim([0, 40])

    ax = fig.add_subplot(1, 3, 3)
    ax.set_title(
        f"Freyberg head cross-section (t = {int(time)}, head shape = {head2.shape})"
    )
    xsect = flopy.plot.PlotCrossSection(
        modelgrid=mfgrid, ax=ax, line={"line": line}, geographic_coords=True
    )
    cmap = xsect.plot_array(
        head2,
        masked_values=[-999.99],
        head=head2,
        alpha=0.4,
    )
    contours = xsect.contour_array(
        head2, head=head2, levels=levels, alpha=1.0, colors="blue"
    )
    xsect.plot_inactive(ibound=ibound, color_noflow=(0.8, 0.8, 0.8))
    xsect.plot_grid(alpha=0.2)
    ax.set_ylim([0, 40])
../_images/Notebooks_flopy3_mfusg_freyberg_21_0.png
../_images/Notebooks_flopy3_mfusg_freyberg_21_1.png
../_images/Notebooks_flopy3_mfusg_freyberg_21_2.png
[12]:
try:
    # ignore PermissionError on Windows
    temp_dir.cleanup()
except:
    pass