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

Viscosity

This example provides a simple demonstration of how to account for the effects of temperature on viscosity.

The basic model setup uses the third MT3DMS demonstration model titled, “Two-Dimensional Transport in a Uniform Flow Field.” In this 2D, left- to-right flow field, an injection well introduces solute that subsequently advects and disperses with time. Changes in the plumes behavior with viscosity activated, compared to the non-visous case, are highlighte by a 2D plot.

Initial setup

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

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

import flopy
import git
import matplotlib.colors as colors
import matplotlib.pyplot as plt
import numpy as np
import numpy.ma as ma
from flopy.mf6 import MFSimulation
from matplotlib.colors import LogNorm
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-gwe-vsc"

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()
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", False)
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"


# Set scenario parameters (make sure there is at least one blank line before next item)
# This entire dictionary is passed to _build_models()_ using the kwargs argument
parameters = {
    "30degGrad": {
        "temp_upper": 4.0,
        "temp_lower": 34.0,
    },
    "90degGrad": {
        "temp_upper": 4.0,
        "temp_lower": 94.0,
    },
}

# Scenario parameter units
parameter_units = {
    "temp_upper": r"$^{\circ}C$",
    "temp_lower": r"$^{\circ}C$",
}

# Model parameters
nlay = 1  # Number of layers
nrow = 31  # Number of rows
ncol = 46  # Number of columns
delr = 10.0  # Column width ($m$)
delc = 10.0  # Row width ($m$)
delz = 10.0  # Layer thickness ($m$)
top = 0.0  # Top of the model ($m$)
prsity = 0.3  # Porosity
perlen = 365  # Simulation time ($days$)
k11 = 1.0  # Horizontal hydraulic conductivity ($m/d$)
qwell = 1.0  # Volumetric injection rate ($m^3/d$)
cwell = 1000.0  # Concentration of injected water ($mg/L$)
al = 10.0  # Longitudinal dispersivity ($m$)
trpt = 0.3  # Ratio of transverse to longitudinal dispersivity
viscref = 8.904e-4  # Reference viscosity ($\frac{kg}{m \cdot sec}$)
tform = "nonlinear"  # Viscosity representation ($-$)
a2 = 10.0  # User-specified parameter in nonlinear formulation ($-$)
a3 = 248.37  # User-specified parameter in nonlinear formulation ($-$)
a4 = 133.16  # User-specified parameter in nonlinear formulation ($-$)
iviscspec = 0  # Species ID for use in a VSC package ($-$)
dviscdc = 0.0  # not used for the nonlinear formulation, but must be specified
cviscref = 20.0  # Reference temperature for viscosity ($^{\circ}C$)
gw_temp = 4.0  # Groundwater temperature ($^{\circ}C$)
scheme = "TVD"  # Advection scheme ($-$)
sconc = 0.0  # Starting concentration ($mg/L$)
cps = 800.0  # Heat capacity of aquifer material ($\frac{J}{kg \cdot ^{\circ} C}$)
cpw = 4180.0  # Heat capacity of water ($\frac{J}{kg \cdot ^{\circ} C}$)
rhow = 1000.0  # Density of water ($kg/m^3$)
rhos = 1200.0  # Density of dry solid aquifer material ($kg/m^3$)
lhv = 2500.0  # Latent heat of vaporization ($kJ/kg$)
kts = 0.25  # Thermal conductivity of the aquifer material ($\frac{W}{m \cdot ^{\circ} C}$)
ktw = 0.58  # Thermal conductivity of water ($\frac{W}{m \cdot ^{\circ} C}$)
c0 = 0.0  # Concentration of boundary inflow ($mg/L$)

# Additional model input
perlen = [1, 365.0]
nper = len(perlen)
nstp = [2, 730]
tsmult = [1.0, 1.0]

# Set some additional parameters
ath1 = al * trpt
botm = [top - delz]  # Model geometry
k33 = k11  # Vertical hydraulic conductivity ($m/d$)
icelltype = 0
kts *= 86400
ktw *= 86400

# Initial conditions
Lx = (ncol - 1) * delr
v = 1.0 / 3.0
prsity = 0.3
q = v * prsity
h1 = q * Lx
strt = np.zeros((nlay, nrow, ncol), dtype=float)
strt[0, :, 0] = h1

idomain = np.ones((nlay, nrow, ncol), dtype=int)
cnc_spd = [[(0, 0, 0), c0]]

# Set solver parameter values (and related)
nouter, ninner = 100, 300
hclose, rclose, relax = 1e-6, 1e-6, 1.0
ttsmult = 1.0

# Time discretization
tdis_rc = []
tdis_rc.append((perlen, nstp, 1.0))
[3]:
# A function for customizing colormaps
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
    new_cmap = colors.LinearSegmentedColormap.from_list(
        f"trunc({cmap.name},{minval:.2f},{maxval:.2f})",
        cmap(np.linspace(minval, maxval, n)),
    )
    return new_cmap

Model setup

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

[4]:
def add_gwf_model(sim, gwfname, activate_vsc):
    # Instantiating MODFLOW 6 groundwater flow model
    gwf = flopy.mf6.ModflowGwf(
        sim,
        modelname=gwfname,
        save_flows=True,
        model_nam_file=f"{gwfname}.nam",
    )

    # Instantiating MODFLOW 6 solver for flow model
    imsgwf = 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="CG",
        scaling_method="NONE",
        reordering_method="NONE",
        relaxation_factor=relax,
        filename=f"{gwfname}.ims",
    )
    sim.register_ims_package(imsgwf, [gwf.name])

    # Instantiating MODFLOW 6 discretization package
    flopy.mf6.ModflowGwfdis(
        gwf,
        length_units=length_units,
        nlay=nlay,
        nrow=nrow,
        ncol=ncol,
        delr=delr,
        delc=delc,
        top=top,
        botm=botm,
        idomain=np.ones((nlay, nrow, ncol), dtype=int),
        filename=f"{gwfname}.dis",
    )

    # Instantiating MODFLOW 6 node-property flow package
    flopy.mf6.ModflowGwfnpf(
        gwf,
        save_flows=False,
        icelltype=icelltype,
        k=k11,
        k33=k33,
        save_specific_discharge=True,
        filename=f"{gwfname}.npf",
    )

    # Instantiating MODFLOW 6 initial conditions package for flow model
    flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic")

    # Instantiate MODFLOW 6 storage package
    flopy.mf6.ModflowGwfsto(gwf, ss=0, sy=0, filename=f"{gwfname}.sto")

    global aux_names
    global wel_spd
    if activate_vsc:
        aux_names = ["CONCENTRATION", "TEMPERATURE"]
        wel_spd = {0: [[(0, 15, 15), qwell, cwell, gw_temp]]}  # MF6 pumping information
    else:
        aux_names = ["CONCENTRATION"]
        wel_spd = {0: [[(0, 15, 15), qwell, cwell]]}  # MF6 pumping information

    # Instantiate the wel package
    flopy.mf6.ModflowGwfwel(
        gwf,
        print_input=True,
        print_flows=True,
        stress_period_data=wel_spd,
        save_flows=False,
        auxiliary=aux_names,
        pname="WEL-1",
        filename=f"{gwfname}.wel",
    )

    # Instantiating MODFLOW 6 constant head package
    rowList = np.arange(0, nrow).tolist()
    chdspd_l = []
    chdspd_r = []
    # Loop through the left & right sides.
    for itm in rowList:
        # first, constant head on left side of model
        if activate_vsc:
            chdspd_l.append([(0, itm, 0), h1, 0.0, gw_temp])
        else:
            chdspd_l.append([(0, itm, 0), h1, 0.0])

        # constant head on right side of model
        chdspd_r.append([(0, itm, ncol - 1), 0.0])

    # left side boundary condition
    chd_spd_l = {0: chdspd_l}
    flopy.mf6.ModflowGwfchd(
        gwf,
        maxbound=len(chd_spd_l),
        stress_period_data=chd_spd_l,
        auxiliary=aux_names,
        save_flows=False,
        pname="CHD-l",
        filename=f"{gwfname}.left.chd",
    )

    # right side boundary condition
    chd_spd_r = {0: chdspd_r}
    flopy.mf6.ModflowGwfchd(
        gwf,
        maxbound=len(chdspd_r),
        stress_period_data=chd_spd_r,
        save_flows=False,
        pname="CHD-r",
        filename=f"{gwfname}.right.chd",
    )

    if activate_vsc:
        # Instantiate viscosity (VSC) package
        vsc_filerecord = f"{gwfname}.vsc.bin"
        gwename2 = sim_name + "-02"
        vsc_pd = [(iviscspec, dviscdc, cviscref, gwename2, "TEMPERATURE")]
        flopy.mf6.ModflowGwfvsc(
            gwf,
            viscref=viscref,
            viscosity_filerecord=vsc_filerecord,
            thermal_formulation=tform,
            thermal_a2=a2,
            thermal_a3=a3,
            thermal_a4=a4,
            nviscspecies=len(vsc_pd),
            packagedata=vsc_pd,
            pname="VSC",
            filename=f"{gwfname}.vsc",
        )

    # Instantiating MODFLOW 6 output control package for flow model
    flopy.mf6.ModflowGwfoc(
        gwf,
        head_filerecord=f"{gwfname}.hds",
        budget_filerecord=f"{gwfname}.bud",
        headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
        saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")],
        printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")],
    )

    return sim
[5]:
def add_gwt_model(sim, gwtname):
    # Instantiating MODFLOW 6 groundwater transport package
    gwt = flopy.mf6.MFModel(
        sim,
        model_type="gwt6",
        modelname=gwtname,
        model_nam_file=f"{gwtname}.nam",
    )
    gwt.name_file.save_flows = True

    # create iterative model solution and register the gwt model with it
    imsgwt = 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=f"{gwtname}.ims",
    )
    sim.register_ims_package(imsgwt, [gwt.name])

    # Instantiating MODFLOW 6 transport discretization package
    flopy.mf6.ModflowGwtdis(
        gwt,
        length_units=length_units,
        nlay=nlay,
        nrow=nrow,
        ncol=ncol,
        delr=delr,
        delc=delc,
        top=top,
        botm=botm,
        idomain=1,
        pname="DIS",
        filename=f"{gwtname}.dis",
    )

    # Instantiating MODFLOW 6 transport initial concentrations
    flopy.mf6.ModflowGwtic(gwt, strt=sconc, filename=f"{gwtname}.ic")

    # Instantiating MODFLOW 6 transport advection package
    flopy.mf6.ModflowGwtadv(gwt, scheme=scheme, filename=f"{gwtname}.adv")

    # Instantiating MODFLOW 6 transport dispersion package
    flopy.mf6.ModflowGwtdsp(
        gwt,
        xt3d_off=True,
        alh=al,
        ath1=ath1,
        filename=f"{gwtname}.dsp",
    )

    # Instantiating MODFLOW 6 transport mass storage package (formerly "reaction" package in MT3DMS)
    flopy.mf6.ModflowGwtmst(
        gwt,
        porosity=prsity,
        first_order_decay=False,
        decay=None,
        decay_sorbed=None,
        sorption=None,
        bulk_density=None,
        distcoef=None,
        filename=f"{gwtname}.mst",
    )

    # Instantiating MODFLOW 6 transport constant concentration package
    flopy.mf6.ModflowGwtcnc(
        gwt,
        maxbound=len(cnc_spd),
        stress_period_data=cnc_spd,
        save_flows=False,
        pname="CNC-1",
        filename=f"{gwtname}.cnc",
    )

    # Instantiating MODFLOW 6 transport source-sink mixing package
    sourcerecarray = [
        ("WEL-1", "AUX", "CONCENTRATION"),
        ("CHD-l", "AUX", "CONCENTRATION"),
    ]
    flopy.mf6.ModflowGwtssm(
        gwt, sources=sourcerecarray, pname="SSM", filename=f"{gwtname}.ssm"
    )

    # Instantiating MODFLOW 6 transport output control package
    flopy.mf6.ModflowGwtoc(
        gwt,
        budget_filerecord=f"{gwtname}.cbc",
        concentration_filerecord=f"{gwtname}.ucn",
        concentrationprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
        saverecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")],
        printrecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")],
    )

    return sim
[6]:
def add_gwe_model(sim, gwename, temp_upper=4.0, temp_lower=4.0):
    # Set up initial temperatures and left boundary inflow temperature
    ini_temp = np.ones((nrow, ncol))
    ctp_spd = []
    temp_diff = temp_lower - temp_upper
    for i in range(nrow):
        temp = temp_diff * i / (nrow - 1) + temp_upper
        ini_temp[i, :] = temp
        ctp_spd.append([(0, i, 0), temp])

    # Instantiate a GWE model
    gwe = flopy.mf6.ModflowGwe(sim, modelname=gwename)

    # Instantiating solver for GWT
    imsgwe = flopy.mf6.ModflowIms(
        sim,
        print_option="ALL",
        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=f"{gwename}.ims",
    )
    sim.register_ims_package(imsgwe, [gwename])

    # Instantiating DIS for GWE
    flopy.mf6.ModflowGwedis(
        gwe,
        length_units=length_units,
        nlay=nlay,
        nrow=nrow,
        ncol=ncol,
        delr=delr,
        delc=delc,
        top=top,
        botm=botm,
        idomain=1,
        pname="DIS",
        filename=f"{gwename}.dis",
    )

    # Instantiate Mobile Storage and Transfer package
    flopy.mf6.ModflowGweest(
        gwe,
        save_flows=True,
        porosity=prsity,
        heat_capacity_water=cpw,
        density_water=rhow,
        latent_heat_vaporization=lhv,
        heat_capacity_solid=cps,
        density_solid=rhos,
        pname="EST",
        filename=f"{gwename}.est",
    )

    # Instantiate Energy Transport Initial Conditions package
    flopy.mf6.ModflowGweic(gwe, strt=ini_temp)

    # Instantiate Advection package
    flopy.mf6.ModflowGweadv(gwe, scheme=scheme)

    # Instantiate Constant Temperature package
    flopy.mf6.ModflowGwectp(
        gwe,
        maxbound=len(ctp_spd),
        stress_period_data=ctp_spd,
        pname="CTP",
        filename=f"{gwename}.ctp",
    )

    # Instantiate Dispersion package (also handles conduction)
    flopy.mf6.ModflowGwecnd(
        gwe,
        xt3d_off=True,
        ktw=ktw,
        kts=kts,
        pname="CND",
        filename=f"{gwename}.cnd",
    )

    # Instantiating MODFLOW 6 transport source-sink mixing package
    # [b/c at least one boundary back is active (SFR), ssm must be on]
    sourcerecarray = [
        ("CHD-l", "AUX", "TEMPERATURE"),
        ("WEL-1", "AUX", "TEMPERATURE"),
    ]
    flopy.mf6.ModflowGwessm(
        gwe, sources=sourcerecarray, pname="SSM", filename=f"{gwename}.ssm"
    )

    # Instantiate Output Control package for transport
    flopy.mf6.ModflowGweoc(
        gwe,
        temperature_filerecord=f"{gwename}.ucn",
        saverecord=[("TEMPERATURE", "ALL")],
        temperatureprintrecord=[("COLUMNS", 3, "WIDTH", 20, "DIGITS", 8, "GENERAL")],
        printrecord=[("TEMPERATURE", "ALL"), ("BUDGET", "ALL")],
        filename=f"{gwename}.oc",
    )

    return sim
[7]:
def build_models(sim_name, silent=False, temp_upper=4.0, temp_lower=4.0):
    # Set model names to have 2 of each type of model (GWF & GWE) in a
    # single simulation
    gwfname1 = sim_name.replace("gwe", "gwf") + "-01"
    gwfname2 = sim_name.replace("gwe", "gwf") + "-02"

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

    # Instantiating MODFLOW 6 time discretization
    tdis_rc = []
    for i in range(nper):
        tdis_rc.append((perlen[i], nstp[i], tsmult[i]))
    flopy.mf6.ModflowTdis(sim, nper=nper, perioddata=tdis_rc, time_units=time_units)

    # Add two gwf models to the simulation, one with VSC and one without
    mod_list = [(gwfname1, False), (gwfname2, True)]
    for gwfname, vsc_status in mod_list:
        sim = add_gwf_model(sim, gwfname, vsc_status)

    # Add accompanying solute transport models for each flow model
    # (only the second gwf model will have an associated gwe model)
    for i, (gwfname, vsc_status) in enumerate(mod_list):
        gwtname = sim_name.replace("gwe", "gwt") + "-" + str(i + 1).zfill(2)
        sim = add_gwt_model(sim, gwtname)

        # Setup flow-transport exchange mechanism
        flopy.mf6.ModflowGwfgwt(
            sim,
            exgtype="GWF6-GWT6",
            exgmnamea=gwfname,
            exgmnameb=gwtname,
            filename=f"{gwtname}.gwfgwt",
        )

        if i > 0:
            gwename = sim_name + "-" + str(i + 1).zfill(2)
            sim = add_gwe_model(
                sim, gwename, temp_upper=temp_upper, temp_lower=temp_lower
            )

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

    return sim


def write_models(sim, silent=True):
    print("Writing input for 2 GWF, 2 GWT, and 1 GWE models...")
    success = False
    if isinstance(sim, MFSimulation):
        sim.write_simulation(silent=silent)
    else:
        sim.write_input()


@timed
def run_simulation(sim, silent=True):
    print("running viscosity demonstration 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)

Plotting results

Define functions to plot model results.

[8]:
# Figure properties
figure_size_1 = (5.5, 5.667)
figure_size_2 = (6.15, 2.833)


def plot_results(sim, idx, temp_upper=4.0, temp_lower=4.0):
    inline_spacing = 25.0
    suffix = "-" + str(round(temp_lower - temp_upper)) + "C"
    ticks = [0.01, 0.1, 1, 10]
    if idx == 0:
        ticks_over = [0.01, 0.1, 1.0]
        ticks_under = [0.01, 0.1, 0.25]
    elif idx == 1:
        ticks_over = [0.01, 0.1, 1.0]
        ticks_under = [0.01, 0.1, 1.0, 8.0]

    gwtname1 = sim.name.replace("gwe", "gwt") + "-01"
    gwtname2 = sim.name.replace("gwe", "gwt") + "-02"

    # Get the MF6 concentration output
    gwt1 = sim.get_model(gwtname1)
    gwt2 = sim.get_model(gwtname2)

    conc_gwt_novsc = gwt1.output.concentration().get_alldata()
    conc_gwt_wvsc = gwt2.output.concentration().get_alldata()

    # Work up plot arrays
    thresh = 0.0009
    conc_diff = conc_gwt_novsc[-1, 0] - conc_gwt_wvsc[-1, 0]
    underpred_ma = ma.masked_where(conc_diff < thresh, conc_diff)
    overpred_ma = ma.masked_where(conc_diff > -1 * thresh, -1 * conc_diff)

    underpred_vmin = 0.001
    underpred_vmax = underpred_ma.max()
    overpred_vmin = 0.001
    overpred_vmax = overpred_ma.max()

    cmap = plt.get_cmap("jet")
    over_cmap = truncate_colormap(cmap, 0.6, 0.9)
    under_cmap = truncate_colormap(cmap, 0.4, 0.2)

    # Create figure for scenario
    sim_name = sim.name
    fontsize = 8
    plt.rcParams["lines.dashed_pattern"] = [5.0, 5.0]

    # 2 part plot with and without viscosity
    # Create figure for simulation
    fig, axes = plt.subplots(
        ncols=1,
        nrows=2,
        sharex=True,
        figsize=figure_size_1,
        constrained_layout=False,
        dpi=600,
    )

    for idx, ax in enumerate(axes):
        mm = flopy.plot.PlotMapView(model=gwt1, ax=ax)
        mm.plot_grid(color=".5", alpha=0.2, linewidth=0.35)
        if idx == 0:
            cb_novsc = mm.plot_array(
                conc_gwt_novsc[-1, 0],
                alpha=0.5,
                cmap="jet",
                norm=LogNorm(vmin=1e-3, vmax=10),
            )
            plt.colorbar(cb_novsc, label="Concentration, $mg/L$", shrink=0.8)
        if idx == 1:
            cb_wvsc = mm.plot_array(
                conc_gwt_wvsc[-1, 0],
                alpha=0.5,
                cmap="jet",
                norm=LogNorm(vmin=1e-3, vmax=10),
            )  # vmin=1e-4, vmax=10, norm=LogNorm()
            plt.colorbar(cb_wvsc, label="Concentration, $mg/L$", shrink=0.8)

        ax.set_aspect("equal")
        ax.set_ylabel("Y, m")
        plt.xlabel("X, m")
        plt.tight_layout()
        # plt.ylabel("Y, m")

    if plot_show:
        plt.show()
    if plot_save:
        fpth = figs_path / f"{sim_name}-conc-2plts{suffix}.png"
        fig.savefig(fpth)

    # Make a difference plot, as in: actually make a difference
    fig, ax = plt.subplots(
        ncols=1, nrows=1, figsize=figure_size_2, constrained_layout=False, dpi=600
    )

    mm = flopy.plot.PlotMapView(model=gwt1, ax=ax)
    mm.plot_grid(color=".5", alpha=0.2, linewidth=0.35)
    cb1 = mm.plot_array(
        overpred_ma,
        alpha=0.5,
        cmap=over_cmap,
        norm=LogNorm(vmin=overpred_vmin, vmax=overpred_vmax),
    )
    cs1 = mm.contour_array(overpred_ma, levels=ticks_over, colors="r", linestyles="--")
    plt.clabel(
        cs1, inline=1, inline_spacing=inline_spacing, fontsize=fontsize, colors="k"
    )
    cb2 = mm.plot_array(
        underpred_ma,
        alpha=0.5,
        cmap=under_cmap,
        norm=LogNorm(vmin=underpred_vmin, vmax=underpred_vmax),
    )
    cs2 = mm.contour_array(
        underpred_ma, levels=ticks_under, colors="b", linestyles="--"
    )
    ax.set_aspect("equal")
    ax.set_ylabel("Y, m")
    plt.xlabel("X, m")
    plt.tight_layout()

    plt.clabel(
        cs2, inline=1, inline_spacing=inline_spacing, fontsize=fontsize, colors="b"
    )
    plt.colorbar(cb1, ticks=ticks, label="Over Prediction, $mg/L$", shrink=0.8)
    plt.colorbar(cb2, ticks=ticks, label="Under Prediction, $mg/L$", shrink=0.8)

    if plot_show:
        plt.show()
    if plot_save:
        fpth = figs_path / f"{sim_name}-diff-02{suffix}.png"
        fig.savefig(fpth)

Running the example

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

[9]:
def scenario(idx, silent=True):
    key = list(parameters.keys())[idx]
    parameter_dict = parameters[key]

    sim = build_models(sim_name, **parameter_dict)
    if write:
        write_models(sim, silent=silent)
    if run:
        run_simulation(sim, silent=silent)
    if plot:
        plot_results(sim, idx, **parameter_dict)
[10]:
# Compares the solute plume with and without accounting for viscosity in a
# 30 deg C temperature gradient (4 deg C top, 34 deg C bottom)
scenario(0, silent=True)

# Compares the solute plume with and without accounting for viscosity in a
# 90 deg C temperature gradient (4 deg C top, 94 deg C bottom)
scenario(1, silent=True)
Writing input for 2 GWF, 2 GWT, and 1 GWE models...
running viscosity demonstration model...
run_simulation took 7863.68 ms
../_images/_notebooks_ex-gwe-vsc_14_2.png
../_images/_notebooks_ex-gwe-vsc_14_3.png
Writing input for 2 GWF, 2 GWT, and 1 GWE models...
running viscosity demonstration model...
run_simulation took 8108.10 ms
../_images/_notebooks_ex-gwe-vsc_14_6.png
../_images/_notebooks_ex-gwe-vsc_14_7.png