Skip to content

Commit

Permalink
bug(flopy_io): limit fixed point format string to fixed column widths (
Browse files Browse the repository at this point in the history
…#1172)

flopy_io.write_fixed_var could write a fixed point string (f) that
exceeded the specified fixed column width. Added test to revert to
general format (g) with precision equal to column width - 6 to preserve
as much precision as possible. This value allows for a string with a
sign (+/-) and +/-e307. Added test for issue 1164 to t015_test.py
autotest.

Closes #1164
  • Loading branch information
jdhughes-usgs committed Aug 6, 2021
1 parent 64094ae commit 5098c56
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 9 deletions.
56 changes: 52 additions & 4 deletions autotest/t015_test.py
Expand Up @@ -32,7 +32,54 @@
else:
path = os.path.join("..", "examples", "data", "mf2005_test")

str_items = {0: {"mfnam": "str.nam", "sfrfile": "str.str"}}
str_items = {
0: {
"mfnam": "str.nam",
"sfrfile": "str.str",
"lstfile": "str.lst",
}
}


def test_str_issue1164():
m = flopy.modflow.Modflow.load(
str_items[0]["mfnam"],
exe_name=mfexe,
model_ws=path,
verbose=False,
check=False,
)

ws = os.path.join(tpth, "issue-1164")
m.change_model_ws(ws)

# adjust stress period data
spd0 = m.str.stress_period_data[0]
spd0["flow"][0] = 2.1149856e6 # 450000000000000000.0000e-17
m.str.stress_period_data[0] = spd0

# write model datasets and run fixed
m.write_input()
success = m.run_model()
assert success, "could not run base model"

# get the budget
lst_pth = os.path.join(ws, str_items[0]["lstfile"])
base_wb = flopy.utils.MfListBudget(lst_pth).get_dataframes()[0]

# set the model to free format
m.set_ifrefm()

# write model datasets and run revised
m.write_input()
success = m.run_model()
assert success, "could not run revised model"

# get the revised budget
revised_wb = flopy.utils.MfListBudget(lst_pth).get_dataframes()[0]

# test if the budgets are the same
assert revised_wb.equals(base_wb), "water budgets do not match"


def test_str_free():
Expand All @@ -43,7 +90,7 @@ def test_str_free():
verbose=False,
check=False,
)
ws = tpth
ws = os.path.join(tpth, "fixed")
m.change_model_ws(ws)

# get pointer to str package
Expand Down Expand Up @@ -116,7 +163,7 @@ def test_str_free():
msg = "could not load the fixed format model with aux variables"
assert m2 is not None, msg

ws = os.path.join(tpth, "mf2005")
ws = os.path.join(tpth, "free")
m.change_model_ws(ws)
m.set_ifrefm()
m.write_input()
Expand Down Expand Up @@ -145,7 +192,7 @@ def test_str_free():
# compare the fixed and free format head files
if run:
if pymake is not None:
fn1 = os.path.join(tpth, "str.nam")
fn1 = os.path.join(tpth, "fixed", "str.nam")
fn2 = os.path.join(ws, "str.nam")
success = pymake.compare_heads(fn1, fn2, verbose=True)
msg = "fixed and free format input output head files are different"
Expand All @@ -162,5 +209,6 @@ def test_str_plot():


if __name__ == "__main__":
test_str_issue1164()
test_str_free()
test_str_plot()
17 changes: 12 additions & 5 deletions flopy/utils/flopy_io.py
Expand Up @@ -185,18 +185,25 @@ def write_fixed_var(v, length=10, ipos=None, free=False, comment=None):
if free:
write_fmt = "{} "
else:
width = ipos[n]
if isinstance(v[n], (float, np.float32, np.float64)):
width = ipos[n] - 6
vmin, vmax = 10 ** -width, 10 ** width
decimal = width - 6
vmin, vmax = 10 ** -decimal, 10 ** decimal
if abs(v[n]) < vmin or abs(v[n]) > vmax:
ctype = "g"
ctype = "g" # default precision is 6 if not specified
else:
ctype = ".{}f".format(width)
ctype = ".{}f".format(decimal)
# evaluate if the fixed format value will exceed width
if (
len("{{:>{}{}}}".format(width, ctype).format(v[n]))
> width
):
ctype = ".{}g".format(decimal) # preserve precision
elif isinstance(v[n], (int, np.int32, np.int64)):
ctype = "d"
else:
ctype = ""
write_fmt = "{{:>{}{}}}".format(ipos[n], ctype)
write_fmt = "{{:>{}{}}}".format(width, ctype)
out += write_fmt.format(v[n])
if comment is not None:
out += " # {}".format(comment)
Expand Down

0 comments on commit 5098c56

Please sign in to comment.