"""
mfhfb module. Contains the ModflowHfb class. Note that the user can access
the ModflowHfb class as `flopy.modflow.ModflowHfb`.
Additional information for this MODFLOW package can be found at the `Online
MODFLOW Guide
<https://water.usgs.gov/ogw/modflow/MODFLOW-2005-Guide/hfb6.html>`_.
"""
import numpy as np
from numpy.lib.recfunctions import stack_arrays
from ..pakbase import Package
from ..utils.flopy_io import line_parse
from ..utils.recarray_utils import create_empty_recarray
from .mfparbc import ModflowParBc as mfparbc
[docs]class ModflowHfb(Package):
"""
MODFLOW HFB6 - Horizontal Flow Barrier Package
Parameters
----------
model : model object
The model object (of type: class:`flopy.modflow.mf.Modflow` or
`flopy.mfusg.MfUsg`) to which this package will be added.
nphfb : int
Number of horizontal-flow barrier parameters. Note that for an HFB
parameter to have an effect in the simulation, it must be defined
and made active using NACTHFB to have an effect in the simulation
(default is 0).
mxfb : int
Maximum number of horizontal-flow barrier barriers that will be
defined using parameters (default is 0).
nhfbnp: int
Number of horizontal-flow barriers not defined by parameters. This
is calculated automatically by FloPy based on the information in
layer_row_column_data (default is 0).
hfb_data : list of records
In its most general form, this is a list of horizontal-flow
barrier records. A barrier is conceptualized as being located on
the boundary between two adjacent finite difference cells in the
same layer. The innermost list is the layer, row1, column1, row2,
column2, and hydrologic characteristics for a single hfb between
the cells. The hydraulic characteristic is the barrier hydraulic
conductivity divided by the width of the horizontal-flow barrier.
(default is None).
For a structured model, this gives the form of::
hfb_data = [
[lay, row1, col1, row2, col2, hydchr],
[lay, row1, col1, row2, col2, hydchr],
[lay, row1, col1, row2, col2, hydchr],
].
Or for unstructured (mfusg) models::
hfb_data = [
[node1, node2, hydchr],
[node1, node2, hydchr],
[node1, node2, hydchr],
].
nacthfb : int
The number of active horizontal-flow barrier parameters
(default is 0).
no_print : boolean
When True or 1, a list of horizontal flow barriers will not be
written to the Listing File (default is False)
options : list of strings
Package options (default is None).
extension : string
Filename extension (default is 'hfb').
unitnumber : int
File unit number (default is None).
filenames : str or list of str
Filenames to use for the package. If filenames=None the package name
will be created using the model name and package extension. If a
single string is passed the package will be set to the string.
Default is None.
Attributes
----------
Methods
-------
See Also
--------
Notes
-----
Parameters are supported in Flopy only when reading in existing models.
Parameter values are converted to native values in Flopy and the
connection to "parameters" is thus nonexistent.
Examples
--------
>>> import flopy
>>> m = flopy.modflow.Modflow()
>>> hfb_data = [[0, 10, 4, 10, 5, 0.01],[1, 10, 4, 10, 5, 0.01]]
>>> hfb = flopy.modflow.ModflowHfb(m, hfb_data=hfb_data)
"""
def __init__(
self,
model,
nphfb=0,
mxfb=0,
nhfbnp=0,
hfb_data=None,
nacthfb=0,
no_print=False,
options=None,
extension="hfb",
unitnumber=None,
filenames=None,
):
# set default unit number of one is not specified
if unitnumber is None:
unitnumber = ModflowHfb._defaultunit()
# call base package constructor
super().__init__(
model,
extension=extension,
name=self._ftype(),
unit_number=unitnumber,
filenames=self._prepare_filenames(filenames),
)
self._generate_heading()
self.url = "hfb6.html"
self.nphfb = nphfb
self.mxfb = mxfb
self.nacthfb = nacthfb
self.no_print = no_print
self.np = 0
if options is None:
options = []
if self.no_print:
options.append("NOPRINT")
self.options = options
aux_names = []
it = 0
while it < len(options):
if "aux" in options[it].lower():
aux_names.append(options[it + 1].lower())
it += 1
it += 1
if hfb_data is None:
raise Exception("Failed to specify hfb_data.")
self.nhfbnp = len(hfb_data)
self.hfb_data = ModflowHfb.get_empty(
self.nhfbnp, structured=self.parent.structured
)
for ibnd, t in enumerate(hfb_data):
self.hfb_data[ibnd] = tuple(t)
self.parent.add_package(self)
def _ncells(self):
"""Maximum number of cell pairs that have horizontal flow barriers
(developed for MT3DMS SSM package).
Returns
-------
ncells: int
maximum number of hfb cells
"""
return self.nhfbnp
[docs] def write_file(self):
"""
Write the package file.
Returns
-------
None
"""
structured = self.parent.structured
f_hfb = open(self.fn_path, "w")
f_hfb.write(f"{self.heading}\n")
f_hfb.write(f"{self.nphfb:10d}{self.mxfb:10d}{self.nhfbnp:10d}")
for option in self.options:
f_hfb.write(f" {option}")
f_hfb.write("\n")
for a in self.hfb_data:
if structured:
f_hfb.write(
"{:10d}{:10d}{:10d}{:10d}{:10d}{:13.6g}\n".format(
a[0] + 1, a[1] + 1, a[2] + 1, a[3] + 1, a[4] + 1, a[5]
)
)
else:
f_hfb.write(
"{:10d}{:10d}{:13.6g}\n".format(a[0] + 1, a[1] + 1, a[2])
)
f_hfb.write(f"{self.nacthfb:10d}")
f_hfb.close()
[docs] @staticmethod
def get_empty(ncells=0, aux_names=None, structured=True):
"""
Get an empty recarray that corresponds to hfb dtype and has
been extended to include aux variables and associated
aux names.
"""
dtype = ModflowHfb.get_default_dtype(structured=structured)
if aux_names is not None:
dtype = Package.add_to_dtype(dtype, aux_names, np.float32)
return create_empty_recarray(ncells, dtype, default_value=-1.0e10)
[docs] @staticmethod
def get_default_dtype(structured=True):
"""
Get the default dtype for hfb data
"""
if structured:
dtype = np.dtype(
[
("k", int),
("irow1", int),
("icol1", int),
("irow2", int),
("icol2", int),
("hydchr", np.float32),
]
)
else:
dtype = np.dtype(
[
("node1", int),
("node2", int),
("hydchr", np.float32),
]
)
return dtype
@staticmethod
def _get_sfac_columns():
return ["hydchr"]
[docs] @classmethod
def load(cls, f, model, ext_unit_dict=None):
"""
Load an existing package.
Parameters
----------
f : filename or file handle
File to load.
model : model object
The model object (of type: class:`flopy.modflow.mf.Modflow`)
to which this package will be added.
ext_unit_dict : dictionary, optional
If the arrays in the file are specified using EXTERNAL,
or older style array control records, then `f` should be a file
handle. In this case ext_unit_dict is required, which can be
constructed using the function
:class:`flopy.utils.mfreadnam.parsenamefile`.
Returns
-------
hfb : ModflowHfb object
ModflowHfb object (of type :class:`flopy.modflow.mfbas.ModflowHfb`)
Examples
--------
>>> import flopy
>>> m = flopy.modflow.Modflow()
>>> hfb = flopy.modflow.ModflowHfb.load('test.hfb', m)
"""
if model.verbose:
print("loading hfb6 package file...")
structured = model.structured
openfile = not hasattr(f, "read")
if openfile:
filename = f
f = open(filename, "r")
# dataset 0 -- header
while True:
line = f.readline()
if line[0] != "#":
break
# dataset 1
t = line_parse(line)
nphfb = int(t[0])
mxfb = int(t[1])
nhfbnp = int(t[2])
# check for no-print suppressor
options = []
aux_names = []
if len(t) > 2:
it = 2
while it < len(t):
toption = t[it]
# print it, t[it]
if toption.lower() == "noprint":
options.append(toption)
elif "aux" in toption.lower():
options.append(" ".join(t[it : it + 2]))
aux_names.append(t[it + 1].lower())
it += 1
it += 1
# data set 2 and 3
if nphfb > 0:
dt = ModflowHfb.get_empty(1, structured=structured).dtype
pak_parms = mfparbc.load(
f,
nphfb,
dt,
model,
ext_unit_dict=ext_unit_dict,
verbose=model.verbose,
)
# data set 4
bnd_output = None
if nhfbnp > 0:
specified = ModflowHfb.get_empty(nhfbnp, structured=structured)
for ibnd in range(nhfbnp):
line = f.readline()
if "open/close" in line.lower():
raise NotImplementedError(
"load() method does not support 'open/close'"
)
t = line.strip().split()
specified[ibnd] = tuple(t[: len(specified.dtype.names)])
# convert indices to zero-based
if structured:
specified["k"] -= 1
specified["irow1"] -= 1
specified["icol1"] -= 1
specified["irow2"] -= 1
specified["icol2"] -= 1
else:
specified["node1"] -= 1
specified["node2"] -= 1
bnd_output = np.recarray.copy(specified)
if nphfb > 0:
partype = ["hydchr"]
line = f.readline()
t = line.strip().split()
nacthfb = int(t[0])
for iparm in range(nacthfb):
line = f.readline()
t = line.strip().split()
pname = t[0].lower()
iname = "static"
par_dict, current_dict = pak_parms.get(pname)
data_dict = current_dict[iname]
par_current = ModflowHfb.get_empty(
par_dict["nlst"], structured=structured
)
#
if model.mfpar.pval is None:
parval = float(par_dict["parval"])
else:
try:
parval = float(model.mfpar.pval.pval_dict[pname])
except:
parval = float(par_dict["parval"])
# fill current parameter data (par_current)
for ibnd, t in enumerate(data_dict):
t = tuple(t)
par_current[ibnd] = tuple(
t[: len(par_current.dtype.names)]
)
# convert indices to zero-based
if structured:
par_current["k"] -= 1
par_current["irow1"] -= 1
par_current["icol1"] -= 1
par_current["irow2"] -= 1
par_current["icol2"] -= 1
else:
par_current["node1"] -= 1
par_current["node2"] -= 1
for ptype in partype:
par_current[ptype] *= parval
if bnd_output is None:
bnd_output = np.recarray.copy(par_current)
else:
bnd_output = stack_arrays(
(bnd_output, par_current),
asrecarray=True,
usemask=False,
)
if openfile:
f.close()
# set package unit number
unitnumber = None
filenames = [None]
if ext_unit_dict is not None:
unitnumber, filenames[0] = model.get_ext_dict_attr(
ext_unit_dict, filetype=ModflowHfb._ftype()
)
return cls(
model,
nphfb=0,
mxfb=0,
nhfbnp=len(bnd_output),
hfb_data=bnd_output,
nacthfb=0,
options=options,
unitnumber=unitnumber,
filenames=filenames,
)
@staticmethod
def _ftype():
return "HFB6"
@staticmethod
def _defaultunit():
return 29