Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(GWE): Introduce Groundwater Energy Transport #1493

Merged
merged 46 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
bcbbef8
feat(GWE): Introduce Groundwater Energy Transport
emorway-usgs Dec 8, 2023
0ac2f48
fix typo in meson file
emorway-usgs Dec 9, 2023
80333a7
fix a formating issue that was popping up in an MST autotest
emorway-usgs Dec 18, 2023
641d238
some legacy line leftover from a botched rebase, possibly
emorway-usgs Dec 18, 2023
00a6e82
Need update initial autotest to conform to new autotest standards ado…
emorway-usgs Dec 18, 2023
059cd43
Start looking for post-rebase breakages
emorway-usgs Dec 20, 2023
0f185ac
Get gwfgwe and gwegwe exchanges up-to-date based on #1505
emorway-usgs Dec 20, 2023
7772953
Code that had been moved to set_active_status in FMI was still presen…
emorway-usgs Dec 21, 2023
18e4e6d
Forgot to remove unused variables after making changes in 4d76729
emorway-usgs Dec 21, 2023
6129d2c
Adding another autotest specific to GWE
emorway-usgs Dec 21, 2023
b24a919
Adding another autotest after getting it #1464 compliant
emorway-usgs Dec 21, 2023
b528234
Compliantizing another new autotest with PR #1464
emorway-usgs Dec 21, 2023
6511c21
Fixes in response to https://github.com/MODFLOW-USGS/modflow6/pull/14…
emorway-usgs Dec 22, 2023
cef5b83
Fix in response to https://github.com/MODFLOW-USGS/modflow6/pull/1493…
emorway-usgs Dec 22, 2023
a8a1df9
Rerunning black in response to https://github.com/MODFLOW-USGS/modflo…
emorway-usgs Dec 22, 2023
4f60e29
Fix in response to https://github.com/MODFLOW-USGS/modflow6/pull/1493…
emorway-usgs Dec 22, 2023
5c774d3
Made changes to dfn files in response to https://github.com/MODFLOW-U…
emorway-usgs Dec 22, 2023
e23babc
Fix in response to https://github.com/MODFLOW-USGS/modflow6/pull/1493…
emorway-usgs Dec 22, 2023
6a1c29c
remove unnecessary line of script
emorway-usgs Dec 29, 2023
ca9b549
Add missing lines to ConnectionBuilder.f90 related to GWE
emorway-usgs Dec 29, 2023
83fc63e
Add a GWE vs GWT comparison autotest
emorway-usgs Jan 12, 2024
b2886d7
GWE-GWE exchanges now working. Other clean-up for code uniformity
emorway-usgs Jan 15, 2024
716fab6
Rebrand constant temperature package acronym to CTP
emorway-usgs Jan 17, 2024
a699f82
Missed an import renaming update
emorway-usgs Jan 17, 2024
a0ee6e0
Forgot to remove a now obsolete file due to renaming.
emorway-usgs Jan 18, 2024
b45754b
Rebrand energy storage and transfer package acronym to EST
emorway-usgs Jan 18, 2024
ab69972
Forgot to remove a now obsolete file due to renaming (again)
emorway-usgs Jan 18, 2024
61a6b15
Rebrand gwe dispersion package acronym to CND (conduction) since that…
emorway-usgs Jan 18, 2024
400a4d3
Remove gwe-related code from generalized transport code (tsp1.f90 & t…
emorway-usgs Jan 19, 2024
2135ed5
add single-cell test for energy source loading (ESL) package
emorway-usgs Jan 26, 2024
5f7f0a4
Adding energy source loading (ESL) package
emorway-usgs Jan 26, 2024
d0c0056
remove unused variable
emorway-usgs Jan 26, 2024
cf51996
fprettify
emorway-usgs Jan 26, 2024
b981a4f
Add another ESL autotest
emorway-usgs Jan 29, 2024
0612af8
Adding another autotest that compares gwe to three different analytic…
emorway-usgs Jan 30, 2024
2ee0a1b
Bringing over Stallman autotest from previous GWE PR (#1237)
emorway-usgs Jan 31, 2024
e8805c0
Adding streamflow energy transport (SFE) package
emorway-usgs Feb 7, 2024
3091a55
Add autotest for SFE
emorway-usgs Feb 8, 2024
c52dc14
Adding lake energy transport (LKE) package. Includes new autotest
emorway-usgs Feb 8, 2024
f2b3310
forgot meson update
emorway-usgs Feb 8, 2024
9eebdf5
Adding multi-aquifer well energy transport (MWE) package. Includes ne…
emorway-usgs Feb 8, 2024
eb57ea5
Adding unsaturated-zone energy transport (UZE) package. Includes 2 ne…
emorway-usgs Feb 9, 2024
34125e7
Attempting to reapply a failing autotest. Unable to discern why it is…
emorway-usgs Feb 9, 2024
1e0d617
removing troublesome autotest. Downloaded contents from failed run o…
emorway-usgs Feb 9, 2024
fd6d84c
Removing a file that shouldn't have been added (snuck in among other …
emorway-usgs Feb 9, 2024
fa190fd
Update release notes
emorway-usgs Feb 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
495 changes: 495 additions & 0 deletions autotest/test_gwe_cnd.py

Large diffs are not rendered by default.

423 changes: 423 additions & 0 deletions autotest/test_gwe_drycell_cnd0.py

Large diffs are not rendered by default.

484 changes: 484 additions & 0 deletions autotest/test_gwe_drycell_cnd1.py

Large diffs are not rendered by default.

669 changes: 669 additions & 0 deletions autotest/test_gwe_drycell_cnd2.py

Large diffs are not rendered by default.

369 changes: 369 additions & 0 deletions autotest/test_gwe_esl01.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,369 @@
"""
A "bathtub" test problem for GWE - bathtub meaning a single cell model
(and actually, the bathtub is dry in this example)

Test the energy source loading package by warming a single cell with a known
amount of energy input.

Model configuration

~: Represents energy source loading

+---------+
| |
| ~ |
| |
+---------+

"""

# Imports

import os
import numpy as np
import pytest
import flopy

from framework import TestFramework


# Base simulation and model name and workspace

scheme = "UPSTREAM"
# scheme = "TVD"

cases = [
"warmup", # 1-cell "bathtub" model with easily calculate-able answers
]

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

# Parameterization

nrow = ncol = nlay = 1
top = 1.0
botm = [0.0]
delr = 1.0 # Column width ($m$)
delc = 1.0 # Row width ($m$)
k11 = 1.0 # Horizontal hydraulic conductivity ($m/d$)
ss = 1e-6 # Specific storage
sy = 0.10 # Specific Yield
prsity = sy # Porosity
nper = 4 # Number of periods
perlen = [1, 1, 1, 1] # Simulation time ($days$)
nstp = [1, 1, 1, 1] # 10 day transient time steps
steady = {0: False}
transient = {0: True}
strthd = 0.0

# Set some static model parameter values

k33 = k11 # Vertical hydraulic conductivity ($m/d$)
idomain = 1 # All cells included in the simulation
iconvert = 1 # All cells are convertible

icelltype = 1 # Cell conversion type (>1: unconfined)

# Set some static transport related model parameter values
strt_temp1 = 0.0
dispersivity = 0.0 # dispersion (remember, 1D model)

# GWE related parameters
rhow = 1000.0
cpw = 4183.0
lhv = 2454.0
cps = 760.0
rhos = 1500.0

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

# Set up temporal data used by TDIS file
tdis_rc = []
for i in np.arange(nper):
tdis_rc.append((perlen[i], nstp[i], ttsmult))

Joules_added_for_1degC_rise = (
delr * delc * (top - botm[0]) * (1 - prsity) * cps * rhos
)

# ### Create MODFLOW 6 GWE
#
# No GWF, only Heat conduction simulated


def build_models(idx, test):
# Base MF6 GWF model type
ws = test.workspace
name = cases[idx]

print("Building MF6 model...()".format(name))

# generate names for each model
gwfname = "gwf-" + name
gwename = "gwe-" + name

sim = flopy.mf6.MFSimulation(
sim_name=name, sim_ws=ws, exe_name="mf6", version="mf6"
)

# Instantiating MODFLOW 6 time discretization
flopy.mf6.ModflowTdis(
sim, nper=nper, perioddata=tdis_rc, time_units=time_units
)

# Instantiating MODFLOW 6 groundwater flow model
gwf = flopy.mf6.ModflowGwf(
sim,
modelname=gwfname,
save_flows=True,
model_nam_file="{}.nam".format(gwfname),
)

# 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="{}.ims".format(gwfname),
)
sim.register_ims_package(imsgwf, [gwfname])

# 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=1,
pname="DIS-1",
filename="{}.dis".format(gwfname),
)

# Instantiating MODFLOW 6 storage package
flopy.mf6.ModflowGwfsto(
gwf,
ss=ss,
sy=sy,
iconvert=iconvert,
steady_state=steady,
transient=transient,
pname="STO",
filename="{}.sto".format(gwfname),
)

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

# Instantiating MODFLOW 6 initial conditions package for flow model
flopy.mf6.ModflowGwfic(
gwf,
strt=strthd,
pname="IC-HD",
filename="{}.ic".format(gwfname),
)

# Instantiating MODFLOW 6 output control package for flow model
flopy.mf6.ModflowGwfoc(
gwf,
pname="OC-1",
head_filerecord="{}.hds".format(gwfname),
budget_filerecord="{}.cbc".format(gwfname),
headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
)

# ----------------------------------
# Instantiating MODFLOW 6 GWE model
# ----------------------------------
gwe = flopy.mf6.ModflowGwe(
sim, modelname=gwename, model_nam_file="{}.nam".format(gwename)
)
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=1,
pname="DIS-GWE",
filename="{}.dis".format(gwename),
)

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

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

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

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

# Instantiate MODFLOW 6 heat transport output control package
flopy.mf6.ModflowGweoc(
gwe,
pname="OC-1",
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")],
)

# Instantiate energy source loading (ESL) package
# Energy is added such that the temperature change in the cell will be
# +1.0, +2.0, -1.0, and 0.0 degrees Celcius from stress period to stress
# period
esl_spd = {
0: [
[(0, 0, 0), Joules_added_for_1degC_rise],
],
1: [[(0, 0, 0), 2 * Joules_added_for_1degC_rise]],
2: [[(0, 0, 0), -1 * Joules_added_for_1degC_rise]],
3: [],
}
flopy.mf6.ModflowGweesl(
gwe,
stress_period_data=esl_spd,
pname="ESL-1",
filename="{}.esl".format(gwename),
)

# Instantiating MODFLOW 6 flow-transport exchange mechanism
flopy.mf6.ModflowGwfgwe(
sim,
exgtype="GWF6-GWE6",
exgmnamea=gwfname,
exgmnameb=gwename,
pname="GWFGWE1",
filename="{}.gwfgwe1".format(gwename),
)

return sim, None


def check_output(idx, test):
print("evaluating results...")

# read transport results from GWE model
name = cases[idx]
gwename = "gwe-" + name

fpth = os.path.join(test.workspace, f"{gwename}.ucn")

try:
# load temperatures
tobj = flopy.utils.HeadFile(
fpth, precision="double", text="TEMPERATURE"
)
temps = tobj.get_alldata()
except:
assert False, f'could not load temperature data from "{fpth}"'

# Energy source loading was carefully chosen to result in a +1,
# +2 (for an absolute value of 3 deg C), -1, and 0.0 degree C
# change between stress periods.
known_ans = [1.0, 3.0, 2.0, 2.0]
msg0 = (
"Grid cell temperatures do not reflect the expected difference "
"in stress period "
)
for index in np.arange(4):
assert np.isclose(temps[index, 0, 0, 0], known_ans[index]), msg0 + str(
index
)


# - No need to change any code below
@pytest.mark.parametrize(
"idx, name",
list(enumerate(cases)),
)
def test_mf6model(idx, name, function_tmpdir, targets):
test = TestFramework(
name=name,
workspace=function_tmpdir,
targets=targets,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
)
test.run()
Loading
Loading