"""
mflgr module.
"""
import os
from ..mbase import BaseModel
from ..modflow import Modflow
[docs]class LgrChild:
def __init__(
self,
ishflg=1,
ibflg=59,
iucbhsv=0,
iucbfsv=0,
mxlgriter=20,
ioutlgr=1,
relaxh=0.4,
relaxf=0.4,
hcloselgr=5e-3,
fcloselgr=5e-2,
nplbeg=0,
nprbeg=0,
npcbeg=0,
nplend=0,
nprend=1,
npcend=1,
ncpp=2,
ncppl=1,
):
self.ishflg = ishflg
self.ibflg = ibflg
self.iucbhsv = iucbhsv
self.iucbfsv = iucbfsv
self.mxlgriter = mxlgriter
self.ioutlgr = ioutlgr
self.relaxh = relaxh
self.relaxf = relaxf
self.hcloselgr = hcloselgr
self.fcloselgr = fcloselgr
self.nplbeg = nplbeg
self.nprbeg = nprbeg
self.npcbeg = npcbeg
self.nplend = nplend
self.nprend = nprend
self.npcend = npcend
self.ncpp = ncpp
if isinstance(ncppl, int):
nlaychild = nplend - nplbeg + 1
self.ncppl = nlaychild * [ncppl]
else:
self.ncppl = ncppl
[docs]class ModflowLgr(BaseModel):
"""
MODFLOW-LGR Model Class.
Parameters
----------
modelname : str, default "modflowlgrtest".
Name of model. This string will be used to name the MODFLOW input
that are created with write_model.
namefile_ext : str, default "lgr"
Extension for the namefile.
version : str, default "mflgr".
Version of MODFLOW-LGR to use.
exe_name : str, default "mflgr.exe"
The name of the executable to use.
iupbhsv : int, default 0
Unit number with boundary heads.
iupbfsv : int, default 0
Unit number with boundary fluxes.
parent : Modflow, optional
Instance of a Modflow object.
children : list, optional
List of instances of 1 or more Modflow objects.
children_data : list, optional
List of LgrChild objects.
model_ws : str, default "."
Model workspace. Directory name to create model data sets.
Default is the present working directory.
external_path : str, optional
Location for external files.
verbose : bool, default False
Print additional information to the screen.
Attributes
----------
Methods
-------
See Also
--------
Notes
-----
Examples
--------
>>> import flopy
>>> lgr = flopy.modflowlgr.ModflowLgr(parent=parent, children=children,
... children_data=children_data)
"""
def __init__(
self,
modelname="modflowlgrtest",
namefile_ext="lgr",
version="mflgr",
exe_name="mflgr.exe",
iupbhsv=0,
iupbfsv=0,
parent=None,
children=None,
children_data=None,
model_ws=".",
external_path=None,
verbose=False,
**kwargs,
):
super().__init__(
modelname,
namefile_ext,
exe_name,
model_ws,
structured=True,
verbose=verbose,
**kwargs,
)
self.version_types = {"mflgr": "MODFLOW-LGR"}
self.set_version(version)
# external option stuff
self.array_free_format = True
self.array_format = "modflow"
self.iupbhsv = iupbhsv
self.iupbfsv = iupbfsv
self.parent = parent
if children is not None:
if not isinstance(children, list):
children = [children]
self.children_models = children
if children_data is not None:
if not isinstance(children_data, list):
children_data = [children_data]
self.children_data = children_data
# set the number of grids
self.children = 0
if children is not None:
self.children += len(children)
self.load_fail = False
# the starting external data unit number
self._next_ext_unit = 2000
# convert iupbhsv, iupbhsv, iucbhsv, and iucbfsv units from
# external_files to output_files
ibhsv = self.iupbhsv
ibfsv = self.iupbfsv
if ibhsv > 0:
self.parent.add_output_file(ibhsv, binflag=False)
if ibfsv > 0:
self.parent.add_output_file(ibfsv, binflag=False)
for child, child_data in zip(self.children_models, self.children_data):
ibhsv = child_data.iucbhsv
ibfsv = child_data.iucbfsv
if ibhsv > 0:
child.add_output_file(ibhsv, binflag=False)
if ibfsv > 0:
child.add_output_file(ibfsv, binflag=False)
if external_path is not None:
if os.path.exists(os.path.join(model_ws, external_path)):
print(f"Note: external_path {external_path} already exists")
else:
os.makedirs(os.path.join(model_ws, external_path))
self.external_path = external_path
return
def __repr__(self):
return f"MODFLOW-LGR model with {self.ngrids} grids"
@property
def ngrids(self):
"""Get the number of grids in the LGR model
Returns
-------
ngrid : int
number of grids (parent and children)
"""
try:
return 1 + self.children
except:
return None
def _padline(self, line, comment=None, line_len=79):
if len(line) < line_len:
fmt = "{:" + str(line_len) + "s}"
line = fmt.format(line)
if comment is not None:
line += f" # {comment}\n"
return line
def _get_path(self, bpth, pth, fpth=""):
lpth = os.path.abspath(bpth)
mpth = os.path.abspath(pth)
rpth = os.path.relpath(mpth, lpth)
if rpth == ".":
rpth = fpth
else:
rpth = os.path.join(rpth, fpth)
msg = (
"namefiles must be in the same directory as "
"the lgr control file\n"
)
msg += f"Control file path: {lpth}\n"
msg += f"Namefile path: {mpth}\n"
msg += f"Relative path: {rpth}\n"
raise ValueError(msg)
return rpth
[docs] def get_namefiles(self):
"""
Get the namefiles (with path) of the parent and children models
Returns
-------
namefiles : list
Examples
--------
>>> import flopy
>>> lgr = flopy.modflowlgr.ModflowLgr.load(f)
>>> namefiles = lgr.get_namefiles()
"""
pth = os.path.join(self.parent._model_ws, self.parent.namefile)
namefiles = [pth]
for child in self.children_models:
pth = os.path.join(child._model_ws, child.namefile)
namefiles.append(pth)
return namefiles
[docs] def write_name_file(self):
"""
Write the modflow-lgr control file.
"""
fn_path = os.path.join(self.model_ws, self.namefile)
f = open(fn_path, "w")
f.write(f"{self.heading}\n")
# dataset 1
line = self._padline("LGR", comment="data set 1")
f.write(line)
# dataset 2
line = str(self.ngrids)
line = self._padline(line, comment="data set 2 - ngridsS")
f.write(line)
# dataset 3
pth = self._get_path(
self._model_ws, self.parent._model_ws, fpth=self.parent.namefile
)
line = self._padline(pth, comment="data set 3 - parent namefile")
f.write(line)
# dataset 4
line = self._padline("PARENTONLY", comment="data set 4 - gridstatus")
f.write(line)
# dataset 5
line = f"{self.iupbhsv} {self.iupbfsv}"
line = self._padline(line, comment="data set 5 - iupbhsv, iupbfsv")
f.write(line)
# dataset 6 to 15 for each child
for idx, (child, child_data) in enumerate(
zip(self.children_models, self.children_data)
):
# dataset 6
pth = self._get_path(
self._model_ws, child._model_ws, fpth=child.namefile
)
comment = f"data set 6 - child {idx + 1} namefile"
line = self._padline(pth, comment=comment)
f.write(line)
# dataset 7
comment = f"data set 7 - child {idx + 1} gridstatus"
line = self._padline("CHILDONLY", comment=comment)
f.write(line)
# dataset 8
line = "{} {} {} {}".format(
child_data.ishflg,
child_data.ibflg,
child_data.iucbhsv,
child_data.iucbfsv,
)
comment = (
f"data set 8 - child {idx + 1} ishflg, ibflg, iucbhsv, iucbfsv"
)
line = self._padline(line, comment=comment)
f.write(line)
# dataset 9
line = f"{child_data.mxlgriter} {child_data.ioutlgr}"
comment = f"data set 9 - child {idx + 1} mxlgriter, ioutlgr"
line = self._padline(line, comment=comment)
f.write(line)
# dataset 10
line = f"{child_data.relaxh} {child_data.relaxf}"
comment = f"data set 10 - child {idx + 1} relaxh, relaxf"
line = self._padline(line, comment=comment)
f.write(line)
# dataset 11
line = f"{child_data.hcloselgr} {child_data.fcloselgr}"
comment = f"data set 11 - child {idx + 1} hcloselgr, fcloselgr"
line = self._padline(line, comment=comment)
f.write(line)
# dataset 12
line = "{} {} {}".format(
child_data.nplbeg + 1,
child_data.nprbeg + 1,
child_data.npcbeg + 1,
)
comment = f"data set 12 - child {idx + 1} nplbeg, nprbeg, npcbeg"
line = self._padline(line, comment=comment)
f.write(line)
# dataset 13
line = "{} {} {}".format(
child_data.nplend + 1,
child_data.nprend + 1,
child_data.npcend + 1,
)
comment = f"data set 13 - child {idx + 1} nplend, nprend, npcend"
line = self._padline(line, comment=comment)
f.write(line)
# dataset 14
line = str(child_data.ncpp)
comment = f"data set 14 - child {idx + 1} ncpp"
line = self._padline(line, comment=comment)
f.write(line)
# dataset 15
line = ""
for ndx in child_data.ncppl:
line += f"{ndx} "
comment = f"data set 15 - child {idx + 1} ncppl"
line = self._padline(line, comment=comment)
f.write(line)
# close the lgr control file
f.close()
[docs] def change_model_ws(self, new_pth=None, reset_external=False):
"""
Change the model work space.
Parameters
----------
new_pth : str
Location of new model workspace. If this path does not exist,
it will be created. (default is None, which will be assigned to
the present working directory).
Returns
-------
val : list of strings
Can be used to see what packages are in the model, and can then
be used with get_package to pull out individual packages.
"""
if new_pth is None:
new_pth = os.getcwd()
if not os.path.exists(new_pth):
try:
print(f"\ncreating model workspace...\n {new_pth}")
os.makedirs(new_pth)
except:
not_valid = new_pth
new_pth = os.getcwd()
print(
"\n{} not valid, workspace-folder was changed to {}"
"\n".format(not_valid, new_pth)
)
# --reset the model workspace
old_pth = self._model_ws
self._model_ws = new_pth
if self.verbose:
print(f"\nchanging model workspace...\n {new_pth}")
# reset model_ws for the parent
lpth = os.path.abspath(old_pth)
mpth = os.path.abspath(self.parent._model_ws)
rpth = os.path.relpath(mpth, lpth)
if rpth == ".":
npth = new_pth
else:
npth = os.path.join(new_pth, rpth)
self.parent.change_model_ws(
new_pth=npth, reset_external=reset_external
)
# reset model_ws for the children
for child in self.children_models:
lpth = os.path.abspath(old_pth)
mpth = os.path.abspath(child._model_ws)
rpth = os.path.relpath(mpth, lpth)
if rpth == ".":
npth = new_pth
else:
npth = os.path.join(new_pth, rpth)
child.change_model_ws(new_pth=npth, reset_external=reset_external)
[docs] @classmethod
def load(
cls,
f,
version="mflgr",
exe_name="mflgr.exe",
verbose=False,
model_ws=".",
load_only=None,
forgive=False,
check=True,
):
"""
Load an existing model.
Parameters
----------
f : str or file handle
Path to MODFLOW-LGR name file to load.
version : str, default "mflgr".
Version of MODFLOW-LGR to use.
exe_name : str, default "mflgr.exe"
The name of the executable to use.
verbose : bool, default False
Print additional information to the screen.
model_ws : str, default "."
Model workspace. Directory name to create model data sets.
Default is the present working directory.
load_only : list of str, optional
Packages to load (e.g. ["bas6", "lpf"]). Default None
means that all packages will be loaded.
forgive : bool, default False
Option to raise exceptions on package load failure, which can be
useful for debugging.
check : bool, default True
Check model input for common errors.
Returns
-------
flopy.modflowlgr.mflgr.ModflowLgr
"""
# test if name file is passed with extension (i.e., is a valid file)
if os.path.isfile(os.path.join(model_ws, f)):
modelname = f.rpartition(".")[0]
else:
modelname = f
openfile = not hasattr(f, "read")
if openfile:
filename = os.path.join(model_ws, f)
f = open(filename, "r")
# dataset 0 -- header
header = ""
while True:
line = f.readline()
if line[0] != "#":
break
header += line.strip()
# dataset 1
ds1 = line.split()[0].lower()
msg = "LGR must be entered as the first item in dataset 1\n"
msg += f" {header}\n"
assert ds1 == "lgr", msg
# dataset 2
line = f.readline()
t = line.split()
ngrids = int(t[0])
nchildren = ngrids - 1
# dataset 3
line = f.readline()
t = line.split()
namefile = t[0]
pws = os.path.join(model_ws, os.path.dirname(namefile))
pn = os.path.basename(namefile)
# dataset 4
line = f.readline()
t = line.split()
gridstatus = t[0].lower()
msg = "GRIDSTATUS for the parent must be 'PARENTONLY'"
assert gridstatus == "parentonly", msg
# dataset 5
line = f.readline()
t = line.split()
try:
iupbhsv, iupbfsv = int(t[0]), int(t[1])
except:
msg = "could not read dataset 5 - IUPBHSV and IUPBFSV."
raise ValueError(msg)
# non-zero values for IUPBHSV and IUPBFSV in dataset 5 are not
# supported
if iupbhsv + iupbfsv > 0:
raise ValueError(
"nonzero values for IUPBHSV ({}) and IUPBFSV ({}) are not "
"supported.".format(iupbhsv, iupbfsv)
)
# load the parent model
parent = Modflow.load(
pn,
verbose=verbose,
model_ws=pws,
load_only=load_only,
forgive=forgive,
check=check,
)
children_data = []
children = []
for child in range(nchildren):
# dataset 6
line = f.readline()
t = line.split()
namefile = t[0]
cws = os.path.join(model_ws, os.path.dirname(namefile))
cn = os.path.basename(namefile)
# dataset 7
line = f.readline()
t = line.split()
gridstatus = t[0].lower()
msg = "GRIDSTATUS for the parent must be 'CHILDONLY'"
assert gridstatus == "childonly", msg
# dataset 8
line = f.readline()
t = line.split()
ishflg, ibflg, iucbhsv, iucbfsv = (
int(t[0]),
int(t[1]),
int(t[2]),
int(t[3]),
)
# dataset 9
line = f.readline()
t = line.split()
mxlgriter, ioutlgr = int(t[0]), int(t[1])
# dataset 10
line = f.readline()
t = line.split()
relaxh, relaxf = float(t[0]), float(t[1])
# dataset 11
line = f.readline()
t = line.split()
hcloselgr, fcloselgr = float(t[0]), float(t[1])
# dataset 12
line = f.readline()
t = line.split()
nplbeg, nprbeg, npcbeg = (
int(t[0]) - 1,
int(t[1]) - 1,
int(t[2]) - 1,
)
# dataset 13
line = f.readline()
t = line.split()
nplend, nprend, npcend = (
int(t[0]) - 1,
int(t[1]) - 1,
int(t[2]) - 1,
)
# dataset 14
line = f.readline()
t = line.split()
ncpp = int(t[0])
# dataset 15
line = f.readline()
t = line.split()
ncppl = []
for idx in range(nplend + 1 - nplbeg):
ncppl.append(int(t[idx]))
# build child data object
children_data.append(
LgrChild(
ishflg=ishflg,
ibflg=ibflg,
iucbhsv=iucbhsv,
iucbfsv=iucbfsv,
mxlgriter=mxlgriter,
ioutlgr=ioutlgr,
relaxh=relaxh,
relaxf=relaxf,
hcloselgr=hcloselgr,
fcloselgr=fcloselgr,
nplbeg=nplbeg,
nprbeg=nprbeg,
npcbeg=npcbeg,
nplend=nplend,
nprend=nprend,
npcend=npcend,
ncpp=ncpp,
ncppl=ncppl,
)
)
# load child model
children.append(
Modflow.load(
cn,
verbose=verbose,
model_ws=cws,
load_only=load_only,
forgive=forgive,
check=check,
)
)
if openfile:
f.close()
# return model object
return cls(
version=version,
exe_name=exe_name,
modelname=modelname,
model_ws=model_ws,
verbose=verbose,
iupbhsv=iupbhsv,
iupbfsv=iupbfsv,
parent=parent,
children=children,
children_data=children_data,
)