Skip to content

Commit

Permalink
fix(internal): Flopy fixed to correctly reads in internal keyword whe…
Browse files Browse the repository at this point in the history
…n no multiplier supplied. Also, header line added to package files. (#962)

* fix(internal): Flopy fixed to correctly reads in internal keyword in the case where there is no multiplier supplied.

* feat(header): Flopy feature added that by default adds a header line to each package file indicating that it was generated by flopy.  Option called "write_headers" added to simulations that allows users to turn on and off headers.

* fix(package/simulation): reformatted with "black --line-length 79"
  • Loading branch information
spaulins-usgs authored Aug 13, 2020
1 parent 573da13 commit af28ed8
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 74 deletions.
3 changes: 2 additions & 1 deletion autotest/t504_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def test001a_tharmonic():

# load simulation
sim = MFSimulation.load(model_name, 'mf6', exe_name, pth,
verbosity_level=0, verify_data=True)
verbosity_level=0, verify_data=True,
write_headers=False)
sim.simulation_data.mfpath.set_sim_path(run_folder)

# write simulation to new location
Expand Down
2 changes: 1 addition & 1 deletion autotest/t505_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def np001():

# create simulation
sim = MFSimulation(sim_name=test_ex_name, version='mf6', exe_name=exe_name,
sim_ws=pth)
sim_ws=pth, write_headers=False)
tdis_rc = [(6.0, 2, 1.0), (6.0, 3, 1.0)]
tdis_package = ModflowTdis(sim, time_units='DAYS', nper=1,
perioddata=[(2.0, 1, 1.0)])
Expand Down
17 changes: 16 additions & 1 deletion examples/data/mf6/test036_twrihfb/twrihfb2015.rch
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,20 @@ END Options

BEGIN PERIOD 1
RECHARGE
CONSTANT 0.30000000E-07
INTERNAL
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08 3.00000000E-08
END PERIOD
24 changes: 1 addition & 23 deletions flopy/mf6/data/mfdatastorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1686,28 +1686,6 @@ def process_internal_line(self, arr_line):
multiplier = self.get_default_mult()
print_format = None
if isinstance(arr_line, list):
if len(arr_line) < 2:
message = (
'Data array "{}" contains an INTERNAL '
"that is not followed by a multiplier in line "
'"{}".'.format(
self.data_dimensions.structure.name, " ".join(arr_line)
)
)
type_, value_, traceback_ = sys.exc_info()
raise MFDataException(
self.data_dimensions.structure.get_model(),
self.data_dimensions.structure.get_package(),
self.data_dimensions.structure.path,
"processing internal data header",
self.data_dimensions.structure.name,
inspect.stack()[0][3],
type_,
value_,
traceback_,
message,
self._simulation_data.debug,
)
index = 1
while index < len(arr_line):
if isinstance(arr_line[index], str):
Expand Down Expand Up @@ -1851,7 +1829,7 @@ def process_open_close_line(self, arr_line, layer, store=True):
except Exception as ex:
message = (
"Data array {} contains an OPEN/CLOSE "
"with an invalid multiplier following the "
"with an invalid factor following the "
'"factor" keyword.'
".".format(data_dim.structure.name)
)
Expand Down
21 changes: 0 additions & 21 deletions flopy/mf6/data/mffileaccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,27 +787,6 @@ def _load_layer(
)
# if internal
elif arr_line[0].upper() == "INTERNAL":
if len(arr_line) < 2:
message = (
'Data array "{}" contains a INTERNAL that is not '
"followed by a multiplier"
".".format(self.structure.name)
)
type_, value_, traceback_ = sys.exc_info()
raise MFDataException(
self.structure.get_model(),
self.structure.get_package(),
self._path,
"loading data layer from file",
self.structure.name,
inspect.stack()[0][3],
type_,
value_,
traceback_,
message,
self._simulation_data.debug,
)

try:
multiplier, print_format = storage.process_internal_line(
arr_line
Expand Down
35 changes: 27 additions & 8 deletions flopy/mf6/mfpackage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
import errno
import inspect
import datetime
import numpy as np
from collections import OrderedDict

Expand All @@ -22,6 +23,7 @@
from ..pakbase import PackageInterface
from .data.mfdatautil import MFComment
from ..utils.check import mf6check
from ..version import __version__


class MFBlockHeader(object):
Expand Down Expand Up @@ -249,7 +251,8 @@ class MFBlock(object):
Attributes
----------
block_headers : MFBlockHeaderIO
block header text (BEGIN/END), header variables, comments in the header
block header text (BEGIN/END), header variables, comments in the
header
structure : MFBlockStructure
structure describing block
path : tuple
Expand Down Expand Up @@ -1007,7 +1010,8 @@ def _find_data_by_keyword(self, line, fd, initial_comment):
line, fd, self.block_headers[-1], initial_comment
)

# see if first item's name indicates a reference to another package
# see if first item's name indicates a reference to another
# package
package_info_list = self._get_package_info(dataset)
if package_info_list is not None:
for package_info in package_info_list:
Expand Down Expand Up @@ -2108,6 +2112,19 @@ def write(self, ext_file_action=ExtFileAction.copy_relative_paths):
# open file
fd = open(package_file_path, "w")

# write flopy header
if self.simulation_data.write_headers:
dt = datetime.datetime.now()
header = (
"# File generated by Flopy version {} on {} at {}."
"\n".format(
__version__,
dt.strftime("%m/%d/%Y"),
dt.strftime("%H:%M:%S"),
)
)
fd.write(header)

# write blocks
self._write_blocks(fd, ext_file_action)

Expand Down Expand Up @@ -2207,7 +2224,9 @@ def _write_blocks(self, fd, ext_file_action):
self.simulation_data.verbosity_level.value
>= VerbosityLevel.verbose.value
):
print(" writing block {}...".format(block.structure.name))
print(
" writing block {}.." ".".format(block.structure.name)
)
# write block
block.write(fd, ext_file_action=ext_file_action)
block_num += 1
Expand Down Expand Up @@ -2257,12 +2276,12 @@ def plot(self, **kwargs):
**kwargs : dict
filename_base : str
Base file name that will be used to automatically generate file
names for output image files. Plots will be exported as image
files if file_name_base is not None. (default is None)
Base file name that will be used to automatically generate
file names for output image files. Plots will be exported as
image files if file_name_base is not None. (default is None)
file_extension : str
Valid matplotlib.pyplot file extension for savefig(). Only used
if filename_base is not None. (default is 'png')
Valid matplotlib.pyplot file extension for savefig(). Only
used if filename_base is not None. (default is 'png')
mflay : int
MODFLOW zero-based layer number to return. If None, then all
all layers will be included. (default is None)
Expand Down
63 changes: 44 additions & 19 deletions flopy/mf6/modflow/mfsimulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ def find_in_path(self, key_path, key_leaf):
data_item_structures = item.structure.data_item_structures
for data_item_struct in data_item_structures:
if data_item_struct.name == key_leaf:
# found key_leaf as a data item name in the data in
# the dictionary
# found key_leaf as a data item name in the data
# in the dictionary
return item, data_item_index
if data_item_struct.type != DatumType.keyword:
data_item_index += 1
Expand Down Expand Up @@ -221,6 +221,9 @@ class MFSimulationData(object):
number of decimal points to write for a floating point number
float_characters : int
number of characters a floating point number takes up
write_headers: bool
when true flopy writes a header to each package file indicating that
it was created by flopy
sci_note_upper_thres : float
numbers greater than this threshold are written in scientific notation
sci_note_lower_thres : float
Expand All @@ -242,6 +245,7 @@ def __init__(self, path):
self.wrap_multidim_arrays = True
self.float_precision = 8
self.float_characters = 15
self.write_headers = True
self._sci_note_upper_thres = 100000
self._sci_note_lower_thres = 0.001
self.fast_write = True
Expand Down Expand Up @@ -345,6 +349,9 @@ 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.
write_headers: bool
when true flopy writes a header to each package file indicating that
it was created by flopy
Attributes
----------
Expand Down Expand Up @@ -377,8 +384,8 @@ class MFSimulation(PackageContainer):
file paths
get_model : (model_name : string)
: [MFModel]
returns the models in the simulation with a given model name, name file
name, or model type
returns the models in the simulation with a given model name, name
file name, or model type
add_model : (model : MFModel, sln_group : integer)
add model to the simulation
remove_model : (model_name : string)
Expand Down Expand Up @@ -412,11 +419,13 @@ def __init__(
continue_=None,
nocheck=None,
memory_print_option=None,
write_headers=True,
):
super(MFSimulation, self).__init__(MFSimulationData(sim_ws), sim_name)
self.simulation_data.verbosity_level = self._resolve_verbosity_level(
verbosity_level
)
self.simulation_data.write_headers = write_headers
# verify metadata
fpdata = mfstructure.MFStructure()
if not fpdata.valid:
Expand Down Expand Up @@ -543,8 +552,10 @@ def __str__(self):

def _get_data_str(self, formal):
file_mgt = self.simulation_data.mfpath
data_str = "sim_name = {}\nsim_path = {}\nexe_name = " "{}\n\n".format(
self.name, file_mgt.get_sim_path(), self.exe_name
data_str = (
"sim_name = {}\nsim_path = {}\nexe_name = "
"{}\n"
"\n".format(self.name, file_mgt.get_sim_path(), self.exe_name)
)

for package in self._packagelist:
Expand Down Expand Up @@ -604,6 +615,7 @@ def load(
verbosity_level=1,
load_only=None,
verify_data=False,
write_headers=True,
):
"""Load an existing model.
Expand Down Expand Up @@ -636,6 +648,9 @@ def load(
example list: ['ic', 'maw', 'npf', 'oc', 'ims', 'gwf6-gwf6']
verify_data : bool
verify data when it is loaded. this can slow down loading
write_headers: bool
when true flopy writes a header to each package file indicating
that it was created by flopy
Returns
-------
Expand All @@ -647,7 +662,14 @@ def load(
"""
# initialize
instance = cls(sim_name, version, exe_name, sim_ws, verbosity_level)
instance = cls(
sim_name,
version,
exe_name,
sim_ws,
verbosity_level,
write_headers=write_headers,
)
verbosity_level = instance.simulation_data.verbosity_level
instance.simulation_data.verify_data = verify_data

Expand Down Expand Up @@ -1099,7 +1121,8 @@ def register_ims_package(self, ims_file, model_list):
# add ims package to simulation
self._ims_files[ims_file.filename] = ims_file

# If ims file is being replaced, replace ims filename in solution group
# If ims file is being replaced, replace ims filename in
# solution group
if pkg_with_same_name is not None and self._is_in_solution_group(
pkg_with_same_name.filename, 1
):
Expand Down Expand Up @@ -1208,10 +1231,10 @@ def write_simulation(
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.
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)
Expand Down Expand Up @@ -1244,7 +1267,8 @@ def write_simulation(
>= VerbosityLevel.normal.value
):
print(
" writing ims package {}...".format(ims_file._get_pname())
" writing ims package {}.."
".".format(ims_file._get_pname())
)
ims_file.write(ext_file_action=ext_file_action)

Expand Down Expand Up @@ -2136,14 +2160,15 @@ def plot(self, model_list=None, SelPackList=None, **kwargs):
all packages will be plotted
kwargs:
filename_base : str
Base file name that will be used to automatically generate file
names for output image files. Plots will be exported as image
files if file_name_base is not None. (default is None)
Base file name that will be used to automatically
generate file names for output image files. Plots will be
exported as image files if file_name_base is not None.
(default is None)
file_extension : str
Valid matplotlib.pyplot file extension for savefig(). Only used
if filename_base is not None. (default is 'png')
Valid matplotlib.pyplot file extension for savefig().
Only used if filename_base is not None. (default is 'png')
mflay : int
MODFLOW zero-based layer number to return. If None, then all
MODFLOW zero-based layer number to return. If None, then
all layers will be included. (default is None)
kper : int
MODFLOW zero-based stress period number to return.
Expand Down

0 comments on commit af28ed8

Please sign in to comment.