import os
from typing import Union
from ..discretization.modeltime import ModelTime
from ..discretization.structuredgrid import StructuredGrid
from ..mbase import BaseModel
from ..modflow import Modflow
from ..mt3d import Mt3dms
from ..pakbase import Package
from .swtvdf import SeawatVdf
from .swtvsc import SeawatVsc
[docs]class SeawatList(Package):
"""
List Package class
"""
def __init__(self, model, extension="list", listunit=7):
super().__init__(model, extension, "LIST", listunit)
return
def __repr__(self):
return "List package class"
[docs] def write_file(self):
# Not implemented for list class
return
[docs]class Seawat(BaseModel):
"""
SEAWAT Model Class.
Parameters
----------
modelname : str, default "swttest"
Name of model. This string will be used to name the SEAWAT input
that are created with write_model.
namefile_ext : str, default "nam"
Extension for the namefile.
modflowmodel : Modflow, default None
Instance of a Modflow object.
mt3dmodel : Mt3dms, default None
Instance of a Mt3dms object.
version : str, default "seawat"
Version of SEAWAT to use. Valid versions are "seawat" (default).
exe_name : str, default "swtv4"
The name of the executable to use.
structured : bool, default True
Specify if model grid is structured (default) or unstructured.
listunit : int, default 2
Unit number for the list file.
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.
load : bool, default True
Load model.
silent : int, default 0
Silent option.
Attributes
----------
Methods
-------
See Also
--------
Notes
-----
Examples
--------
>>> import flopy
>>> m = flopy.seawat.swt.Seawat()
"""
def __init__(
self,
modelname="swttest",
namefile_ext="nam",
modflowmodel=None,
mt3dmodel=None,
version="seawat",
exe_name="swtv4",
structured=True,
listunit=2,
model_ws=".",
external_path=None,
verbose=False,
load=True,
silent=0,
):
super().__init__(
modelname,
namefile_ext,
exe_name,
model_ws,
structured=structured,
verbose=verbose,
)
# Set attributes
self.version_types = {"seawat": "SEAWAT"}
self.set_version(version)
self.lst = SeawatList(self, listunit=listunit)
self.glo = None
self._mf = None
self._mt = None
# If a MODFLOW model was passed in, then add its packages
self.mf = self
if modflowmodel is not None:
for p in modflowmodel.packagelist:
self.packagelist.append(p)
self._modelgrid = modflowmodel.modelgrid
else:
modflowmodel = Modflow()
# If a MT3D model was passed in, then add its packages
if mt3dmodel is not None:
for p in mt3dmodel.packagelist:
self.packagelist.append(p)
else:
mt3dmodel = Mt3dms()
# external option stuff
self.array_free_format = False
self.array_format = "mt3d"
self.external_fnames = []
self.external_units = []
self.external_binflag = []
self.external = False
self.load = load
# the starting external data unit number
self._next_ext_unit = 3000
if external_path is not None:
assert (
model_ws == "."
), "ERROR: external cannot be used with model_ws"
# external_path = os.path.join(model_ws, external_path)
if os.path.exists(external_path):
print(f"Note: external_path {external_path} already exists")
# assert os.path.exists(external_path),'external_path does not exist'
else:
os.mkdir(external_path)
self.external = True
self.external_path = external_path
self.verbose = verbose
self.silent = silent
# Create a dictionary to map package with package object.
# This is used for loading models.
self.mfnam_packages = {}
for k, v in modflowmodel.mfnam_packages.items():
self.mfnam_packages[k] = v
for k, v in mt3dmodel.mfnam_packages.items():
self.mfnam_packages[k] = v
self.mfnam_packages["vdf"] = SeawatVdf
self.mfnam_packages["vsc"] = SeawatVsc
return
@property
def modeltime(self):
# build model time
data_frame = {
"perlen": self.dis.perlen.array,
"nstp": self.dis.nstp.array,
"tsmult": self.dis.tsmult.array,
}
self._model_time = ModelTime(
data_frame,
self.dis.itmuni_dict[self.dis.itmuni],
self.dis.start_datetime,
self.dis.steady.array,
)
return self._model_time
@property
def modelgrid(self):
if not self._mg_resync:
return self._modelgrid
if self.has_package("bas6"):
ibound = self.bas6.ibound.array
else:
ibound = None
# build grid
# self.dis should exist if modflow model passed
self._modelgrid = StructuredGrid(
self.dis.delc.array,
self.dis.delr.array,
self.dis.top.array,
self.dis.botm.array,
idomain=ibound,
lenuni=self.dis.lenuni,
crs=self._modelgrid.crs,
xoff=self._modelgrid.xoffset,
yoff=self._modelgrid.yoffset,
angrot=self._modelgrid.angrot,
nlay=self.dis.nlay,
)
# resolve offsets
xoff = self._modelgrid.xoffset
if xoff is None:
if self._xul is not None:
xoff = self._modelgrid._xul_to_xll(self._xul)
else:
xoff = 0.0
yoff = self._modelgrid.yoffset
if yoff is None:
if self._yul is not None:
yoff = self._modelgrid._yul_to_yll(self._yul)
else:
yoff = 0.0
self._modelgrid.set_coord_info(
xoff,
yoff,
self._modelgrid.angrot,
self._modelgrid.crs,
)
self._mg_resync = not self._modelgrid.is_complete
return self._modelgrid
@property
def nlay(self):
if self.dis:
return self.dis.nlay
else:
return 0
@property
def nrow(self):
if self.dis:
return self.dis.nrow
else:
return 0
@property
def ncol(self):
if self.dis:
return self.dis.ncol
else:
return 0
@property
def nper(self):
if self.dis:
return self.dis.nper
else:
return 0
@property
def nrow_ncol_nlay_nper(self):
dis = self.get_package("DIS")
if dis:
return dis.nrow, dis.ncol, dis.nlay, dis.nper
else:
return 0, 0, 0, 0
[docs] def get_nrow_ncol_nlay_nper(self):
return self.nrow_ncol_nlay_nper
[docs] def get_ifrefm(self):
bas = self.get_package("BAS6")
if bas:
return bas.ifrefm
else:
return False
@property
def ncomp(self):
if self.btn:
return self.btn.ncomp
else:
return 1
@property
def mcomp(self):
if self.btn:
return self.btn.mcomp
else:
return 1
def _set_name(self, value):
# Overrides BaseModel's setter for name property
super()._set_name(value)
# for i in range(len(self.lst.extension)):
# self.lst.file_name[i] = self.name + '.' + self.lst.extension[i]
# return
[docs] def change_model_ws(self, new_pth=None, reset_external=False):
# if hasattr(self,"_mf"):
if self._mf is not None:
self._mf.change_model_ws(
new_pth=new_pth, reset_external=reset_external
)
# if hasattr(self,"_mt"):
if self._mt is not None:
self._mt.change_model_ws(
new_pth=new_pth, reset_external=reset_external
)
super().change_model_ws(new_pth=new_pth, reset_external=reset_external)
[docs] def write_name_file(self):
"""
Write the name file
Returns
-------
None
"""
# open and write header
fn_path = os.path.join(self.model_ws, self.namefile)
f_nam = open(fn_path, "w")
f_nam.write(f"{self.heading}\n")
# Write global file entry
if self.glo is not None:
if self.glo.unit_number[0] > 0:
f_nam.write(
"{:14s} {:5d} {}\n".format(
self.glo.name[0],
self.glo.unit_number[0],
self.glo.file_name[0],
)
)
# Write list file entry
f_nam.write(
"{:14s} {:5d} {}\n".format(
self.lst.name[0],
self.lst.unit_number[0],
self.lst.file_name[0],
)
)
# Write SEAWAT entries and close
f_nam.write(str(self.get_name_file_entries()))
if self._mf is not None:
# write the external files
for b, u, f in zip(
self._mf.external_binflag,
self._mf.external_units,
self._mf.external_fnames,
):
tag = "DATA"
if b:
tag = "DATA(BINARY)"
f_nam.write(f"{tag:14s} {u:5d} {f}\n")
# write the output files
for u, f, b in zip(
self._mf.output_units,
self._mf.output_fnames,
self._mf.output_binflag,
):
if u == 0:
continue
if b:
f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n")
else:
f_nam.write(f"DATA {u:5d} {f}\n")
if self._mt is not None:
# write the external files
for b, u, f in zip(
self._mt.external_binflag,
self._mt.external_units,
self._mt.external_fnames,
):
tag = "DATA"
if b:
tag = "DATA(BINARY)"
f_nam.write(f"{tag:14s} {u:5d} {f}\n")
# write the output files
for u, f, b in zip(
self._mt.output_units,
self._mt.output_fnames,
self._mt.output_binflag,
):
if u == 0:
continue
if b:
f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n")
else:
f_nam.write(f"DATA {u:5d} {f}\n")
# write the external files
for b, u, f in zip(
self.external_binflag, self.external_units, self.external_fnames
):
tag = "DATA"
if b:
tag = "DATA(BINARY)"
f_nam.write(f"{tag:14s} {u:5d} {f}\n")
# write the output files
for u, f, b in zip(
self.output_units, self.output_fnames, self.output_binflag
):
if u == 0:
continue
if b:
f_nam.write(f"DATA(BINARY) {u:5d} {f} REPLACE\n")
else:
f_nam.write(f"DATA {u:5d} {f}\n")
f_nam.close()
return
[docs] @classmethod
def load(
cls,
f: str,
version="seawat",
exe_name: Union[str, os.PathLike] = "swtv4",
verbose=False,
model_ws: Union[str, os.PathLike] = os.curdir,
load_only=None,
):
"""
Load an existing model.
Parameters
----------
f : str
Name of SEAWAT name file to load.
version : str, default "seawat"
Version of SEAWAT to use. Valid versions are "seawat" (default).
exe_name : str, default "swtv4"
The name of the executable to use.
verbose : bool, default False
Print additional information to the screen.
model_ws : str or PathLike, default "."
Model workspace. Directory to create model data sets.
Default is the present working directory.
load_only : list of str, optional
Packages to load (e.g. ["lpf", "adv"]). Default None
means that all packages will be loaded.
Returns
-------
flopy.seawat.swt.Seawat
Examples
--------
>>> import flopy
>>> m = flopy.seawat.swt.Seawat.load(f)
"""
# 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
# create instance of a seawat model and load modflow and mt3dms models
ms = cls(
modelname=modelname,
namefile_ext="nam",
modflowmodel=None,
mt3dmodel=None,
version=version,
exe_name=exe_name,
model_ws=model_ws,
verbose=verbose,
)
mf = Modflow.load(
f,
version="mf2k",
exe_name=None,
verbose=verbose,
model_ws=model_ws,
load_only=load_only,
forgive=False,
check=False,
)
mt = Mt3dms.load(
f,
version="mt3dms",
exe_name=None,
verbose=verbose,
model_ws=model_ws,
forgive=False,
)
# set listing and global files using mf objects
ms.lst = mf.lst
ms.glo = mf.glo
for p in mf.packagelist:
p.parent = ms
ms.add_package(p)
ms._mt = None
if mt is not None:
for p in mt.packagelist:
p.parent = ms
ms.add_package(p)
mt.external_units = []
mt.external_binflag = []
mt.external_fnames = []
ms._mt = mt
ms._mf = mf
# return model object
return ms