diff --git a/autotest/test_listbudget.py b/autotest/test_listbudget.py index aa6a586f6..47f438237 100644 --- a/autotest/test_listbudget.py +++ b/autotest/test_listbudget.py @@ -141,3 +141,22 @@ def test_mtlist(example_data_path): assert len(w) == 1, len(w) assert w[0].category == UserWarning, w[0] assert "error parsing SW mass budget" in str(w[0].message) + + +@pytest.mark.parametrize( + "value, expected", + [ + ("8.5159-100", 8.5159e-100), + ("-8.5159-100", -8.5159e-100), + ("1.0000+100", 1.0e100), + ("-1.2000+150", -1.2e150), + ("3.9204E-103", 3.9204e-103), + ("60.3962", 60.3962), + ], +) +def test_mf6listfile_parse_budget_line_missing_e(value, expected): + line = f" FLOW-JA-FACE = {value:>16} FLOW-JA-FACE = {value:>16}" + entry, flux, cumu = Mf6ListBudget._parse_budget_line(None, line) + assert entry == "FLOW-JA-FACE" + assert flux == expected + assert cumu == expected diff --git a/flopy/utils/mflistfile.py b/flopy/utils/mflistfile.py index 18ae848de..93581e784 100644 --- a/flopy/utils/mflistfile.py +++ b/flopy/utils/mflistfile.py @@ -16,6 +16,24 @@ from ..utils.flopy_io import get_ts_sp from ..utils.utils_def import totim_to_datetime +# Fortran E/ES edit descriptors without an exponent width drop the "E" +# when the exponent has three digits, e.g. 8.5159E-100 -> 8.5159-100 +_MISSING_E = re.compile(r"^([+-]?\d*\.?\d+)([+-]\d{3})$") + + +def _parse_float(s): + """Parse a float from a list file, tolerating a missing "E" and NaN.""" + s = s.strip() + try: + return float(s) + except ValueError: + m = _MISSING_E.match(s) + if m: + return float(f"{m.group(1)}E{m.group(2)}") + if "NAN" in s.upper(): + return np.nan + return None + class ListBudget: """ @@ -825,17 +843,8 @@ def _parse_budget_line(self, line): idx = line2.index("=") + 1 fx_str = line2[idx:].split()[0].strip() - flux, cumu = None, None - try: - cumu = float(cu_str) - except: - if "NAN" in cu_str.strip().upper(): - cumu = np.nan - try: - flux = float(fx_str) - except: - if "NAN" in fx_str.strip().upper(): - flux = np.nan + cumu = _parse_float(cu_str) + flux = _parse_float(fx_str) return entry, flux, cumu def _get_totim(self, ts, sp, seekpoint):