This page was generated from ex-gwf-zaidel.py. It's also available as a notebook.

Zaidel Problem

Described in Zaidel (2013), representing a discontinuous water table configuration over a stairway impervious base.

Initial setup

Import dependencies, define the example name and workspace, and read settings from environment variables.

[1]:
import os
import pathlib as pl

import flopy
import git
import matplotlib.pyplot as plt
import numpy as np
from flopy.plot.styles import styles
from modflow_devtools.misc import get_env, timed

# Example name and workspace paths. If this example is running
# in the git repository, use the folder structure described in
# the README. Otherwise just use the current working directory.
sim_name = "ex-gwf-zaidel"
try:
    root = pl.Path(git.Repo(".", search_parent_directories=True).working_dir)
except:
    root = None
workspace = root / "examples" if root else pl.Path.cwd()
figs_path = root / "figures" if root else pl.Path.cwd()

# Settings from environment variables
write = get_env("WRITE", True)
run = get_env("RUN", True)
plot = get_env("PLOT", True)
plot_show = get_env("PLOT_SHOW", True)
plot_save = get_env("PLOT_SAVE", True)

Define parameters

Define model units, parameters and other settings.

[2]:
# Model units
length_units = "meters"
time_units = "days"

# Scenario-specific parameters
parameters = {
    "ex-gwf-zaidel-p01a": {
        "H2": 1.0,
    },
    "ex-gwf-zaidel-p02a": {
        "H2": 10.0,
    },
}

# Model parameters
nper = 1  # Number of periods
nlay = 1  # Number of layers
nrow = 1  # Number of rows
ncol = 200  # Number of columns
delr = 5.0  # Column width ($m$)
delc = 1.0  # Row width ($m$)
top = 25.0  # Top of the model ($m$)
strt = 23.0  # Starting head ($m$)
icelltype = 1  # Cell conversion type
k11 = 0.0001  # Horizontal hydraulic conductivity ($m/day$)
H1 = 23.0  # Constant head in column 1 ($m$)

# Time discretization
tdis_ds = ((1.0, 1, 1.0),)

# Build stairway bottom
botm = np.zeros((nlay, nrow, ncol), dtype=float)
base = 20.0
for j in range(ncol):
    botm[0, :, j] = base
    if j + 1 in (40, 80, 120, 160):
        base -= 5

# Solver parameters
nouter = 500
ninner = 50
hclose = 1e-9
rclose = 1e-6

Model setup

Define functions to build models, write input files, and run the simulation.

[3]:
def build_models(H2=1.0):
    # Constant head cells are specified on the left and right edge of the model
    chd_spd = [
        [0, 0, 0, H1],
        [0, 0, ncol - 1, H2],
    ]

    sim_ws = os.path.join(workspace, sim_name)
    sim = flopy.mf6.MFSimulation(sim_name=sim_name, sim_ws=sim_ws, exe_name="mf6")
    flopy.mf6.ModflowTdis(sim, nper=nper, perioddata=tdis_ds, time_units=time_units)
    flopy.mf6.ModflowIms(
        sim,
        linear_acceleration="bicgstab",
        outer_maximum=nouter,
        outer_dvclose=hclose,
        inner_maximum=ninner,
        inner_dvclose=hclose,
        rcloserecord=f"{rclose} strict",
    )
    gwf = flopy.mf6.ModflowGwf(sim, modelname=sim_name, newtonoptions="newton")
    flopy.mf6.ModflowGwfdis(
        gwf,
        length_units=length_units,
        nlay=nlay,
        nrow=nrow,
        ncol=ncol,
        delr=delr,
        delc=delc,
        top=top,
        botm=botm,
    )
    flopy.mf6.ModflowGwfnpf(
        gwf,
        icelltype=icelltype,
        k=k11,
    )
    flopy.mf6.ModflowGwfic(gwf, strt=strt)
    flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd)

    head_filerecord = f"{sim_name}.hds"
    flopy.mf6.ModflowGwfoc(
        gwf,
        head_filerecord=head_filerecord,
        saverecord=[("HEAD", "ALL")],
    )
    return sim


def write_models(sim, silent=True):
    sim.write_simulation(silent=silent)


@timed
def run_models(sim, silent=True):
    success, buff = sim.run_simulation(silent=silent)
    assert success, buff

Plotting results

Define functions to plot model results.

[4]:
# Figure properties
figure_size = (6.3, 2.5)


def plot_results(idx, sim, silent=True):
    with styles.USGSMap():
        gwf = sim.get_model(sim_name)
        xedge = gwf.modelgrid.xvertices[0]
        zedge = np.array([botm[0, 0, 0]] + botm.flatten().tolist())

        # create MODFLOW 6 head object
        hobj = gwf.output.head()

        # extract heads
        head = hobj.get_data()
        vmin, vmax = 0, 25

        # Create figure for simulation
        extents = (0, ncol * delr, -1, 25.0)
        fig, ax = plt.subplots(
            ncols=1,
            nrows=1,
            figsize=figure_size,
            dpi=300,
            constrained_layout=True,
            sharey=True,
        )

        ax.set_xlim(extents[:2])
        ax.set_ylim(extents[2:])

        fmp = flopy.plot.PlotCrossSection(
            model=gwf, ax=ax, extent=extents, line={"row": 0}
        )
        ax.fill_between(xedge, zedge, y2=-1, color="0.75", step="pre", lw=0.0)
        plot_obj = fmp.plot_array(head, head=head, vmin=vmin, vmax=vmax)
        fmp.plot_bc("CHD", color="cyan", head=head)
        ax.set_xlabel("x-coordinate, in meters")
        ax.set_ylabel("Elevation, in meters")

        # create legend
        ax.plot(
            -10000,
            -10000,
            lw=0,
            marker="s",
            ms=10,
            mfc="cyan",
            mec="cyan",
            label="Constant Head",
        )
        ax.plot(
            -10000,
            -10000,
            lw=0,
            marker="s",
            ms=10,
            mfc="0.75",
            mec="0.75",
            label="Model Base",
        )
        styles.graph_legend(ax, ncol=2, loc="upper right")

        # plot colorbar
        cax = plt.axes([0.62, 0.76, 0.325, 0.025])
        cbar = plt.colorbar(plot_obj, shrink=0.8, orientation="horizontal", cax=cax)
        cbar.ax.tick_params(size=0)
        cbar.ax.set_xlabel(r"Head, $m$", fontsize=9)

        if plot_show:
            plt.show()
        if plot_save:
            fpth = figs_path / f"{sim_name}-{idx + 1:02d}.png"
            fig.savefig(fpth)

Running the example

Define and invoke a function to run the example scenario, then plot results.

[5]:
def scenario(idx, silent=True):
    key = list(parameters.keys())[idx]
    params = parameters[key].copy()
    sim = build_models(**params)
    if write:
        write_models(sim, silent=silent)
    if run:
        run_models(sim, silent=silent)
    if plot:
        plot_results(idx, sim, silent=silent)

Run the Zaidel model with H2 = 1, then plot simulated heads.

[6]:
scenario(0)
<flopy.mf6.data.mfstructure.MFDataItemStructure object at 0x7fee9da73d60>
run_models took 20.96 ms
../_images/_notebooks_ex-gwf-zaidel_12_1.png

Run the Zaidel model with H2 = 10, then plot simulated heads.

[7]:
scenario(1)
<flopy.mf6.data.mfstructure.MFDataItemStructure object at 0x7fee9da73d60>
run_models took 17.39 ms
../_images/_notebooks_ex-gwf-zaidel_14_1.png