diff --git a/autotest/test_obs.py b/autotest/test_obs.py index 80df8f0cfd..187e32a206 100644 --- a/autotest/test_obs.py +++ b/autotest/test_obs.py @@ -3,6 +3,7 @@ import numpy as np import pytest +import flopy from modflow_devtools.markers import requires_exe from flopy.modflow import ( @@ -19,6 +20,7 @@ from flopy.utils.observationfile import Mf6Obs + @requires_exe("mf2005") def test_hob_simple(function_tmpdir): """ @@ -444,3 +446,44 @@ def test_multilayerhob_pr_multiline(): hob = ModflowHob.load(StringIO(problem_hob), ml) assert len(hob.obs_data) == 2, "pr, mlay... load error" + + +def test_duplicate_observation_names(function_tmpdir): + sim_ws = function_tmpdir + sim = flopy.mf6.MFSimulation(sim_ws=sim_ws) + + tdis = flopy.mf6.ModflowTdis(sim) + ims = flopy.mf6.ModflowIms(sim) + + gwf = flopy.mf6.ModflowGwf(sim) + + nlay = 2 + nrow = 10 + ncol = 10 + top = 10 + botm = [0, -10] + + dis = flopy.mf6.ModflowGwfdis(gwf, nlay=nlay, nrow=nrow, ncol=ncol, top=top, + botm=botm) + ic = flopy.mf6.ModflowGwfic(gwf, strt=top) + npf = flopy.mf6.ModflowGwfnpf(gwf, k=1, k33=1) + sto = flopy.mf6.ModflowGwfsto(gwf) + obs = flopy.mf6.ModflowUtlobs( + gwf, + continuous={"repeat_obs.csv": [ + ("obsdup", "HEAD", (0, 4, 4)), + ("obsdup", "HEAD", (1, 4, 4)) + ] + } + ) + + spd = {0: [((1, 4, 4), -50.)]} + wel = flopy.mf6.ModflowGwfwel(gwf, stress_period_data=spd) + sim.write_simulation() + sim.run_simulation() + + gwf = sim.get_model() + obs = gwf.obs.output.obs() + data = obs.get_data() + if len(data.dtype.names) != 3: + raise AssertionError("CsvFile not incrementing duplicate headings") diff --git a/flopy/mf6/utils/output_util.py b/flopy/mf6/utils/output_util.py index e2d87fb91b..5577a23a87 100644 --- a/flopy/mf6/utils/output_util.py +++ b/flopy/mf6/utils/output_util.py @@ -201,6 +201,26 @@ def get_layerfile_data(self, f=data, text=rectype): setattr(self.__class__, rectype, get_layerfile_data) self._methods.append(f"{rectype}()") + def __repr__(self): + """ + String representation of the MF6Output object + + Returns + ------- + s : str + human readable class representation + """ + name = self._obj.name + if isinstance(name, list): + name = name[0] + l = [ + f"MF6Output Class for {name}", + f"Available output methods include:", + ] + l += [f".{m}" for m in self.methods()] + s = "\n".join(l) + return s + def methods(self): """ Method that returns a list of available method calls diff --git a/flopy/utils/observationfile.py b/flopy/utils/observationfile.py index 5f6f37fdfb..8ac1e082da 100644 --- a/flopy/utils/observationfile.py +++ b/flopy/utils/observationfile.py @@ -511,6 +511,7 @@ def __init__( # read header line line = self.file.readline() self._header = line.rstrip().split(delimiter) + self.__fix_duplicate_headings() self.floattype = "f8" self.dtype = _build_dtype(self._header, self.floattype) @@ -518,6 +519,25 @@ def __init__( self.file, self.dtype, delimiter, deletechars, replace_space ) + def __fix_duplicate_headings(self): + """ + Method to increment duplicate observation names if they exist + + """ + new_header = [] + while self._header: + colname = self._header.pop(0) + cnt = 1 + if colname in new_header: + cnt = 1 + basename = colname + while colname in new_header: + colname = f"{basename}_{cnt}" + cnt += 1 + new_header.append(colname) + + self._header = new_header + @property def obsnames(self): """