From 435359fa3ce97f1b69ea743098120aa1e1730246 Mon Sep 17 00:00:00 2001 From: spaulins-usgs Date: Mon, 9 Dec 2019 15:22:24 -0800 Subject: [PATCH] refact(docstrings): refactored docstrings in mfsimulation --- flopy/mf6/modflow/mfsimulation.py | 535 +++++++++++++++++++----------- 1 file changed, 337 insertions(+), 198 deletions(-) diff --git a/flopy/mf6/modflow/mfsimulation.py b/flopy/mf6/modflow/mfsimulation.py index 696f322556..54827f9e1f 100644 --- a/flopy/mf6/modflow/mfsimulation.py +++ b/flopy/mf6/modflow/mfsimulation.py @@ -1,15 +1,14 @@ -""" -mfsimulation module. contains the MFSimulation class +"""mfsimulation module. contains the MFSimulation class.""" - -""" -import errno, sys, inspect +import errno +import sys +import inspect import collections import os.path from ...mbase import run_model from ..mfbase import PackageContainer, MFFileMgmt, ExtFileAction, \ - PackageContainerType, MFDataException, FlopyException, \ - VerbosityLevel + PackageContainerType, MFDataException, FlopyException, \ + VerbosityLevel from ..mfpackage import MFPackage from ..data.mfstructure import DatumType from ..data import mfstructure @@ -20,9 +19,9 @@ class SimulationDict(collections.OrderedDict): - """ - Class containing custom dictionary for MODFLOW simulations. Behaves as an - OrderedDict with some additional features described below. + """Class containing custom dictionary for MODFLOW simulations. + + Behaves as an OrderedDict with some additional features described below. Parameters ---------- @@ -31,28 +30,47 @@ class SimulationDict(collections.OrderedDict): Methods ------- - output_keys : (print_keys: boolean) : list - returns a list of output data keys the dictionary supports for output + find_in_path : (key_path : string, key_leaf : string) : MFData, int + attempt to find key_leaf in a partial key path key_path + output_keys : (print_keys : boolean) : list + return a list of output data keys the dictionary supports for output data, print_keys allows those keys to be printed to output. input_keys : () - prints all input data keys + print all input data keys observation_keys : () - prints observation keys + print observation keys keys : () print all keys, input and output plot : (key : string, **kwargs) - plots data with key 'key' using **kwargs for plot options + plot data with key 'key' using **kwargs for plot options shapefile : (key : string, **kwargs) create shapefile from data with key 'key' and with additional fields in **kwargs rename_all_packages : (name : string) - renames all packages in the simulation and associated models + rename all packages in the simulation and associated models + """ + def __init__(self, path=None): + """Define the __init__ method. + + Parameters: + path (string): File-like path used as dictionary key + + """ collections.OrderedDict.__init__(self) self._path = path def __getitem__(self, key): + """Define the __getitem__ magic method. + + Parameters: + key (string): Part or all of a dictionary key + + Returns: + MFData or numpy.ndarray + + """ if key == '_path' or not hasattr(self, '_path'): raise AttributeError(key) @@ -71,9 +89,27 @@ def __getitem__(self, key): return AttributeError(key) def __setitem__(self, key, val): + """Define the __setitem__ magic method. + + Parameters: + key (string): Dictionary key + val (MFData): MFData to store in dictionary + + """ collections.OrderedDict.__setitem__(self, key, val) def find_in_path(self, key_path, key_leaf): + """Attempt to find key_leaf in a partial key path key_path. + + Parameters: + key_path (string): partial path to the data + key_leaf (string): name of the data + + Returns: + MFData: Data found at the path. + int: Data index + + """ key_path_size = len(key_path) for key, item in self.items(): if key[:key_path_size] == key_path: @@ -93,21 +129,48 @@ def find_in_path(self, key_path, key_leaf): return None, None def output_keys(self, print_keys=True): + """Return a list of output data keys. + + Parameters: + print_keys (bool): print keys to console + + Returns: + list: keys for requesting binary output + + """ # get keys to request binary output x = binaryfile_utils.MFOutputRequester.getkeys(self, self._path, print_keys=print_keys) return [key for key in x.dataDict] def input_keys(self): + """Return a list of input data keys. + + Returns: + list: input data keys + + """ # get keys to request input ie. package data for key in self: print(key) def observation_keys(self): + """Return a list of observation keys. + + Returns: + list: observation keys + + """ # get keys to request observation file output mfobservation.MFObservationRequester.getkeys(self, self._path) def keys(self): + """Return a list of all keys. + + Returns: + list: all keys + + """ # overrides the built in keys to print all keys, input and output self.input_keys() try: @@ -122,8 +185,7 @@ def keys(self): class MFSimulationData(object): - """ - Class containing MODFLOW simulation data and file formatting data. + """Class containing MODFLOW simulation data and file formatting data. Parameters ---------- @@ -159,8 +221,16 @@ class MFSimulationData(object): dictionary containing discretization information for each model mfdata : SimulationDict custom dictionary containing all model data for the simulation + """ + def __init__(self, path): + """Define the __init__ method. + + Parameters: + path (string): File-like path to simulation + + """ # --- formatting variables --- self.indent_string = ' ' self.constant_formatting = ['constant', ''] @@ -195,24 +265,44 @@ def __init__(self, path): self.referenced_files = collections.OrderedDict() def set_sci_note_upper_thres(self, value): + """Set threshold number. + + Sets threshold number where any number larger than threshold + is represented in scientific notation. + + Parameters: + value (float): threshold value + + """ self._sci_note_upper_thres = value self._update_str_format() def set_sci_note_lower_thres(self, value): + """Set threshold number. + + Sets threshold number where any number smaller than threshold + is represented in scientific notation. + + Parameters: + value (float): threshold value + + """ self._sci_note_lower_thres = value self._update_str_format() def _update_str_format(self): + """Update floating point formatting strings.""" self.reg_format_str = '{:.%dE}' % \ - self.float_precision + self.float_precision self.sci_format_str = '{:%d.%df' \ '}' % (self.float_characters, self.float_precision) class MFSimulation(PackageContainer): - """ - MODFLOW Simulation Class. Entry point into any MODFLOW simulation. + """Entry point into any MODFLOW simulation. + + MFSimulation is used to load, build, and/or save a MODFLOW6 simulation. Parameters ---------- @@ -248,27 +338,20 @@ class MFSimulation(PackageContainer): the total memory for each simulation component. ALL means print information for each variable stored in the memory manager. NONE is default if memory_print_option is not specified. + Attributes ---------- sim_name : string name of the simulation - models : OrderedDict + _models : OrderedDict all models in the simulation - exchanges : list + _exchange_files : list all exchange packages in the simulation - imsfiles : list + _ims_files : list all ims packages in the simulation - mfdata : OrderedDict - all variables defined in the simulation. the key for a variable is - defined as a tuple. for "simulation level" packages the tuple - starts with the package type, followed by the block name, followed - by the variable name ("TDIS", "DIMENSIONS", "nper"). for "model level" - packages the tuple starts with the model name, followed by the package - name, followed by the block name, followed by the variable name ( - "MyModelName", "DIS6", "OPTIONS", "length_units"). name_file : MFPackage simulation name file - tdis_file + _tdis_file simulation tdis file Methods @@ -302,21 +385,57 @@ class MFSimulation(PackageContainer): is_valid : () : boolean checks the validity of the solution and all of its models and packages - See Also - -------- - - Notes - ----- - Examples -------- - - >>> s = flopy6.mfsimulation.load('my simulation', 'simulation.nam') + >>> s = MFSimulation.load('my simulation', 'simulation.nam') """ + def __init__(self, sim_name='sim', version='mf6', exe_name='mf6.exe', sim_ws='.', verbosity_level=1, continue_=None, nocheck=None, memory_print_option=None): + """Initialization. + + __init__ is used to initialize a simulation object + + Parameters: + sim_name : string + name of the simulation. + version : string + MODFLOW version + exe_name : string + relative path to MODFLOW executable from the simulation + working folder + sim_ws : string + path to simulation working folder + verbosity_level : int + verbosity level of standard output + 0 : no standard output + 1 : standard error/warning messages with some + informational messages + 2 : verbose mode with full error/warning/informational + messages. this is ideal for debugging + continue_ : bool + sets the continue option in the simulation name file. the + continue option is a keyword flag to indicate that the + simulation should continue even if one or more solutions do + not converge. + nocheck : bool + sets the nocheck option in the simulation name file. the + nocheckoption is a keyword flag to indicate that the model + input check routines should not be called prior to each time + step. checks are performed by default. + memory_print_option : str + sets memory_print_option in the simulation name file. + memory_print_option is a flag that controls printing of + detailed memory manager usage to the end of the simulation + list file. NONE means do not print detailed information. + SUMMARY means print only the total memory for each + simulation component. ALL means print information for each + variable stored in the memory manager. NONE is default if + memory_print_option is not specified. + + """ super(MFSimulation, self).__init__(MFSimulationData(sim_ws), sim_name) self.simulation_data.verbosity_level = self._resolve_verbosity_level( verbosity_level) @@ -371,8 +490,9 @@ def __init__(self, sim_name='sim', version='mf6', exe_name='mf6.exe', self.valid = False def __getattr__(self, item): - """ - __getattr__ - used to allow for getting models and packages as if + """Override __getattr__ to allow retrieving models. + + __getattr__ is used to allow for getting models and packages as if they are attributes Parameters @@ -412,9 +532,23 @@ def __getattr__(self, item): raise AttributeError(item) def __repr__(self): + """Override __repr__ to print custom string. + + Returns: + repr string : str + string describing object + + """ return self._get_data_str(True) def __str__(self): + """Override __str__ to print custom string. + + Returns: + str string : str + string describing object + + """ return self._get_data_str(False) def _get_data_str(self, formal): @@ -454,8 +588,11 @@ def _get_data_str(self, formal): @property def model_names(self): - """ - Returns a list of model names associated with this simulation + """Return a list of model names associated with this simulation. + + Returns: + list: list of model names + """ return self._models.keys() @@ -463,8 +600,7 @@ def model_names(self): def load(cls, sim_name='modflowsim', version='mf6', exe_name='mf6.exe', sim_ws='.', strict=True, verbosity_level=1, load_only=None, verify_data=True): - """ - Load an existing model. + """Load an existing model. Parameters ---------- @@ -502,7 +638,8 @@ def load(cls, sim_name='modflowsim', version='mf6', exe_name='mf6.exe', Examples -------- - >>> s = flopy6.mfsimulation.load('my simulation') + >>> s = flopy.mf6.mfsimulation.load('my simulation') + """ # initialize instance = cls(sim_name, version, exe_name, sim_ws, verbosity_level) @@ -572,8 +709,8 @@ def load(cls, sim_name='modflowsim', version='mf6', exe_name='mf6.exe', try: exch_data = exchange_recarray.get_data() except MFDataException as mfde: - message = 'Error occurred while loading exchange names from the ' \ - 'simulation name file.' + message = 'Error occurred while loading exchange names from ' \ + 'the simulation name file.' raise MFDataException(mfdata_except=mfde, model=instance.name, package='nam', @@ -591,7 +728,7 @@ def load(cls, sim_name='modflowsim', version='mf6', exe_name='mf6.exe', exchange_type = ''.join([char for char in exgfile[0] if not char.isdigit()]).upper() # get exchange number for this type - if not exchange_type in instance._exg_file_num: + if exchange_type not in instance._exg_file_num: exchange_file_num = 0 instance._exg_file_num[exchange_type] = 1 else: @@ -668,8 +805,7 @@ def load(cls, sim_name='modflowsim', version='mf6', exe_name='mf6.exe', def load_package(self, ftype, fname, pname, strict, ref_path, dict_package_name=None, parent_package=None): - """ - loads a package from a file + """Load a package from a file. Parameters ---------- @@ -688,8 +824,6 @@ def load_package(self, ftype, fname, pname, strict, ref_path, parent_package : MFPackage parent package - Examples - -------- """ if ftype == 'gnc': if fname not in self._ghost_node_files: @@ -700,11 +834,9 @@ def load_package(self, ftype, fname, pname, strict, ref_path, package_abbr = 'GWF' # build package name and package gnc_name = '{}-GNC_{}'.format(package_abbr, self._gnc_file_num) - ghost_node_file = mfgwfgnc.ModflowGwfgnc(self, filename=fname, - pname=gnc_name, - parent_file= - parent_package, - loading_package=True) + ghost_node_file = mfgwfgnc.ModflowGwfgnc( + self, filename=fname, pname=gnc_name, + parent_file=parent_package, loading_package=True) ghost_node_file.load(strict) self._ghost_node_files[fname] = ghost_node_file self._gnc_file_num += 1 @@ -751,18 +883,14 @@ def load_package(self, ftype, fname, pname, strict, ref_path, return package def register_ims_package(self, ims_file, model_list): - """ - registers an ims package with the simulation + """Register an ims package with the simulation. Parameters - ---------- - ims_file : MFPackage - ims package to register - model_list : list of strings - list of models using the ims package to be registered + ims_file : MFPackage + ims package to register + model_list : list of strings + list of models using the ims package to be registered - Examples - -------- """ if isinstance(model_list, str): model_list = [model_list] @@ -837,7 +965,8 @@ def register_ims_package(self, ims_file, model_list): if self.name_file.mxiter.get_data(solution_group_num) is None: self.name_file.mxiter.add_transient_key(solution_group_num) - # associate any models in the model list to this simulation file + # associate any models in the model list to this + # simulation file version_string = mfstructure.MFStructure().get_version_string() ims_pkg = 'ims{}'.format(version_string) new_record = [ims_pkg, ims_file.filename] @@ -868,6 +997,12 @@ def _rename_package_group(group_dict, name): package.package_type) def rename_all_packages(self, name): + """Rename all packages with name as prefix. + + Parameters: + name (str): prefix of name + + """ if self._tdis_file is not None: self._tdis_file.filename = '{}.{}'.format( name, self._tdis_file.package_type) @@ -883,20 +1018,17 @@ def rename_all_packages(self, name): def write_simulation(self, ext_file_action=ExtFileAction.copy_relative_paths, silent=False): - """ - writes the simulation to files + """Write the simulation to files. Parameters - ---------- - ext_file_action : ExtFileAction - defines what to do with external files when the simulation path - has changed. defaults to copy_relative_paths which copies only - files with relative paths, leaving files defined by absolute - paths fixed. - silent : bool - writes out the simulation in silent mode (verbosity_level = 0) - Examples - -------- + ext_file_action : ExtFileAction + defines what to do with external files when the simulation path + has changed. defaults to copy_relative_paths which copies only + files with relative paths, leaving files defined by absolute + paths fixed. + silent : bool + writes out the simulation in silent mode (verbosity_level = 0) + """ saved_verb_lvl = self.simulation_data.verbosity_level if silent: @@ -942,8 +1074,8 @@ def write_simulation(self, VerbosityLevel.normal.value: print(' writing gnc package {}...'.format( self._ghost_node_files[gnc_file]._get_pname())) - self._ghost_node_files[gnc_file].write(ext_file_action= - ext_file_action) + self._ghost_node_files[gnc_file].write( + ext_file_action=ext_file_action) else: if self.simulation_data.verbosity_level.value >= \ VerbosityLevel.normal.value: @@ -967,8 +1099,8 @@ def write_simulation(self, VerbosityLevel.normal.value: print(' writing mvr package {}...'.format( self._mover_files[mvr_file]._get_pname())) - self._mover_files[mvr_file].write(ext_file_action= - ext_file_action) + self._mover_files[mvr_file].write( + ext_file_action=ext_file_action) else: if self.simulation_data.verbosity_level.value >= \ VerbosityLevel.normal.value: @@ -1012,13 +1144,45 @@ def write_simulation(self, self.simulation_data.verbosity_level = saved_verb_lvl def set_sim_path(self, path): + """Return a list of output data keys. + + Parameters: + print_keys (bool): print keys to console + + Returns: + list: keys for requesting binary output + + """ self.simulation_data.mfpath.set_sim_path(path) def run_simulation(self, silent=None, pause=False, report=False, normal_msg='normal termination', use_async=False, cargs=None): - """ - Run the simulation. + """Run the simulation. + + Parameters: + silent (bool): + run in silent mode + pause (bool): + pause at end of run + report (bool): + save stdout lines to a list (buff) + normal_msg (str or list): + Normal termination message used to determine if the run + terminated normally. More than one message can be provided + using a list. (default is 'normal termination') + use_async : (boolean) + asynchronously read model stdout and report with timestamps. + good for models that take long time to run. not good for + models that run really fast + cargs : (str or list of strings) + additional command line arguments to pass to the executable. + default is None + Returns: + (success, buff) + success : boolean + buff : list of lines of stdout + """ if silent is None: if self.simulation_data.verbosity_level.value >= \ @@ -1032,9 +1196,7 @@ def run_simulation(self, silent=None, pause=False, report=False, normal_msg=normal_msg, use_async=use_async, cargs=cargs) def delete_output_files(self): - """ - Delete simulation output files. - """ + """Delete simulation output files.""" output_req = binaryfile_utils.MFOutputRequester output_file_keys = output_req.getkeys(self.simulation_data.mfdata, self.simulation_data.mfpath, @@ -1044,6 +1206,12 @@ def delete_output_files(self): os.remove(path) def remove_package(self, package_name): + """Remove a package. + + Parameters: + package_name (str): name of package to be removed + + """ if isinstance(package_name, MFPackage): packages = [package_name] else: @@ -1062,30 +1230,32 @@ def remove_package(self, package_name): del self._ghost_node_files[package.filename] if package.filename in self._mover_files: del self._mover_files[package.filename] - if package.filename in self._other_files : + if package.filename in self._other_files: del self._other_files[package.filename] self._remove_package(package) @property def model_dict(self): + """Return a dictionary of models. + + Returns: + model dict : dict + dictionary of models + + """ return self._models.copy() def get_model(self, model_name=None): - """ - Load an existing model. + """Load an existing model. - Parameters - ---------- - model_name : string - name of model to get + Parameters: + model_name : string + name of model to get - Returns - ------- - model : MFModel + Returns: + model : MFModel - Examples - -------- """ if len(self._models) == 0: return None @@ -1098,20 +1268,15 @@ def get_model(self, model_name=None): return None def get_exchange_file(self, filename): - """ - get a specified exchange file + """Get a specified exchange file. - Parameters - ---------- - filename : string - name of exchange file to get + Parameters: + filename : string + name of exchange file to get - Returns - ------- - exchange package : MFPackage + Returns: + exchange package : MFPackage - Examples - -------- """ if filename in self._exchange_files: return self._exchange_files[filename] @@ -1121,20 +1286,15 @@ def get_exchange_file(self, filename): raise FlopyException(excpt_str) def get_mvr_file(self, filename): - """ - get a specified mover file + """Get a specified mover file. - Parameters - ---------- - filename : string - name of mover file to get + Parameters: + filename : string + name of mover file to get - Returns - ------- - mover package : MFPackage + Returns: + mover package : MFPackage - Examples - -------- """ if filename in self._mover_files: return self._mover_files[filename] @@ -1144,20 +1304,15 @@ def get_mvr_file(self, filename): raise FlopyException(excpt_str) def get_gnc_file(self, filename): - """ - get a specified gnc file + """Get a specified gnc file. - Parameters - ---------- - filename : string - name of gnc file to get + Parameters: + filename : string + name of gnc file to get - Returns - ------- - gnc package : MFPackage + Returns: + gnc package : MFPackage - Examples - -------- """ if filename in self._ghost_node_files: return self._ghost_node_files[filename] @@ -1167,16 +1322,12 @@ def get_gnc_file(self, filename): raise FlopyException(excpt_str) def register_exchange_file(self, package): - """ - register an exchange package file with the simulation + """Register an exchange package file with the simulation. - Parameters - ---------- - package : MFPackage - exchange package object to register + Parameters: + package : MFPackage + exchange package object to register - Examples - -------- """ if package.filename not in self._exchange_files: exgtype = package.exgtype @@ -1246,26 +1397,21 @@ def register_exchange_file(self, package): def register_package(self, package, add_to_package_list=True, set_package_name=True, set_package_filename=True): - """ - register a package file with the simulation + """Register a package file with the simulation. - Parameters - ---------- - package : MFPackage - package to register - add_to_package_list : bool - add package to lookup list - set_package_name : bool - produce a package name for this package - set_package_filename : bool - produce a filename for this package + Parameters: + package : MFPackage + package to register + add_to_package_list : bool + add package to lookup list + set_package_name : bool + produce a package name for this package + set_package_filename : bool + produce a filename for this package - Returns - ------- - (path : tuple, package structure : MFPackageStructure) + Returns: + (path : tuple, package structure : MFPackageStructure) - Examples - -------- """ package.container_type = [PackageContainerType.simulation] path = self._get_package_path(package) @@ -1386,24 +1532,18 @@ def register_package(self, package, add_to_package_list=True, raise FlopyException(excpt_str) def register_model(self, model, model_type, model_name, model_namefile): - """ - add a model to the simulation. + """Add a model to the simulation. - Parameters - ---------- - model : MFModel - model object to add to simulation - sln_group : string - solution group of model + Parameters: + model : MFModel + model object to add to simulation + sln_group : string + solution group of model - Returns - ------- - model_structure_object : MFModelStructure + Returns: + model_structure_object : MFModelStructure - Examples - -------- """ - # get model structure from model type if model_type not in self.structure.model_struct_objs: message = 'Invalid model type: "{}".'.format(model_type) @@ -1432,23 +1572,28 @@ def register_model(self, model, model_type, model_name, model_namefile): return self.structure.model_struct_objs[model_type] def get_ims_package(self, key): + """Add a model to the simulation. + + Parameters: + key : str + ims package key + + Returns: + ims_package : ModflowIms + + """ if key in self._ims_files: return self._ims_files[key] return None def remove_model(self, model_name): - """ - remove a model from the simulation. + """Remove a model from the simulation. - Parameters - ---------- - model_name : string - model name to remove from simulation + Parameters: + model_name : string + model name to remove from simulation - Examples - -------- """ - # Remove model del self._models[model_name] @@ -1456,18 +1601,13 @@ def remove_model(self, model_name): # Update simulation name file def is_valid(self): - """ - check all packages and models in the simulation to verify validity + """Check all packages and models in the simulation to verify validity. - Returns - ---------- - valid : boolean - simulation validity + Returns: + valid : boolean + simulation validity - Examples - -------- """ - # name file valid if not self.name_file.is_valid(): return False @@ -1588,18 +1728,17 @@ def _is_in_solution_group(self, item, index): return True return False - def plot(self, model_list=None, SelPackList=None, **kwargs): - """ + """Plot simulation or models. + Method to plot a whole simulation or a series of models - that are part of a simualtion + that are part of a simulation. Parameters: model_list: (list) list of model names to plot, if none all models will be plotted SelPackList: (list) list of package names to plot, if none all packages will be plotted - kwargs: filename_base : str Base file name that will be used to automatically generate file @@ -1617,9 +1756,9 @@ def plot(self, model_list=None, SelPackList=None, **kwargs): key : str MfList dictionary key. (default is None) - Returns: axes: (list) matplotlib.pyplot.axes objects + """ from flopy.plot.plotutil import PlotUtilities