Source code for flopy.modflow.mfgage

"""
mfgage module.  Contains the ModflowGage class. Note that the user can access
the ModflowGage class as `flopy.modflow.ModflowGage`.

Additional information for this MODFLOW package can be found at the `Online
MODFLOW Guide
<https://water.usgs.gov/ogw/modflow/MODFLOW-2005-Guide/gage.html>`_.

"""

import os

import numpy as np
import pandas as pd

from ..pakbase import Package
from ..utils import read_fixed_var, write_fixed_var
from ..utils.recarray_utils import create_empty_recarray


[docs]class ModflowGage(Package): """ MODFLOW Gage Package Class. Parameters ---------- model : model object The model object (of type :class:`flopy.modflow.mf.Modflow`) to which this package will be added. numgage : int The total number of gages included in the gage file (default is 0). gage_data : list or numpy array or recarray or pandas dataframe data for dataset 2a and 2b in the gage package. If a list is provided then the list includes 2 to 3 entries (LAKE UNIT [OUTTYPE]) for each LAK Package entry and 4 entries (GAGESEG GAGERCH UNIT OUTTYPE) for each SFR Package entry. If a numpy array it passed each gage location must have 4 entries, where LAK Package gages can have any value for the second column. The numpy array can be created using the get_empty() method available in ModflowGage. Default is None files : list of strings Names of gage output files. A file name must be provided for each gage. If files are not provided and filenames=None then a gage name will be created using the model name and the gage number (for example, modflowtest.gage1.go). Default is None. extension : string Filename extension (default is 'gage') unitnumber : int File unit number (default is None). filenames : str or list of str Filenames to use for the package and the output files. If filenames=None the package name will be created using the model name and package extension and gage output names will be created using the model name and the gage number (for example, modflowtest.gage1.go). If a single string is passed the package will be set to the string and gage output names will be created using the model name and the gage number. To define the names for all gage files (input and output) the length of the list of strings should be numgage + 1. Default is None. Methods ------- See Also -------- Notes ----- Parameters are not supported in FloPy. Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow() >>> gages = [[-1, -26, 1], [-2, -27, 1]] >>> files = ['gage1.go', 'gage2.go'] >>> gage = flopy.modflow.ModflowGage(m, numgage=2, >>> gage_data=gages, files=files) """ def __init__( self, model, numgage=0, gage_data=None, files=None, extension="gage", unitnumber=None, filenames=None, **kwargs, ): # set default unit number of one is not specified if unitnumber is None: unitnumber = ModflowGage._defaultunit() # set filenames filenames = self._prepare_filenames(filenames, numgage + 1) # process gage output files dtype = self.get_default_dtype() if numgage > 0: # check the provided file entries if filenames[1] is None: if files is None: files = [] for idx in range(numgage): files.append(f"{model.name}.gage{idx + 1}.go") if isinstance(files, np.ndarray): files = files.flatten().tolist() elif isinstance(files, str): files = [files] elif isinstance(files, int) or isinstance(files, float): files = [f"{files}.go"] if len(files) < numgage: raise Exception( "a filename needs to be provided for {} gages - {} " "filenames were provided".format(numgage, len(files)) ) else: if len(filenames) < numgage + 1: raise Exception( "filenames must have a length of {} the length " "provided is {}".format(numgage + 1, len(filenames)) ) else: files = [] for n in range(numgage): files.append(filenames[n + 1]) # convert gage_data to a recarray, if necessary if isinstance(gage_data, np.ndarray): if not gage_data.dtype == dtype: gage_data = np.core.records.fromarrays( gage_data.transpose(), dtype=dtype ) elif isinstance(gage_data, pd.DataFrame): gage_data = gage_data.to_records(index=False) elif isinstance(gage_data, list): d = ModflowGage.get_empty(ncells=numgage) for n in range(len(gage_data)): t = gage_data[n] gageloc = int(t[0]) if gageloc < 0: gagerch = 0 iu = int(t[1]) outtype = 0 if iu < 0: outtype = int(t[2]) else: gagerch = int(t[1]) iu = int(t[2]) outtype = int(t[3]) d["gageloc"][n] = gageloc d["gagerch"][n] = gagerch d["unit"][n] = iu d["outtype"][n] = outtype gage_data = d else: raise Exception( "gage_data must be a numpy record array, numpy array " "or a list" ) # add gage output files to model for n in range(numgage): model.add_output_file( abs(gage_data["unit"][n]), fname=files[n], binflag=False, package=self._ftype(), ) # call base package constructor super().__init__( model, extension=extension, name=self._ftype(), unit_number=unitnumber, filenames=filenames[0], ) # no heading for this format self.url = "gage.html" self.numgage = numgage self.files = files self.dtype = self.get_default_dtype() self.gage_data = gage_data self.parent.add_package(self) return
[docs] @staticmethod def get_default_dtype(): dtype = np.dtype( [ ("gageloc", int), ("gagerch", int), ("unit", int), ("outtype", int), ] ) return dtype
[docs] @staticmethod def get_empty(ncells=0, aux_names=None, structured=True): # get an empty recarray that corresponds to dtype dtype = ModflowGage.get_default_dtype() return create_empty_recarray(ncells, dtype, default_value=-1.0e10)
def _ncells(self): """Maximum number of cells that have gages (developed for MT3DMS SSM package). Return zero because gage is not added to SSM package. Returns ------- ncells: int 0 """ return 0
[docs] def write_file(self): """ Write the package file. Returns ------- None """ f = open(self.fn_path, "w") # no heading for this format # dataset 1 f.write(write_fixed_var([self.numgage], free=True)) # dataset 2 for n in range(self.numgage): gageloc = self.gage_data["gageloc"][n] gagerch = self.gage_data["gagerch"][n] iu = self.gage_data["unit"][n] outtype = self.gage_data["outtype"][n] t = [gageloc] if gageloc < 0: t.append(iu) if iu < 0: t.append(outtype) else: t.append(gagerch) t.append(iu) t.append(outtype) f.write(write_fixed_var(t, free=True)) # close the gage file f.close()
[docs] @classmethod def load(cls, f, model, nper=None, 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. nper : int The number of stress periods. If nper is None, then nper will be obtained from the model object. (default is None). 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 ------- str : ModflowStr object ModflowStr object. Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow() >>> gage = flopy.modflow.ModflowGage.load('test.gage', m) """ if model.verbose: print("loading gage package file...") openfile = not hasattr(f, "read") if openfile: filename = f f = open(filename, "r", errors="replace") # no heading for this format # read dataset 1 if model.verbose: print(" reading gage dataset 1") line = f.readline().rstrip() t = read_fixed_var(line, free=True) numgage = int(t[0]) if numgage == 0: gage_data = None files = None else: # read dataset 2 if model.verbose: print(" reading gage dataset 2") gage_data = ModflowGage.get_empty(ncells=numgage) files = [] for n in range(numgage): line = f.readline().rstrip() t = read_fixed_var(line, free=True) gageloc = int(t[0]) if gageloc < 0: gagerch = 0 iu = int(t[1]) outtype = 0 if iu < 0: outtype = int(t[2]) else: gagerch = int(t[1]) iu = int(t[2]) outtype = int(t[3]) gage_data["gageloc"][n] = gageloc gage_data["gagerch"][n] = gagerch gage_data["unit"][n] = iu gage_data["outtype"][n] = outtype for key, value in ext_unit_dict.items(): if key == abs(iu): model.add_pop_key_list(abs(iu)) relpth = os.path.relpath( value.filename, model.model_ws ) files.append(relpth) break if openfile: f.close() # determine specified unit number unitnumber = None filenames = [] if ext_unit_dict is not None: for key, value in ext_unit_dict.items(): if value.filetype == ModflowGage._ftype(): unitnumber = key filenames.append(os.path.basename(value.filename)) for file in files: filenames.append(os.path.basename(file)) return cls( model, numgage=numgage, gage_data=gage_data, filenames=filenames, unitnumber=unitnumber, )
@staticmethod def _ftype(): return "GAGE" @staticmethod def _defaultunit(): return 120