Source code for flopy.modpath.mp7

"""
mp7 module.  Contains the Modpath7List and Modpath7 classes.


"""

import numpy as np
from ..mbase import BaseModel
from ..modflow import Modflow
from ..mf6 import MFModel
from ..pakbase import Package
from .mp7bas import Modpath7Bas
from .mp7sim import Modpath7Sim
from .mp7particledata import CellDataType, NodeParticleData
from .mp7particlegroup import ParticleGroupNodeTemplate
import os


[docs]class Modpath7List(Package): """ List package class """ def __init__(self, model, extension="list", unitnumber=None): """ Package constructor. """ if unitnumber is None: unitnumber = model.next_unit() # Call ancestor's init to set self.parent, extension, name and # unit number Package.__init__(self, model, extension, "LIST", unitnumber) # self.parent.add_package(self) This package is not added to the base # model so that it is not included in get_name_file_entries() return
[docs] def write_file(self): # Not implemented for list class return
[docs]class Modpath7(BaseModel): """ Modpath 7 base class Parameters ---------- modelname : str Basename for MODPATH 7 input and output files (default is 'modpath7test'). simfile_ext : str Filename extension of the MODPATH 7 simulation file (default is 'mpsim'). namefile_ext : str Filename extension of the MODPATH 7 namefile (default is 'mpnam'). version : str String that defines the MODPATH version. Valid versions are 'modpath7' (default is 'modpath7'). exe_name : str The name of the executable to use (the default is 'mp7'). flowmodel : flopy.modflow.Modflow or flopy.mf6.MFModel object MODFLOW model headfilename : str Filename of the MODFLOW output head file. If headfilename is not provided then it will be set from the flowmodel (default is None). budgetfilename : str Filename of the MODFLOW output cell-by-cell budget file. If budgetfilename is not provided then it will be set from the flowmodel (default is None). model_ws : str model workspace. Directory name to create model data sets. (default is the current working directory). verbose : bool Print additional information to the screen (default is False). Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow.load('mf2005.nam') >>> mp = flopy.modpath.Modpath7('mf2005_mp', flowmodel=m) """ def __init__( self, modelname="modpath7test", simfile_ext="mpsim", namefile_ext="mpnam", version="modpath7", exe_name="mp7.exe", flowmodel=None, headfilename=None, budgetfilename=None, model_ws=None, verbose=False, ): """ Model constructor. """ BaseModel.__init__( self, modelname, simfile_ext, exe_name, model_ws=model_ws, verbose=verbose, ) self.version_types = {"modpath7": "MODPATH 7"} self.set_version(version) self.lst = Modpath7List(self) self.mpnamefile = "{}.{}".format(self.name, namefile_ext) self.mpbas_file = "{}.mpbas".format(modelname) if not isinstance(flowmodel, (Modflow, MFModel)): msg = ( "Modpath7: flow model is not an instance of " + "flopy.modflow.Modflow or flopy.mf6.MFModel. " + "Passed object of type {}".format(type(flowmodel)) ) raise TypeError(msg) # if a MFModel instance ensure flowmodel is a MODFLOW 6 GWF model if isinstance(flowmodel, MFModel): if ( flowmodel.model_type != "gwf" and flowmodel.model_type != "gwf6" ): msg = ( "Modpath7: flow model type must be gwf. " + "Passed model_type is {}.".format(flowmodel.model_type) ) raise TypeError(msg) # set flowmodel and flow_version attributes self.flowmodel = flowmodel self.flow_version = self.flowmodel.version if self.flow_version == "mf6": # get discretization package ibound = None dis = self.flowmodel.get_package("DIS") if dis is None: msg = ( "DIS, DISV, or DISU packages must be " + "included in the passed MODFLOW 6 model" ) raise Exception(msg) else: if dis.package_name.lower() == "dis": nlay, nrow, ncol = ( dis.nlay.array, dis.nrow.array, dis.ncol.array, ) shape = (nlay, nrow, ncol) elif dis.package_name.lower() == "disv": nlay, ncpl = dis.nlay.array, dis.ncpl.array shape = (nlay, ncpl) elif dis.package_name.lower() == "disu": nodes = dis.nodes.array shape = tuple( nodes, ) else: msg = ( "DIS, DISV, or DISU packages must be " + "included in the passed MODFLOW 6 model" ) raise TypeError(msg) # terminate (for now) if mf6 model does not use dis or disv if len(shape) < 2: msg = ( "DIS and DISV are currently the only supported " + "MODFLOW 6 discretization packages that can be " + "used with MODPATH 7" ) raise TypeError(msg) # set ib ib = dis.idomain.array # set all ib to active if ib is not defined if ib is None: ib = np.ones(shape, np.int32) # set dis and grbdis file name dis_file = None grbdis_file = dis.filename + ".grb" grbtag = "GRB{}".format(dis.package_name.upper()) tdis = self.flowmodel.simulation.get_package("TDIS") if tdis is None: msg = ( "TDIS package must be " + "included in the passed MODFLOW 6 model" ) raise Exception(msg) tdis_file = tdis.filename # get stress period data nper = tdis.nper.array perlen = [] nstp = [] v = tdis.perioddata.array for pl, ns, tsmult in v: perlen.append(pl) nstp.append(ns) perlen = np.array(perlen, dtype=np.float32) nstp = np.array(nstp, dtype=np.int32) # get oc file oc = self.flowmodel.get_package("OC") if oc is not None: # set head file name if headfilename is None: headfilename = oc.head_filerecord.array["headfile"][0] # set budget file name if budgetfilename is None: budgetfilename = oc.budget_filerecord.array["budgetfile"][ 0 ] else: shape = None # extract data from DIS or DISU files and set shape dis = self.flowmodel.get_package("DIS") if dis is None: dis = self.flowmodel.get_package("DISU") elif dis is not None and shape is None: nlay, nrow, ncol = dis.nlay, dis.nrow, dis.ncol shape = (nlay, nrow, ncol) if dis is None: msg = ( "DIS, or DISU packages must be " + "included in the passed MODFLOW model" ) raise Exception(msg) elif dis is not None and shape is None: nlay, nodes = dis.nlay, dis.nodes shape = (nodes,) # terminate (for now) if mf6 model does not use dis if len(shape) != 3: msg = ( "DIS currently the only supported MODFLOW " + "discretization package that can be used with " + "MODPATH 7" ) raise Exception(msg) # get stress period data nper = dis.nper perlen = dis.perlen.array nstp = dis.nstp.array # set dis_file dis_file = dis.file_name[0] # set grbdis_file grbdis_file = None grbtag = None # set tdis_file tdis_file = None # set head file name if headfilename is None: iu = self.flowmodel.oc.iuhead headfilename = self.flowmodel.get_output(unit=iu) # get discretization package p = self.flowmodel.get_package("LPF") if p is None: p = self.flowmodel.get_package("BCF6") if p is None: p = self.flowmodel.get_package("UPW") if p is None: msg = ( "LPF, BCF6, or UPW packages must be " + "included in the passed MODFLOW model" ) raise Exception(msg) # set budget file name if budgetfilename is None: iu = p.ipakcb budgetfilename = self.flowmodel.get_output(unit=iu) # set hnoflo and ibound from BAS6 package bas = self.flowmodel.get_package("BAS6") ib = bas.ibound.array # reset to constant values if possible ibound = [] for k in range(shape[0]): i = ib[k].flatten() if np.all(i == i[0]): kval = i[0] else: kval = ib[k] ibound.append(kval) # set dis_file and tdis_file self.shape = shape self.dis_file = dis_file self.grbdis_file = grbdis_file self.grbtag = grbtag self.tdis_file = tdis_file # set temporal data self.nper = nper self.time_end = perlen.sum() self.perlen = perlen self.nstp = nstp # set output file names self.headfilename = headfilename self.budgetfilename = budgetfilename # make sure the valid files are available if self.headfilename is None: msg = ( "the head file in the MODFLOW model or passed " + "to __init__ cannot be None" ) raise ValueError(msg) if self.budgetfilename is None: msg = ( "the budget file in the MODFLOW model or passed " + "to __init__ cannot be None" ) raise ValueError(msg) if self.dis_file is None and self.grbdis_file is None: msg = ( "the dis file in the MODFLOW model or passed " + "to __init__ cannot be None" ) raise ValueError(msg) # set ib and ibound self.ib = ib self.ibound = ibound # set file attributes self.array_free_format = True self.array_format = "modflow" self.external = False return def __repr__(self): return "MODPATH 7 model" @property def laytyp(self): if self.flowmodel.version == "mf6": icelltype = self.flowmodel.npf.icelltype.array laytyp = [ icelltype[k].max() for k in range(self.flowmodel.modelgrid.nlay) ] else: p = self.flowmodel.get_package("BCF6") if p is None: laytyp = self.flowmodel.laytyp else: laytyp = p.laycon.array return np.array(laytyp, dtype=np.int32) @property def hdry(self): if self.flowmodel.version == "mf6": return None else: return self.flowmodel.hdry @property def hnoflo(self): if self.flowmodel.version == "mf6": return None else: return self.flowmodel.hnoflo
[docs] def write_name_file(self): """ Write the name file Returns ------- None """ fpth = os.path.join(self.model_ws, self.mpnamefile) f = open(fpth, "w") f.write("{}\n".format(self.heading)) if self.mpbas_file is not None: f.write("{:10s} {}\n".format("MPBAS", self.mpbas_file)) if self.dis_file is not None: f.write("{:10s} {}\n".format("DIS", self.dis_file)) if self.grbdis_file is not None: f.write("{:10s} {}\n".format(self.grbtag, self.grbdis_file)) if self.tdis_file is not None: f.write("{:10s} {}\n".format("TDIS", self.tdis_file)) if self.headfilename is not None: f.write("{:10s} {}\n".format("HEAD", self.headfilename)) if self.budgetfilename is not None: f.write("{:10s} {}\n".format("BUDGET", self.budgetfilename)) f.close()
[docs] @classmethod def create_mp7( cls, modelname="modpath7test", trackdir="forward", flowmodel=None, exe_name="mp7", model_ws=".", verbose=False, columncelldivisions=2, rowcelldivisions=2, layercelldivisions=2, nodes=None, ): """ Create a default MODPATH 7 model using a passed flowmodel with 8 particles in user-specified node locations or every active model cell. Parameters ---------- modelname : str Basename for MODPATH 7 input and output files (default is 'modpath7test'). trackdir : str Keyword that defines the MODPATH particle tracking direction. Available trackdir's are 'backward' and 'forward'. (default is 'forward') flowmodel : flopy.modflow.Modflow or flopy.mf6.MFModel object MODFLOW model exe_name : str The name of the executable to use (the default is 'mp7'). model_ws : str model workspace. Directory name to create model data sets. (default is the current working directory). verbose : bool Print additional information to the screen (default is False). columncelldivisions : int Number of particles in a cell in the column (x-coordinate) direction (default is 2). rowcelldivisions : int Number of particles in a cell in the row (y-coordinate) direction (default is 2). layercelldivisions : int Number of particles in a cell in the layer (z-coordinate) direction (default is 2). nodes : int, list of ints, tuple of ints, or np.ndarray Nodes (zero-based) with particles. If (default is node 0). Returns ------- mp : Modpath7 object Examples -------- >>> import flopy >>> m = flopy.modflow.Modflow.load('mf2005.nam') >>> mp = flopy.modpath.Modpath7.create_mp7(flowmodel=m) """ # create MODPATH 7 model instance mp = Modpath7( modelname=modelname, flowmodel=flowmodel, exe_name=exe_name, model_ws=model_ws, verbose=verbose, ) # set default iface for recharge and et if mp.flow_version == "mf6": defaultiface = {"RCH": 6, "EVT": 6} else: defaultiface = {"RECHARGE": 6, "ET": 6} # create MODPATH 7 basic file and add to the MODPATH 7 # model instance (mp) Modpath7Bas(mp, defaultiface=defaultiface) # create particles if nodes is None: nodes = [] node = 0 for ib in mp.ib.flatten(): if ib > 0: nodes.append(node) node += 1 sd = CellDataType( columncelldivisions=columncelldivisions, rowcelldivisions=rowcelldivisions, layercelldivisions=layercelldivisions, ) p = NodeParticleData(subdivisiondata=sd, nodes=nodes) pg = ParticleGroupNodeTemplate(particledata=p) # create MODPATH 7 simulation file and add to the MODPATH 7 # model instance (mp) Modpath7Sim( mp, simulationtype="combined", trackingdirection=trackdir, weaksinkoption="pass_through", weaksourceoption="pass_through", referencetime=0.0, stoptimeoption="extend", particlegroups=pg, ) return mp