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

Infiltrating Heat Front

An example demonstrating that a specified energy flux boundary condition works as expected when compared to an analytical solution.

Initial Setup

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

[1]:
import math
import os
import pathlib as pl
from pprint import pformat

import flopy
import git
import matplotlib.pyplot as plt
import numpy as np
from flopy.mf6 import MFSimulation
from matplotlib.lines import Line2D
from matplotlib.patches import Patch
from modflow_devtools.misc import get_env, timed

[2]:
# 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-gwe-danckwerts"
# shorten model names so they fit in 16-char limit
gwfname = "gwf-" + sim_name.replace("ex-gwe-", "")
gwename = "gwe-" + sim_name.replace("ex-gwe-", "")

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()
data_path = root / "data" / sim_name if root else pl.Path.cwd()
sim_ws = workspace / sim_name

# 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)
[3]:
# ### Define analytical solution functions
# Analytical solution derived by Alden Provost, similar in form to
# Barends (2010) Equation 5 - but remember that that solution
# pins the temperature of the top cell to a specified temperature
# rather than specifying what the input energy flux is.
def flux_analyt(t, z, qt0, qtinfil, v, d):
    if t == 0.0:
        flux = qt0
    else:
        denom = 2.0 * math.sqrt(d * t)
        ztermm = (z - v * t) / denom
        ztermp = (z + v * t) / denom
        vterm = v * z / d
        if vterm < 100.0:
            # might need to adjust this limit
            flux = qt0 + (qtinfil - qt0) * 0.5 * (
                math.erfc(ztermm) + math.exp(vterm) * math.erfc(ztermp)
            )
        else:
            zeta = 1.0 / (1.0 + 0.47047 * ztermp)
            polyterm = zeta * (0.3480242 + zeta * (-0.0958798 + zeta * 0.7478556))
            flux = qt0 + 0.5 * (qtinfil - qt0) * (
                math.erfc(ztermm) + math.exp(vterm - ztermp**2) * polyterm
            )

    return flux
[4]:
def temp_analyt(t, z, t0, tinfil, v, d):
    if t == 0.0:
        temp = t0
    else:
        denom = 2.0 * math.sqrt(d * t)
        ztermm = (z - v * t) / denom
        ztermp = (z + v * t) / denom
        vterm = v * z / d
        if vterm < 100.0:
            # might need to adjust this limit
            temp = t0 + 0.5 * (tinfil - t0) * (
                math.erfc(ztermm) + math.exp(vterm) * math.erfc(ztermp)
            )
        else:
            zeta = 1.0 / (1.0 + 0.47047 * ztermp)
            polyterm = zeta * (0.3480242 + zeta * (-0.0958798 + zeta * 0.7478556))
            temp = t0 + 0.5 * (tinfil - t0) * (
                math.erfc(ztermm) + math.exp(vterm - ztermp**2) * polyterm
            )

    return temp
[5]:
# ### Define parameters
#
# Define model units, parameters and other settings.

# Model units
length_units = "meters"
time_units = "days"

# Model parameters
nlay = 101  # Number of layers ($-$)
nrow = 1  # Number of rows ($-$)
ncol = 1  # Number of columns ($-$)
nper = 2  # Number of simulated periods ($-$)
delr = 1.0  # Cell width ($m$)
delc = 1.0  # Cell length ($m$)
delz = 0.1  # Cell thickness ($m$)
strt = 0.05  # Initial head ($m$)
top = 10.00  # Top of the model grid ($m$)
strt_temp = 10.0  # Initial temperature ($^{\circ}C$)
scheme = "Upstream"  # Advection scheme ($-$)
dispersivity = 0.0  # Longitudinal mechanical dispersion term ($m$)
prsity = 0.2  # Porosity ($-$)
rhos = 1500.0  # Density of dry solid aquifer material ($\frac{kg}{m^3}$)
cps = 760.0  # Heat capacity of dry solid aquifer material ($\frac{J}{kg \cdot ^{\circ} C}$)
rhow = 1000.0  # Density of water ($\frac{kg}{m^3}$)
cpw = 4183.0  # Heat capacity of water ($\frac{J}{kg \cdot ^{\circ} C}$)
ktw = 0.5918  # Thermal conductivity of water ($\frac{W}{m \cdot ^{\circ} C}$)
kts = 0.27  # Thermal conductivity of solid aquifer material ($\frac{W}{m \cdot ^{\circ} C}$)
finf = 0.01  # Infiltration rate ($\frac{m}{d}$)
chdval = 0.05  # Contant head at the model outlet ($m$)
thtr = 0.0001  # Residual water content of the unsaturated zone ($-$)
thts = 0.20  # Saturated water content of the unsaturated zone ($-$)
thti = 0.055  # Initial water content of the unsaturated zone ($-$)
eps = 4.0  # Brooks-Corey epsilon parameter ($-$)
vks = 1.0  # Vertical hydraulic conductivity of the unsaturated zone ($\frac{m}{d}$)
t0 = 10.0  # Initial temperature in simulation domain ($^{\circ} C$)
tinfil = 20.0  # Temperature of infiltrating water ($^{\circ} C$)

[6]:
# Solver parameters
nouter, ninner = 100, 300
hclose, rclose, relax = 1e-9, 1e-3, 0.97
steady = {0: False, 1: False}
transient = {0: True, 1: True}

[7]:
# Values that do not show up in the table generated for latex
perlen = [1.0e9, 100.0]  # Length of stress periods ($-$)
nstp = [1, 100]  # Number of time steps per stress period ($-$)
tsmult = len(perlen) * [1.0]  # Time step multiplier ($-$)

top += 0.0005  # Add thin amount to upper layer for placing the node at 10.0 m
botm = [9.9995]  # Thickness of uppermost boundary cell ($m$)
for i in np.arange(1, nlay):
    bot = 10.0 - (i * delz)
    botm.append(round(bot, 1))

idomain = [1] * nlay

q = finf  # infiltration rate
area = delr * delc
rhowCpw = cpw * rhow
rhosCps = cps * rhos
lhv = 2500.0  # Latent heat of vaporization

# transient uzf info
# iuzno  cellid landflg ivertcn surfdp vks thtr thts thti eps [bndnm]
uzf_pkdat = [[0, (0, 0, 0), 1, 1, 0.00001, vks, thtr, thts, thti, eps]]

# Continue building the UZF list of objects
for iuzno in np.arange(1, 100, 1):
    if iuzno < nlay - 2:
        ivertconn = iuzno + 1
    else:
        ivertconn = -1

    uzf_pkdat.append(
        [iuzno, (iuzno, 0, 0), 0, ivertconn, 0.01, vks, thtr, thts, thti, eps]
    )

iuz_cell_dict = {}
cell_iuz_dict = {}
for i, itm in enumerate(uzf_pkdat):
    iuz_cell_dict.update({itm[0]: (itm[1][0], itm[1][1], itm[1][2])})
    cell_iuz_dict.update({(itm[1][0], itm[1][1], itm[1][2]): itm[0]})

extdp = 0.0
pet = 0.0
extwc = 0.0
zero = 0.0
uzf_spd = {
    0: [[0, finf, pet, extdp, extwc, zero, zero, zero]],
    1: [[0, finf, pet, extdp, extwc, zero, zero, zero]],
}

[8]:
def build_model(sim_name):
    print(f"Building models for {sim_name}")

    # build MODFLOW 6 files
    sim = flopy.mf6.MFSimulation(
        sim_name=sim_name, version="mf6", exe_name="mf6", sim_ws=sim_ws
    )

    print(sim.sim_path)

    # create tdis package
    tdis_rc = []
    for i in range(nper):
        tdis_rc.append((perlen[i], nstp[i], tsmult[i]))

    flopy.mf6.ModflowTdis(sim, time_units=time_units, nper=nper, perioddata=tdis_rc)

    newtonoptions = ["NEWTON", "UNDER_RELAXATION"]
    # create gwf model
    gwf = flopy.mf6.ModflowGwf(
        sim,
        modelname=gwfname,
        newtonoptions=newtonoptions,
        save_flows=True,
    )

    # create iterative model solution and register the gwf model with it
    ims = flopy.mf6.ModflowIms(
        sim,
        print_option="SUMMARY",
        complexity="MODERATE",
        outer_dvclose=hclose,
        outer_maximum=nouter,
        under_relaxation="DBD",
        inner_maximum=ninner,
        inner_dvclose=hclose,
        rcloserecord=rclose,
        linear_acceleration="BICGSTAB",
        scaling_method="NONE",
        reordering_method="NONE",
        relaxation_factor=relax,
        filename=f"{gwfname}.ims",
    )
    sim.register_ims_package(ims, [gwf.name])

    flopy.mf6.ModflowGwfdis(
        gwf,
        nlay=nlay,
        nrow=nrow,
        ncol=ncol,
        delr=delr,
        delc=delc,
        top=top,
        botm=botm,
        idomain=idomain,
        filename=f"{gwfname}.dis",
    )

    # initial conditions
    flopy.mf6.ModflowGwfic(
        gwf,
        strt=strt,
        filename=f"{gwfname}.ic",
    )

    # node property flow
    flopy.mf6.ModflowGwfnpf(
        gwf,
        save_flows=True,
        icelltype=1,
        k=100.0,
        k33=10,
        filename=f"{gwfname}.npf",
    )

    # aquifer storage
    flopy.mf6.ModflowGwfsto(
        gwf,
        iconvert=1,
        ss=1e-5,
        sy=prsity,
        steady_state=steady,
        transient=transient,
        filename=f"{gwfname}.sto",
    )

    # constant head for draining the model
    chdspd = {0: [[(100, 0, 0), chdval, 10.0]]}

    flopy.mf6.ModflowGwfchd(
        gwf,
        auxiliary=["TEMPERATURE"],
        print_flows=True,
        stress_period_data=chdspd,
        pname="CHD-1",
        filename=f"{gwfname}.chd",
    )

    # Unsaturated-zone flow package
    flopy.mf6.ModflowGwfuzf(
        gwf,
        print_flows=True,
        save_flows=True,
        wc_filerecord=gwfname + ".uzfwc.bin",
        simulate_et=False,
        simulate_gwseep=False,
        linear_gwet=False,
        boundnames=False,
        ntrailwaves=15,
        nwavesets=40,
        nuzfcells=len(uzf_pkdat),
        packagedata=uzf_pkdat,
        perioddata=uzf_spd,
        budget_filerecord=f"{gwfname}.uzf.bud",
        pname="UZF-1",
        filename=f"{gwfname}.uzf",
    )

    # output control
    flopy.mf6.ModflowGwfoc(
        gwf,
        budget_filerecord=f"{gwfname}.cbc",
        head_filerecord=f"{gwfname}.hds",
        headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
        saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
        printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
        filename=f"{gwfname}.oc",
    )

    # ----------------------------------------------------
    # Instantiating MODFLOW 6 GWE model
    # ----------------------------------------------------
    gwe = flopy.mf6.MFModel(
        sim, model_type="gwe6", modelname=gwename, model_nam_file=f"{gwename}.nam"
    )
    gwe.name_file.save_flows = True

    imsgwe = flopy.mf6.ModflowIms(
        sim,
        print_option="SUMMARY",
        outer_dvclose=hclose,
        outer_maximum=nouter,
        under_relaxation="NONE",
        inner_maximum=ninner,
        inner_dvclose=hclose,
        rcloserecord=rclose,
        linear_acceleration="BICGSTAB",
        scaling_method="NONE",
        reordering_method="NONE",
        relaxation_factor=relax,
        filename="{}.ims".format(gwename),
    )
    sim.register_ims_package(imsgwe, [gwe.name])

    # Instantiating MODFLOW 6 transport discretization package
    flopy.mf6.ModflowGwedis(
        gwe,
        nogrb=True,
        nlay=nlay,
        nrow=nrow,
        ncol=ncol,
        delr=delr,
        delc=delc,
        top=top,
        botm=botm,
        idomain=idomain,
        pname="DIS",
        filename=f"{gwename}.dis",
    )

    # Instantiating MODFLOW 6 transport initial concentrations
    flopy.mf6.ModflowGweic(
        gwe,
        strt=strt_temp,
        pname="IC",
        filename=f"{gwename}.ic",
    )

    # Instantiating MODFLOW 6 transport advection package
    flopy.mf6.ModflowGweadv(
        gwe, scheme=scheme, pname="ADV", filename="{}.adv".format(gwename)
    )

    # Instantiating MODFLOW 6 transport dispersion package
    flopy.mf6.ModflowGwecnd(
        gwe,
        xt3d_off=False,
        alh=dispersivity,
        ath1=dispersivity,
        ktw=ktw * 86400,
        kts=kts * 86400,
        pname="CND",
        filename=f"{gwename}.cnd",
    )

    # Instantiating MODFLOW 6 transport mass storage package
    flopy.mf6.ModflowGweest(
        gwe,
        save_flows=True,
        porosity=prsity,
        cps=cps,
        rhos=rhos,
        packagedata=[cpw, rhow, lhv],
        pname="EST",
        filename=f"{gwename}.est",
    )

    # Instantiating MODFLOW 6 transport source-sink mixing package
    srctype = "AUX"
    auxname = "TEMPERATURE"
    pname = ["CHD-1"]
    # Inpput to SSM is: <pname> <srctype> <auxname>
    sources = [[itm, srctype, auxname] for itm in pname]

    flopy.mf6.ModflowGwessm(
        gwe,
        sources=sources,
        pname="SSM",
        filename=f"{gwename}.ssm",
    )

    # Instantiating MODFLOW 6 energy transport source-sink mixing package
    uzepackagedata = [(iuz, 10.0) for iuz in range(nlay - 1)]
    uzeperioddata = {0: [[0, "INFILTRATION", 10.0]], 1: [[0, "INFILTRATION", 20.0]]}

    flopy.mf6.ModflowGweuze(
        gwe,
        flow_package_name="UZF-1",
        boundnames=False,
        save_flows=True,
        print_input=True,
        print_flows=True,
        print_temperature=True,
        temperature_filerecord=gwename + ".uze.bin",
        budget_filerecord=gwename + ".uze.bud",
        packagedata=uzepackagedata,
        uzeperioddata=uzeperioddata,
        pname="UZE",
        filename=f"{gwename}.uze",
    )

    # Instantiate MODFLOW 6 heat transport output control package
    flopy.mf6.ModflowGweoc(
        gwe,
        pname="OC",
        budget_filerecord="{}.cbc".format(gwename),
        temperature_filerecord="{}.ucn".format(gwename),
        temperatureprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
        saverecord=[("TEMPERATURE", "ALL"), ("BUDGET", "ALL")],
        printrecord=[("TEMPERATURE", "ALL"), ("BUDGET", "ALL")],
        filename=f"{gwename}.oc",
    )

    # Instantiate Gwf-Gwe Exchange package
    flopy.mf6.ModflowGwfgwe(
        sim,
        exgtype="GWF6-GWE6",
        exgmnamea=gwfname,
        exgmnameb=gwename,
        filename="{}.gwfgwe".format(gwename),
    )

    return sim
[9]:
def write_model(sim, silent=True):
    print("Writing input for 1D Danckwerts test model...")
    success = False
    if isinstance(sim, MFSimulation):
        sim.write_simulation(silent=silent)
    else:
        sim.write_input()
[10]:
@timed
def run_model(sim, silent=True):
    print("running 1D Danckwerts test model...")
    if isinstance(sim, MFSimulation):
        success, buff = sim.run_simulation(silent=silent, report=True)
    else:
        sim.run_model(silent=silent, report=True)
    assert success, pformat(buff)
[11]:
def plot_sim_vs_analytical_sln(sim):
    print("comparing simulated results to analytical solution...")

    ws = sim.sim_path  # exdirs[sim.idxsim]

    # check some output...
    wc_fl = gwfname + ".uzfwc.bin"
    wcobj = flopy.utils.HeadFile(os.path.join(ws, wc_fl), text="water-content")
    wc = wcobj.get_alldata()

    # temperature output
    fl2 = gwename + ".uze.bin"
    uzeobj = flopy.utils.HeadFile(os.path.join(ws, fl2), text="TEMPERATURE")
    temps = uzeobj.get_alldata()

    # Cell flows output
    qfile = gwename + ".cbc"
    gweflowsobj = flopy.utils.CellBudgetFile(os.path.join(ws, qfile))

    # Binary grid file needed for post-processing
    fgrb = gwfname + ".dis.grb"
    grb_file = os.path.join(ws, fgrb)

    # UZE flows
    fuzebud = gwename + ".uze.bud"
    uzeflowsobj = flopy.utils.CellBudgetFile(os.path.join(ws, fuzebud))
    flowsadv = uzeflowsobj.get_data(text="FLOW-JA-FACE")

    t = np.linspace(0.0, 100.0, 101)
    z = np.linspace(0.0, 9.9, 99)

    Kts = kts * 86400
    Ktw = 0.0

    steady_wc = wc[1, 0, 0, 0]
    Sw = steady_wc / prsity

    rhoCp_bulk = Sw * prsity * rhowCpw + (1 - prsity) * rhosCps
    Kt_bulk = Sw * prsity * Ktw + (1 - prsity) * Kts
    v = rhowCpw / rhoCp_bulk * q
    D = Kt_bulk / rhoCp_bulk

    qt0 = q * t0
    qtinfil = q * tinfil

    # for converting from J/day to W
    unitadj = 1 / 86400

    conv10 = []
    cond10 = []
    conv50 = []
    cond50 = []
    conv100 = []
    cond100 = []
    analytical_sln = np.zeros((len(t), len(z)))
    simulated_sln = np.zeros((len(t), len(z)))
    for i, tm in enumerate(t):
        if i == 0:
            gweflowjaface = gweflowsobj.get_data(text="FLOW-JA-FACE", kstpkper=(0, 0))
        else:
            gweflowjaface = gweflowsobj.get_data(
                text="FLOW-JA-FACE", kstpkper=(i - 1, 1)
            )
        flowscond = flopy.mf6.utils.postprocessing.get_structured_faceflows(
            gweflowjaface[0][0], grb_file=grb_file
        )
        for j, depth in enumerate(z):
            fluxa = flux_analyt(tm, depth, qt0, qtinfil, v, D)
            analytical_sln[i, j] = fluxa * rhowCpw * unitadj

            (uze1, uze2, floadv) = flowsadv[i][2 * j + 1]
            floadv /= rhowCpw
            flocond = flowscond[2][j][0][0]
            flocond /= rhowCpw

            flo = floadv * rhowCpw * unitadj + flocond * rhowCpw * unitadj
            if i == 10:
                conv10.append(floadv * rhowCpw * unitadj)
                cond10.append(flocond * rhowCpw * unitadj)
            elif i == 50:
                conv50.append(floadv * rhowCpw * unitadj)
                cond50.append(flocond * rhowCpw * unitadj)
            elif i == 100:
                conv100.append(floadv * rhowCpw * unitadj)
                cond100.append(flocond * rhowCpw * unitadj)

            flux = flo / area
            simulated_sln[i, j] = flux

    # A summary figure without parsing advection and conduction
    fig, ax = plt.subplots(ncols=1, figsize=(3, 6))
    ax.plot(analytical_sln[10], z, "-", color="red", label="Analytical")
    ax.plot(simulated_sln[10], z, "-.", color="blue", label="MODFLOW 6")
    # 50th transient stress period
    ax.plot(analytical_sln[50], z, "-", color="red")
    ax.plot(simulated_sln[50], z, "-.", color="blue")
    # last stress period
    ax.plot(analytical_sln[100], z, "-", color="red")
    ax.plot(simulated_sln[100], z, "-.", color="blue")
    # add labels
    ax.text(5.2, 1.95, "10 days", fontsize=10)
    ax.text(6.5, 3.30, "50 days", fontsize=10)
    ax.text(7.25, 4.70, "100 days", fontsize=10)

    plt.gca().invert_yaxis()
    ax.set_xlabel(r"Energy Flux, $\dfrac{Watts}{m^2}$")
    ax.set_ylabel("Depth, $m$")
    plt.minorticks_on()
    plt.axhline(y=0.0)
    plt.legend(loc="lower right", frameon=False)
    plt.tight_layout()

    # show and/or save figure
    if plot_show:
        plt.show()
    if plot_save:
        fpth = figs_path / "{}{}".format("ex-" + gwename + "-01", ".png")
        fig.savefig(fpth, dpi=600)

    # Generate plots corresponding to three different times
    fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(7.0, 5))

    # 10 days
    # -------
    polys1 = ax1.stackplot(
        z,
        conv10,
        cond10,
        labels=["Convection", "Conduction"],
        colors=["lightseagreen", "lightgreen"],
    )
    for poly in polys1:
        for path in poly.get_paths():
            path.vertices = path.vertices[:, ::-1]
    ax1.set_xlim(0.095 * rhowCpw * unitadj, 0.205 * rhowCpw * unitadj)
    ax1.set_ylim([9.9, 0.0])
    ax1.plot(simulated_sln[10], z, "-", color="blue", linewidth=2)
    ax1.plot(analytical_sln[10], z, "-.", color="red")
    ax1.text(4.9, 0.4, "10 Days")

    legend_elements = [
        Line2D(
            [0],
            [0],
            linestyle="-",
            color="blue",
            lw=2,
            label="MODFLOW 6\nTotal Heat Flux",
        ),
        Line2D([0], [0], linestyle="-.", color="red", lw=1, label="Analytical"),
        Patch(facecolor="lightseagreen", edgecolor="lightseagreen", label="Convection"),
        Patch(facecolor="lightgreen", edgecolor="lightgreen", label="Conduction"),
    ]

    ax1.legend(handles=legend_elements, loc="lower right", frameon=False)
    ax1.set_xlabel(r"Energy Flux, $\dfrac{Watts}{m^2}$")
    ax1.set_ylabel("Depth, m")

    # 50 days
    # -------
    polys2 = ax2.stackplot(
        z,
        conv50,
        cond50,
        labels=["Convection", "Conduction"],
        colors=["lightseagreen", "lightgreen"],
    )
    for poly in polys2:
        for path in poly.get_paths():
            path.vertices = path.vertices[:, ::-1]
    ax2.set_xlim(0.095 * rhowCpw * unitadj, 0.205 * rhowCpw * unitadj)
    ax2.set_ylim([9.9, 0.0])  # or xlims[::-1]
    ax2.plot(simulated_sln[50], z, "-", color="blue", linewidth=2)
    ax2.plot(analytical_sln[50], z, "-.", color="red")
    ax2.set_xlabel(r"Energy Flux, $\dfrac{Watts}{m^2}$")
    ax2.text(4.9, 0.4, "50 Days")

    # 100 days
    # -------
    polys3 = ax3.stackplot(
        z,
        conv100,
        cond100,
        labels=["Convection", "Conduction"],
        colors=["lightseagreen", "lightgreen"],
    )
    for poly in polys3:
        for path in poly.get_paths():
            path.vertices = path.vertices[:, ::-1]
    ax3.set_xlim(0.095 * rhowCpw * unitadj, 0.205 * rhowCpw * unitadj)
    ax3.set_ylim([9.9, 0.0])  # or xlims[::-1]
    ax3.plot(simulated_sln[100], z, "-", color="blue", linewidth=2)
    ax3.plot(analytical_sln[100], z, "-.", color="red")
    ax3.set_xlabel(r"Energy Flux, $\dfrac{Watts}{m^2}$")
    ax3.text(4.9, 0.4, "100 Days")

    plt.tight_layout()

    # show and/or save figure
    if plot_show:
        plt.show()
    if plot_save:
        fpth = figs_path / "{}{}".format("ex-" + gwename + "-02", ".png")
        fig.savefig(fpth, dpi=600)
[12]:
# ### Running the example
#
# Define a function to run the example scenarios and plot results.


def scenario(silent=True):
    sim = build_model(sim_name)
    if isinstance(sim, MFSimulation) and write:
        write_model(sim, silent=silent)
    if run:
        run_model(sim, silent=silent)
    if plot:
        plot_sim_vs_analytical_sln(sim)
[13]:
# Initiate model construction, write, run, and plot sequence
scenario(silent=True)
Building models for ex-gwe-danckwerts
/home/runner/work/modflow6-examples/modflow6-examples/modflow6-examples/examples/ex-gwe-danckwerts
Writing input for 1D Danckwerts test model...
running 1D Danckwerts test model...
run_model took 1701.42 ms
comparing simulated results to analytical solution...
../_images/_notebooks_ex-gwe-danckwerts_14_3.png
../_images/_notebooks_ex-gwe-danckwerts_14_4.png