Source code for flopy.modflow.mfbas

"""
mfbas module.  Contains the ModflowBas class. Note that the user can access
the ModflowBas class as `flopy.modflow.ModflowBas`.

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

"""

import re

import numpy as np

from ..pakbase import Package
from ..utils import Util3d


[docs]class ModflowBas(Package): """ MODFLOW Basic Package Class. Parameters ---------- model : model object The model object (of type :class:`flopy.modflow.mf.Modflow`) to which this package will be added. ibound : array of ints, optional The ibound array (the default is 1). strt : array of floats, optional An array of starting heads (the default is 1.0). ifrefm : bool, optional Indication if data should be read using free format (the default is True). ixsec : bool, optional Indication of whether model is cross sectional or not (the default is False). ichflg : bool, optional Flag indicating that flows between constant head cells should be calculated (the default is False). stoper : float percent discrepancy that is compared to the budget percent discrepancy continue when the solver convergence criteria are not met. Execution will unless the budget percent discrepancy is greater than stoper (default is None). MODFLOW-2005 only hnoflo : float Head value assigned to inactive cells (default is -999.99). extension : str, optional File extension (default is 'bas'). unitnumber : int, optional FORTRAN unit number for this package (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 name will be set to the string. Default is None. Attributes ---------- heading : str Text string written to top of package input file. options : list of str Can be either or a combination of XSECTION, CHTOCH or FREE. ifrefm : bool Indicates whether or not packages will be written as free format. Methods ------- See Also -------- Notes ----- Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow() >>> bas = flopy.modflow.ModflowBas(m) """ @staticmethod def _ftype(): return "BAS6" @staticmethod def _defaultunit(): return 13 def __init__( self, model, ibound=1, strt=1.0, ifrefm=True, ixsec=False, ichflg=False, stoper=None, hnoflo=-999.99, extension="bas", unitnumber=None, filenames=None, ): if unitnumber is None: unitnumber = ModflowBas._defaultunit() # call base package constructor super().__init__( model, extension=extension, name=self._ftype(), unit_number=unitnumber, filenames=self._prepare_filenames(filenames), ) self.url = "bas6.html" nrow, ncol, nlay, nper = self.parent.nrow_ncol_nlay_nper self.ibound = Util3d( model, (nlay, nrow, ncol), np.int32, ibound, name="ibound", locat=self.unit_number[0], ) self.strt = Util3d( model, (nlay, nrow, ncol), np.float32, strt, name="strt", locat=self.unit_number[0], ) self._generate_heading() self.options = "" self.ixsec = ixsec self.ichflg = ichflg self.stoper = stoper # self.ifrefm = ifrefm # model.array_free_format = ifrefm model.free_format_input = ifrefm self.hnoflo = hnoflo self.parent.add_package(self) return @property def ifrefm(self): return self.parent.free_format_input def __setattr__(self, key, value): if key == "ifrefm": self.parent.free_format_input = value else: super().__setattr__(key, value)
[docs] def check(self, f=None, verbose=True, level=1, checktype=None): """ Check package data for common errors. Parameters ---------- f : str or file handle String defining file name or file handle for summary file of check method output. If a string is passed a file handle is created. If f is None, check method does not write results to a summary file. (default is None) verbose : bool Boolean flag used to determine if check method results are written to the screen level : int Check method analysis level. If level=0, summary checks are performed. If level=1, full checks are performed. Returns ------- None Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow.load('model.nam') >>> m.bas6.check() """ chk = self._get_check(f, verbose, level, checktype) neighbors = chk.get_neighbors(self.ibound.array) if isinstance(neighbors, np.ndarray): neighbors[np.isnan(neighbors)] = ( 0 # set neighbors at edges to 0 (inactive) ) chk.values( self.ibound.array, (self.ibound.array > 0) & np.all(neighbors < 1, axis=0), "isolated cells in ibound array", "Warning", ) chk.values( self.ibound.array, np.isnan(self.ibound.array), error_name="Not a number", error_type="Error", ) chk.summarize() return chk
[docs] def write_file(self, check=True): """ Write the package file. Parameters ---------- check : boolean Check package data for common errors. (default True) Returns ------- None """ # allows turning off package checks when writing files at model level if check: self.check( f=f"{self.name[0]}.chk", verbose=self.parent.verbose, level=1, ) # Open file for writing f_bas = open(self.fn_path, "w") # First line: heading f_bas.write(f"{self.heading}\n") # Second line: format specifier opts = [] if self.ixsec: opts.append("XSECTION") if self.ichflg: opts.append("CHTOCH") if self.ifrefm: opts.append("FREE") if self.stoper is not None: opts.append(f"STOPERROR {self.stoper}") self.options = " ".join(opts) f_bas.write(self.options + "\n") # IBOUND array f_bas.write(self.ibound.get_file_entry()) # Head in inactive cells str_hnoflo = str(self.hnoflo).rjust(10) if not self.ifrefm and len(str_hnoflo) > 10: # write fixed-width no more than 10 characters str_hnoflo = f"{self.hnoflo:10.4G}" assert len(str_hnoflo) <= 10, str_hnoflo f_bas.write(str_hnoflo + "\n") # Starting heads array f_bas.write(self.strt.get_file_entry()) # Close file f_bas.close()
[docs] @classmethod def load(cls, f, model, ext_unit_dict=None, check=True, **kwargs): """ 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`. check : boolean Check package data for common errors. (default True) kwargs : dictionary Keyword arguments that are passed to load. Possible keyword arguments are nlay, nrow, and ncol. If not provided, then the model must contain a discretization package with correct values for these parameters. Returns ------- bas : ModflowBas object ModflowBas object (of type :class:`flopy.modflow.ModflowBas`) Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow() >>> bas = flopy.modflow.ModflowBas.load('test.bas', m, nlay=1, nrow=10, >>> ncol=10) """ if model.verbose: print("loading bas6 package file...") # parse keywords if "nlay" in kwargs: nlay = kwargs.pop("nlay") else: nlay = None if "nrow" in kwargs: nrow = kwargs.pop("nrow") else: nrow = None if "ncol" in kwargs: ncol = kwargs.pop("ncol") else: ncol = None # open the file if not already open 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 -- options # only accept alphanumeric characters, as well as '+', '-' and '.' line = re.sub(r"[^A-Z0-9\.\-\+]", " ", line.upper()) opts = line.strip().split() ixsec = "XSECTION" in opts ichflg = "CHTOCH" in opts ifrefm = "FREE" in opts iprinttime = "PRINTTIME" in opts ishowp = "SHOWPROGRESS" in opts if "STOPERROR" in opts: i = opts.index("STOPERROR") stoper = np.float32(opts[i + 1]) else: stoper = None # get nlay,nrow,ncol if not passed if nlay is None and nrow is None and ncol is None: nrow, ncol, nlay, nper = model.get_nrow_ncol_nlay_nper() # dataset 2 -- ibound ibound = Util3d.load( f, model, (nlay, nrow, ncol), np.int32, "ibound", ext_unit_dict ) # dataset 3 -- hnoflo line = f.readline() hnoflo = np.float32(line.strip().split()[0]) # dataset 4 -- strt strt = Util3d.load( f, model, (nlay, nrow, ncol), np.float32, "strt", ext_unit_dict ) 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=ModflowBas._ftype() ) # create bas object and return bas = cls( model, ibound=ibound, strt=strt, ixsec=ixsec, ifrefm=ifrefm, ichflg=ichflg, stoper=stoper, hnoflo=hnoflo, unitnumber=unitnumber, filenames=filenames, ) if check: bas.check( f=f"{bas.name[0]}.chk", verbose=bas.parent.verbose, level=0, ) return bas